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 ensure_modem_listening (modem):
60 # We try to ger response for about 2 seconds
62 modem.send('at junk\r');
63 index = modem.expect (['ERROR\r', pexpect.TIMEOUT], 0.1);
66 index = modem.expect (['OK\r'], 1);
70 def init_modem(modem):
71 # We have only one modem, simultaneous acces wouldn't bring anything good
75 while response != "OK" and init_retry > 0 :
77 # OK response should be recieved shortly
78 modem = pexpect.spawn('pnatd', [], 2)
80 ensure_modem_listening (modem);
87 # Switch output encoding to GSM default encoding
88 modem.send('at+cscs="GSM"\r');
92 response = modem.readline().strip()
93 except pexpect.TIMEOUT:
102 if response != "OK" :
103 print >> sys.stderr, "Couldn't init modem."
109 modem.timeout = timeout
112 def close_modem (modem):
118 allow_last_error = True
124 if sys.argv[1] == "interactive":
125 number = "interactive"
127 number = sys.argv[1].split(" ")
129 if not check_number(n):
130 print >> sys.stderr, "Syntax error in USSD number."
135 # Parsing command line options
138 while arg < len(sys.argv)-1:
141 if sys.argv[arg] == "-l":
144 if sys.argv[arg] == "-r":
147 if sys.argv[arg] == "-t":
150 if sys.argv[arg] == "-d":
153 if sys.argv[arg] == "-f":
154 allow_last_error = False
156 if sys.argv[arg] == "-s":
159 if sys.argv[arg] == "-m":
160 modem = init_modem(modem)
164 if sys.argv[arg] == "German":
166 elif sys.argv[arg] == "English":
168 elif sys.argv[arg] == "Italian":
170 elif sys.argv[arg] == "French":
172 elif sys.argv[arg] == "Spanish":
174 elif sys.argv[arg] == "Dutch":
176 elif sys.argv[arg] == "Swedish":
178 elif sys.argv[arg] == "Danish":
180 elif sys.argv[arg] == "Portuguese":
182 elif sys.argv[arg] == "Finnish":
184 elif sys.argv[arg] == "Norwegian":
186 elif sys.argv[arg] == "Greek":
188 elif sys.argv[arg] == "Turkish":
190 elif sys.argv[arg] == "Reserved1":
192 elif sys.argv[arg] == "Reserved2":
194 elif sys.argv[arg] == "Unspecified":
197 print >> sys.stderr, "Language unknown, falling back to unspecified."
202 if number == "interactive":
203 delimiter = sys.argv[arg]
205 print >> sys.stderr, "Delimiter is only supported in interactive mode."
210 if number == "interactive":
211 print >> sys.stderr, "Retry is only supported in normal mode."
214 retry = int(sys.argv[arg])
216 print >> sys.stderr, "Number of allowed errors must be >= -1. -1 assumed."
219 print >> sys.stderr, "Retry must be an integer."
223 if state == "timeout":
225 timeout = int(sys.argv[arg])
227 print >> sys.stderr, "Timeout must be an integer."
232 print >> sys.stderr, "Unrecogmized argument: "+sys.argv[arg]
237 retry_forever = False
239 bus = dbus.SystemBus()
240 ussdd = bus.get_object("su.kibergus.ussdd", "/su/kibergus/ussdd")
241 ussdd_int = dbus.Interface(ussdd, "su.kibergus.ussdd")
243 # Now we are ready to send commands
246 if number == "interactive":
247 sys.stdout.write(delimiter)
249 while number == "interactive" or stage < len(number):
250 if number == "interactive":
251 cnumber = sys.stdin.readline().strip()
252 if cnumber == "exit":
256 if not check_number (cnumber):
257 sys.stdout.write ("Syntax error in USSD number"+delimiter)
261 cnumber = number[stage]
264 modem = init_modem(modem)
266 if retry == -1 and not retry_forever:
267 print >> sys.stderr, "Retry limit is over. Giving up."
271 if number != "interactive" and not show_qussd or stage != len(number)-1:
272 ussdd_int.skip_next()
274 modem.send('at+cusd=1,"'+cnumber+'",'+str(language)+'\r')
275 # Read our query echoed back
278 #Read and parse reply
279 replystring = modem.readline().decode('string_escape')
280 # This will read out unneeded info from modem
283 except pexpect.TIMEOUT:
284 print >> sys.stderr, "Timeout. Modem didn't reply."
286 ussdd_int.show_next()
289 if replystring.strip() == "ERROR" :
291 print >> sys.stderr, "Modem returned ERROR. Query not executed."
292 ussdd_int.show_next()
296 reresult = re.match("(?s)^\\+CUSD: (\\d+),\"(.*)\",(\\d+)$", replystring.strip())
298 # 0 no further user action required (network initiated USSD-Notify, or no further information needed after mobile initiated operation)
299 # 1 further user action required (network initiated USSD-Request, or further information needed after mobile initiated operation)
300 # 2 USSD terminated by network
301 # 3 other local client has responded
302 # 4 operation not supported
304 reply_status=reresult.group(1)
305 reply = reresult.group(2)
306 # See GSM 07.07 and GSM 03.38
307 encoding = reresult.group(3)
310 print >> sys.stderr, "Couldn't parse modem answer: "+replystring
313 if reply_status == 0:
314 # May be somebody else needs it
317 elif reply_status == 2:
318 print >> sys.stderr, "USSD terminated by network."
319 elif reply_status == 3:
320 print >> sys.stderr, "Error: other local client has responded."
321 elif reply_status == 4:
322 print >> sys.stderr, "Operation not supported."
323 elif reply_status == 5:
324 print >> sys.stderr, "Network time out."
327 reply = gsmdecode.decode(reply, int(encoding))
329 if number == "interactive":
331 sys.stdout.write(reply+delimiter)
334 if stage == len(number)-1:
337 if not allow_last_error and namber != "interactive" and stage == len(number) - 1: