import os
import stat
+# Needed for correct output of utf-8 symbols.
+sys.stdout=file("/dev/stdout", "wb")
+
def check_number(number):
if number == "":
return False
print "Usage:\nussdquery.py <ussd number> [options]\nussdquery.py interactive [options]\n"+\
"Options:\n-l language. Allowed languages: German, English, Italian, French, Spanish, Dutch, Swedish, Danish, Portuguese, Finnish, Norwegian, Greek, Turkish, Reserved1, Reserved2, Unspecified\n"+\
"-r retry count. 0 default. Use -1 for infinite.\n-f If specified, errors, which occur on last query are threated as fatal\n"+\
-"-t timeout in seconds. Default 30. Timeout is considered to be critical error because you can't be shure answer for what request was returned.\n"+\
+"-t timeout in seconds. Default 30. Timeout is considered to be critical error because you can't be sure answer for what request was returned.\n"+\
"-d delimeter. Default is '\\n> '"+\
-"For USSD menu navigation divide USSD number via spacebars for every nex menu selection. Type exit in interactive mode to exit."
+"For USSD menu navigation divide USSD number via spacebars for every next menu selection. Type exit in interactive mode to exit."
sys.exit()
+lockf = None
+
+def gain_lock ():
+ global lockf
+ lockf = open("/tmp/ussdquery.lock", 'a')
+ fcntl.flock(lockf,fcntl.LOCK_EX)
+ try:
+ os.chmod("/tmp/ussdquery.lock", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH)
+ except:
+ None
+
+def release_lock ():
+ global lockf
+ fcntl.flock(lockf,fcntl.LOCK_UN)
+ lockf.close()
+
+def init_modem(modem):
+ # We have only one modem, simultaneous acces wouldn't bring anything good
+ gain_lock()
+ response = ""
+ init_retry = 5
+ while response != "OK" and init_retry > 0 :
+ if modem == None :
+ # OK response should be recieved shortly
+ modem = pexpect.spawn('pnatd', [], 2)
+ try :
+ modem.send('at\r');
+ # Read our "at" command
+ modem.readline();
+ # Read OK response
+ response = modem.readline().strip()
+ except pexpect.TIMEOUT:
+ modem.kill(9)
+ modem = None
+ response = ""
+ if response != "OK" :
+ time.sleep(0.5)
+ init_retry -= 1
+ else:
+ try:
+ # Switch output encoding to GSM default encoding
+ modem.send('at+cscs="GSM"\r');
+ # Read our command
+ modem.readline();
+ # Read OK response
+ response = modem.readline().strip()
+ except pexpect.TIMEOUT:
+ modem.kill(9)
+ modem = None
+ response = ""
+
+ if response != "OK" :
+ time.sleep(0.5)
+ init_retry -= 1
+
+ if response != "OK" :
+ print >> sys.stderr, "Couldn't init modem."
+ if modem != None:
+ modem.kill(9)
+ release_lock()
+ sys.exit (-1)
+
+ modem.timeout = timeout
+ return modem
+
+def close_modem (modem):
+ modem.sendeof()
+ modem.kill(9)
+ release_lock()
+
retry = 0
allow_last_error = True
delimiter = "\n> "
retry = int(sys.argv[arg])
if retry < -1:
print >> sys.stderr, "Number of allowed errors must be >= -1. -1 assumed."
- retry = -1
+ retry = -1
except:
print >> sys.stderr, "Retry must be an integer."
sys.exit(-5)
else:
retry_forever = False
-# We have only one modem, simultaneous acces wouldn't bring anything good
-lockf = open("/tmp/ussdquery.lock", 'a')
-fcntl.flock(lockf,fcntl.LOCK_EX)
-try:
- os.chmod("/tmp/ussdquery.lock", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH)
-except:
- None
-child = None
-response = ""
-init_retry = 5
-while response != "OK" and init_retry > 0 :
- if child == None :
- # OK response should be recieved shortly
- child = pexpect.spawn('pnatd', [], 2)
- try :
- child.send('at\r');
- # Read our "at" command
- child.readline();
- # Read OK response
- response = child.readline().strip()
- except pexpect.TIMEOUT:
- child.kill(9)
- child = None
- response = ""
- if response != "OK" :
- time.sleep(0.5)
- init_retry -= 1
-
-if response != "OK" :
- print >> sys.stderr, "Couldn't init modem."
- if child != None:
- child.kill(9)
- fcntl.flock(lockf,fcntl.LOCK_UN)
- lockf.close()
- sys.exit (-1)
-
-child.timeout = timeout
+modem = None
+
# Now we are ready to send commands
stage = 0
if number == "interactive":
sys.stdout.write(delimiter)
while number == "interactive" or stage < len(number):
+ if modem == None:
+ modem = init_modem(modem)
+
if number == "interactive":
cnumber = sys.stdin.readline().strip()
if cnumber == "exit":
- child.kill(9)
- fcntl.flock(lockf,fcntl.LOCK_UN)
- lockf.close()
- sys.exit (-2)
+ close_modem (modem)
+ sys.exit (0)
if not check_number (cnumber):
sys.stdout.write ("Sintax error in USSD number"+delimiter)
continue
break
try :
- child.send('at+cusd=1,"'+cnumber+'",'+str(language)+'\r')
+ modem.send('at+cusd=1,"'+cnumber+'",'+str(language)+'\r')
# Read our query echoed back
- child.readline()
+ modem.readline()
#Read and parse reply
- replystring = child.readline().decode('string_escape')
+ replystring = modem.readline().decode('string_escape')
# This will read out unneeded info from modem
- child.readline()
- child.readline()
+ modem.readline()
+ modem.readline()
except pexpect.TIMEOUT:
print >> sys.stderr, "Timeout. Modem didn't reply."
- child.kill(9)
- fcntl.flock(lockf,fcntl.LOCK_UN)
- lockf.close()
+ close_modem (modem)
sys.exit (-2)
if replystring.strip() == "ERROR" :
continue
try:
- reresult = re.match("(?s)^\\+CUSD: \\d+,\"(.*)\",(\\d+)$", replystring.strip())
- reply = reresult.group(1)
- encoding = reresult.group(2)
+ reresult = re.match("(?s)^\\+CUSD: (\\d+),\"(.*)\",(\\d+)$", replystring.strip())
+
+ # 0 no further user action required (network initiated USSD-Notify, or no further information needed after mobile initiated operation)
+ # 1 further user action required (network initiated USSD-Request, or further information needed after mobile initiated operation)
+ # 2 USSD terminated by network
+ # 3 other local client has responded
+ # 4 operation not supported
+ # 5 network time out
+ reply_status=reresult.group(1)
+ reply = reresult.group(2)
+ # See GSM 07.07 and GSM 03.38
+ encoding = reresult.group(3)
except:
retry -= 1
- print >> sys.stderr, "Couldn't parse modem answer."
+ print >> sys.stderr, "Couldn't parse modem answer: "+replystring
continue
+ if reply_status == 0:
+ # May be somebody else needs it
+ close_modem(modem)
+ modem = None
+ elif reply_status == 2:
+ print >> sys.stderr, "USSD terminated by network."
+ elif reply_status == 3:
+ print >> sys.stderr, "Error: other local client has responded."
+ elif reply_status == 4:
+ print >> sys.stderr, "Operation not supported."
+ elif reply_status == 5:
+ print >> sys.stderr, "Network time out."
+
# Decoding ansver
reply = gsmdecode.decode(reply, int(encoding))
if not allow_last_error and namber != "interactive" and stage == len(number) - 1:
retry = 0
-child.sendeof()
-fcntl.flock(lockf,fcntl.LOCK_UN)
-lockf.close()
+if modem != None:
+ close_modem (modem)