2 # -*- coding: utf-8 -*-
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published
5 ## by the Free Software Foundation; version 2 and higer.
7 ## Guseynov Alexey (kibergus bark-bark gmail.com) 2010
11 from subprocess import *
21 # Needed for correct output of utf-8 symbols.
22 sys.stdout=file("/dev/stdout", "wb")
24 def check_number(number):
28 if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#"]) :
32 if len(sys.argv) == 1:
33 print "Usage:\nussdquery.py <ussd number> [options]\nussdquery.py interactive [options]\n"+\
34 "Options:\n-l language. Allowed languages: German, English, Italian, French, Spanish, Dutch, Swedish, Danish, Portuguese, Finnish, Norwegian, Greek, Turkish, Reserved1, Reserved2, Unspecified\n"+\
35 "-r retry count. 0 default. Use -1 for infinite.\n-f If specified, errors, which occur on last query are threated as fatal\n"+\
36 "-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"+\
37 "-d delimeter. Default is '\\n> \n'"+\
38 "-m gain modem lock imidiately '"+\
39 "-s show GUI message box on last reply"+\
40 "For USSD menu navigation divide USSD number via spacebars for every next menu selection. Type exit in interactive mode to exit."
47 lockf = open("/tmp/ussdquery.lock", 'a')
48 fcntl.flock(lockf,fcntl.LOCK_EX)
50 os.chmod("/tmp/ussdquery.lock", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH)
56 fcntl.flock(lockf,fcntl.LOCK_UN)
59 def init_modem(modem):
60 # We have only one modem, simultaneous acces wouldn't bring anything good
64 while response != "OK" and init_retry > 0 :
66 # OK response should be recieved shortly
67 modem = pexpect.spawn('pnatd', [], 2)
68 # FIXME This is a dirty hack. A better solution needed
72 # Read our "at" command
75 response = modem.readline().strip()
76 except pexpect.TIMEOUT:
85 # Switch output encoding to GSM default encoding
86 modem.send('at+cscs="GSM"\r');
90 response = modem.readline().strip()
91 except pexpect.TIMEOUT:
100 if response != "OK" :
101 print >> sys.stderr, "Couldn't init modem."
107 modem.timeout = timeout
110 def close_modem (modem):
116 allow_last_error = True
122 if sys.argv[1] == "interactive":
123 number = "interactive"
125 number = sys.argv[1].split(" ")
127 if not check_number(n):
128 print >> sys.stderr, "Syntax error in USSD number."
133 # Parsing command line options
136 while arg < len(sys.argv)-1:
139 if sys.argv[arg] == "-l":
142 if sys.argv[arg] == "-r":
145 if sys.argv[arg] == "-t":
148 if sys.argv[arg] == "-d":
151 if sys.argv[arg] == "-f":
152 allow_last_error = False
154 if sys.argv[arg] == "-s":
157 if sys.argv[arg] == "-m":
158 modem = init_modem(modem)
162 if sys.argv[arg] == "German":
164 elif sys.argv[arg] == "English":
166 elif sys.argv[arg] == "Italian":
168 elif sys.argv[arg] == "French":
170 elif sys.argv[arg] == "Spanish":
172 elif sys.argv[arg] == "Dutch":
174 elif sys.argv[arg] == "Swedish":
176 elif sys.argv[arg] == "Danish":
178 elif sys.argv[arg] == "Portuguese":
180 elif sys.argv[arg] == "Finnish":
182 elif sys.argv[arg] == "Norwegian":
184 elif sys.argv[arg] == "Greek":
186 elif sys.argv[arg] == "Turkish":
188 elif sys.argv[arg] == "Reserved1":
190 elif sys.argv[arg] == "Reserved2":
192 elif sys.argv[arg] == "Unspecified":
195 print >> sys.stderr, "Language unknown, falling back to unspecified."
200 if number == "interactive":
201 delimiter = sys.argv[arg]
203 print >> sys.stderr, "Delimiter is only supported in interactive mode."
208 if number == "interactive":
209 print >> sys.stderr, "Retry is only supported in normal mode."
212 retry = int(sys.argv[arg])
214 print >> sys.stderr, "Number of allowed errors must be >= -1. -1 assumed."
217 print >> sys.stderr, "Retry must be an integer."
221 if state == "timeout":
223 timeout = int(sys.argv[arg])
225 print >> sys.stderr, "Timeout must be an integer."
230 print >> sys.stderr, "Unrecogmized argument: "+sys.argv[arg]
235 retry_forever = False
237 bus = dbus.SystemBus()
238 ussdd = bus.get_object("su.kibergus.ussdd", "/su/kibergus/ussdd")
239 ussdd_int = dbus.Interface(ussdd, "su.kibergus.ussdd")
241 # Now we are ready to send commands
244 if number == "interactive":
245 sys.stdout.write(delimiter)
247 while number == "interactive" or stage < len(number):
248 if number == "interactive":
249 cnumber = sys.stdin.readline().strip()
250 if cnumber == "exit":
254 if not check_number (cnumber):
255 sys.stdout.write ("Syntax error in USSD number"+delimiter)
259 cnumber = number[stage]
262 modem = init_modem(modem)
264 if retry == -1 and not retry_forever:
265 print >> sys.stderr, "Retry limit is over. Giving up."
269 if number != "interactive" and not show_qussd or stage != len(number)-1:
270 ussdd_int.skip_next()
272 modem.send('at+cusd=1,"'+cnumber+'",'+str(language)+'\r')
273 # Read our query echoed back
276 #Read and parse reply
277 replystring = modem.readline().decode('string_escape')
278 # This will read out unneeded info from modem
281 except pexpect.TIMEOUT:
282 print >> sys.stderr, "Timeout. Modem didn't reply."
284 ussdd_int.show_next()
287 if replystring.strip() == "ERROR" :
289 print >> sys.stderr, "Modem returned ERROR. Query not executed."
290 ussdd_int.show_next()
294 reresult = re.match("(?s)^\\+CUSD: (\\d+),\"(.*)\",(\\d+)$", replystring.strip())
296 # 0 no further user action required (network initiated USSD-Notify, or no further information needed after mobile initiated operation)
297 # 1 further user action required (network initiated USSD-Request, or further information needed after mobile initiated operation)
298 # 2 USSD terminated by network
299 # 3 other local client has responded
300 # 4 operation not supported
302 reply_status=reresult.group(1)
303 reply = reresult.group(2)
304 # See GSM 07.07 and GSM 03.38
305 encoding = reresult.group(3)
308 print >> sys.stderr, "Couldn't parse modem answer: "+replystring
311 if reply_status == 0:
312 # May be somebody else needs it
315 elif reply_status == 2:
316 print >> sys.stderr, "USSD terminated by network."
317 elif reply_status == 3:
318 print >> sys.stderr, "Error: other local client has responded."
319 elif reply_status == 4:
320 print >> sys.stderr, "Operation not supported."
321 elif reply_status == 5:
322 print >> sys.stderr, "Network time out."
325 reply = gsmdecode.decode(reply, int(encoding))
327 if number == "interactive":
329 sys.stdout.write(reply+delimiter)
332 if stage == len(number)-1:
335 if not allow_last_error and namber != "interactive" and stage == len(number) - 1: