2 # -*- coding: utf-8 -*-
4 ## This program is free software; you can redistribute it and/or modify
5 ## it under the terms of the GNU General Public License as published
6 ## by the Free Software Foundation; version 2 and higer.
8 ## Guseynov Alexey (kibergus bark-bark gmail.com) 2010
25 from dbus.mainloop.glib import DBusGMainLoop
28 t = gettext.translation('ussd-widget', '/usr/share/locale')
31 print "Translation file for your language not found"
36 ussd_languages = ["German", "English", "Italian", "French", "Spanish", "Dutch", "Swedish", "Danish", "Portuguese", "Finnish", "Norwegian", "Greek", "Turkish", "Reserved1", "Reserved2", "Unspecified"]
37 ussd_languages_localized = [_("German"), _("English"), _("Italian"), _("French"), _("Spanish"), _("Dutch"), _("Swedish"), _("Danish"), _("Portuguese"), _("Finnish"), _("Norwegian"), _("Greek"), _("Turkish"), _("Reserved1"), _("Reserved2"), _("Unspecified")]
39 # TODO Cutt off too long messages and show them in separate dialog
40 # how TODO widget vertical minimum size policy
42 class USSD_Controller:
43 def __init__( self, widget ) :
45 # number, parser, chain, interval, regexp, width, execute_at_start, retry pattern, font, name, language, show_message_box, message_box_parser, additional arguments, regexp group, use SMS listener, SMS number, SMS regexp, SMS timeout
46 self.default_config = ["", "", "", 0, "", 0, True, [], pango.FontDescription("Nokia Sans 18"), _("Click to update"), 15, False, "", "", 1, False, "", "", 60]
47 self.config = self.default_config
48 self.timeout_version = 0
49 self.retry_version = 0
54 def save_config( self ) :
55 configname = os.getenv("HOME")+"/.ussdWidget.conf"
57 lockf = open(configname+".lock", 'a')
58 fcntl.flock(lockf,fcntl.LOCK_EX)
62 fconfig = open(configname,"r")
63 #Read configuration of other instances
67 my_section = line[1:].strip() == self.id
72 print _("Couldn't read previous config")
74 fconfig = open(configname,"w")
76 fconfig.write(oldconfig)
77 fconfig.write("%"+self.id+"\n");
78 fconfig.writelines(["# USSD query to be run by widget\n", "number="+self.config[0], "\n"])
79 fconfig.writelines(["#Parser command for widget\n", "parser="+self.config[1], "\n"])
80 fconfig.writelines(["#Parser command for banner\n", "parser_box="+self.config[12], "\n"])
81 fconfig.writelines(["#Chain command\n", "chain="+self.config[2], "\n"])
82 fconfig.writelines(["#Update interval in minutes\n", "interval="+str(self.config[3]), "\n"])
83 fconfig.writelines(["#RegExp pattern\n", "regexp="+self.config[4], "\n"])
84 fconfig.writelines(["#Widget width\n", "width="+str(self.config[5]), "\n"])
85 fconfig.writelines(["#Execute query at start\n", "query_at_start="+str(self.config[6]), "\n"])
86 fconfig.writelines(["#Retry pattern\n"])
87 fconfig.write("retry=")
89 for i in self.config[7]:
95 fconfig.writelines(["#Font description\n", "font="+self.config[8].to_string(), "\n"])
96 fconfig.writelines(["#Font color\n", "text_color="+self.widget.get_text_color().to_string(), "\n"])
97 fconfig.writelines(["#Background color\n", "bg_color="+self.widget.get_bg_color().to_string(), "\n"])
98 fconfig.writelines(["#Widget name\n", "name="+self.config[9], "\n"])
99 fconfig.writelines(["#Show banner\n", "show_box="+str(self.config[11]), "\n"])
100 fconfig.writelines(["#USSD reply language\n", "language="+str(self.config[10]), "\n"])
101 fconfig.writelines(["#Additional ussdquery.py arguments\n", "args="+self.config[13], "\n"])
102 fconfig.writelines(["#Regexp matching group\n", "reggroup="+str(self.config[14]), "\n"])
103 fconfig.writelines(["#Use SMS listener\n", "listen_sms="+str(self.config[15]), "\n"])
104 fconfig.writelines(["#Number,from which SMS should come\n", "sms_number="+self.config[16], "\n"])
105 fconfig.writelines(["#SMS RegExp pattern\n", "sms_regexp="+self.config[17], "\n"])
106 fconfig.writelines(["#SMS timeout\n", "sms_timeout="+str(self.config[18]), "\n"])
109 fcntl.flock(lockf,fcntl.LOCK_UN)
112 def get_config(self):
115 def read_config( self, id ):
118 config = open(os.getenv("HOME")+"/.ussdWidget.conf","r")
128 my_section = line[1:].strip() == id
132 # This is config for another instace
135 line=line.split('=', 1)
139 print _("Error reading config on line %(line)d. = or # expected.")%{"line":i}
141 if line[0] == "number" :
142 self.config[0] = line[1].strip()
143 elif line[0] == "parser" :
144 self.config[1] = line[1].strip()
145 elif line[0] == "parser_box" :
146 self.config[12] = line[1].strip()
147 elif line[0] == "chain" :
148 self.config[2] = line[1].strip()
149 elif line[0] == "interval" :
151 self.config[3] = int(line[1].strip())
154 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
156 elif line[0] == "regexp" :
157 self.config[4] = line[1].strip()
158 elif line[0] == "width" :
160 self.config[5] = int(line[1].strip())
163 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
165 elif line[0] == "query_at_start" :
166 if line[1].strip() == "True" :
167 self.config[6] = True
169 self.config[6] = False
170 elif line[0] == "retry" :
171 line[1] = line[1].strip()
173 line[1] = line[1].split("-")
175 while i < len(line[1]) :
177 line[1][i] = int(line[1][i])
180 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
182 self.config[7] = line[1]
186 elif line[0] == "font" :
188 self.config[8] = pango.FontDescription(line[1].strip())
191 print _("Error reading config on line %(line)d. Pango font description expected.")%{"line":i}
193 elif line[0] == "bg_color" :
195 self.widget.set_bg_color(gtk.gdk.color_parse(line[1].strip()))
198 print _("Error reading config on line %(line)d. Expected color definition.")%{"line":i}
199 elif line[0] == "text_color" :
201 self.widget.set_text_color(gtk.gdk.color_parse(line[1].strip()))
204 print _("Error reading config on line %(line)d. Expected color definition.")%{"line":i}
205 elif line[0] == "name" :
206 self.config[9] = line[1].strip()
207 elif line[0] == "show_box" :
208 if line[1].strip() == "True" :
209 self.config[11] = True
211 self.config[11] = False
212 elif line[0] == "language" :
214 if int(line[1].strip()) >=0 and int(line[1].strip()) < len(ussd_languages):
215 self.config[10] = int(line[1].strip())
218 print _("Error reading config on line %(line)d. Unknown language code.")%{"line":i}
221 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
222 elif line[0] == "args" :
223 self.config[13] = line[1].strip()
224 elif line[0] == "reggroup" :
226 self.config[14] = int(line[1].strip())
229 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
231 elif line[0] == "listen_sms" :
232 if line[1].strip() == "True" :
233 self.config[15] = True
235 self.config[15] = False
236 elif line[0] == "sms_number" :
237 self.config[16] = line[1].strip()
238 elif line[0] == "sms_regexp" :
239 self.config[17] = line[1].strip()
240 elif line[0] == "sms_timeout" :
242 self.config[18] = int(line[1].strip())
245 print _("Error reading config on line %(line)d. Integer expected.")%{"line":i}
249 print _("Error reading config on line %(line)d. Unexpected variable: ")%{"line":i}+line[0]
255 self.widget.error = 1
256 self.widget.set_text (_("Config error"), 5000)
260 self.widget.error = 1
261 self.widget.set_text (_("Config error"), 0)
262 print _("IO error while reading config")
264 return self.default_config
266 def on_show_settings( self, widget ) :
267 dialog = UssdConfigDialog(self.config, self.widget.get_bg_color(), self.widget.get_text_color(), self.id)
270 if dialog.run() != gtk.RESPONSE_OK :
274 test = check_regexp(dialog.regexp.get_text())
276 dialog.on_error_regexp(test)
279 # Check, that we have ussd number
280 if not check_number(dialog.ussdNumber.get_text()):
281 dialog.on_error_ussd_number()
284 if not check_number(dialog.sms_number.get_text()):
285 dialog.on_error_sms_number()
288 # Parse retry pattern
289 retry = dialog.retryEdit.get_text().strip()
291 retry = retry.split("-")
293 while i < len(retry) :
295 retry[i] = int(retry[i])
297 dialog.on_error_retry_pattern()
309 dialog.ussdNumber.get_text(),
310 dialog.parser.get_text(),
311 dialog.chain.get_text(),
312 dialog.update_interval.get_value(),
313 dialog.regexp.get_text(),
314 dialog.widthEdit.get_value(),
315 dialog.query_at_start.get_active(),
318 dialog.wname.get_text(),
319 dialog.language.get_active(),
320 dialog.show_box.get_active(),
321 dialog.b_parser.get_text(),
322 dialog.args.get_text(),
323 dialog.reggroup.get_value(),
324 dialog.sms_listener.get_active(),
325 dialog.sms_number.get_text(),
326 dialog.sms_regexp.get_text(),
327 dialog.sms_timeout.get_value()
330 widget.set_bg_color(dialog.bg_color)
331 widget.set_text_color(dialog.text_color)
335 widget.set_width(self.config[5])
336 self.reset_timed_renew()
337 self.widget.label.modify_font(self.config[8])
341 # Before running this function widget wasn't configured
342 if self.config == self.default_config:
343 self.widget.set_text(_("Click to update"))
346 def handle_sms(self, pdumsg, msgcenter, message, sendernumber):
347 # Timeout was recieved first
351 if self.config[16] == "" or self.config[16] == sendernumber:
352 pdu = gsmdecode.decode_pdu (pdumsg)
354 self.sms_reply += pdu['user_data']
356 if self.config[17] == "" or re.search( self.config[17], message, re.MULTILINE | re.UNICODE ):
357 self.sms_ready = True
358 self.sms_signal.remove()
361 def callback_ussd_data( self, source, condition ):
362 if condition == gobject.IO_IN or condition == gobject.IO_PRI :
363 data = source.read( )
365 self.cb_reply += data
371 elif condition == gobject.IO_HUP or condition == gobject.IO_ERR :
373 self.ussd_ready = True
377 print (_("serious problems in program logic"))
378 # This will force widget to show error message
385 def call_external_script( self, ussd_code, language ):
388 p = subprocess.Popen(['/usr/bin/ussdquery.py', ussd_code, "-l", ussd_languages[language]] + smart_split_string(self.config[13],"%","&"), stdout=subprocess.PIPE)
389 gobject.io_add_watch( p.stdout, gobject.IO_IN | gobject.IO_PRI | gobject.IO_HUP | gobject.IO_ERR , self.callback_ussd_data )
391 def ussd_renew(self, widget, event):
392 if self.widget.processing == 0:
394 widget.processing = 1
395 widget.set_text(_("Processing"), 0)
397 self.ussd_ready = False
398 self.sms_ready = False
402 self.sms_counter += 1
403 self.retry_timer = gobject.timeout_add (1000*self.config[18], self.sms_timeout, self.sms_counter)
405 self.bus = dbus.SystemBus()
406 self.sms_signal = self.bus.add_signal_receiver(self.handle_sms, path='/com/nokia/phone/SMS', dbus_interface='Phone.SMS', signal_name='IncomingSegment')
408 self.call_external_script( self.config[0], self.config[10] )
410 widget.processing = 0
412 widget.set_text(_("No config"), 0)
414 def process_reply( self ):
415 if not self.ussd_ready or not self.sms_ready and self.config[15]:
418 reply = self.cb_reply.strip()
419 sms_reply = self.sms_reply.strip()
421 if reply == "" or self.config[15] and sms_reply == "" :
422 self.widget.error = 1
423 self.widget.set_text (_("Error"), 5000)
424 if self.retry_state == len(self.config[7]):
425 self.retry_version += 1
428 self.retry_timer = gobject.timeout_add (1000*self.config[7][self.retry_state], self.retry_renew, self.retry_version)
429 self.retry_state += 1
431 self.widget.error = 0
433 reresult1 = reresult2 = None
434 if self.config[4] != "":
435 reresult1 = re.search( self.config[4], reply, re.MULTILINE | re.UNICODE )
436 if self.config[17] != "":
437 reresult2 = re.search( self.config[17], sms_reply, re.MULTILINE | re.UNICODE )
438 w_reply = b_reply = reply
439 if self.widget.error == 0:
441 if self.config[12] != "" and self.config[11]:
443 p = subprocess.Popen(smart_split_string(self.config[12], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE)
444 b_reply = p.communicate()[0].strip()
446 print _("Couldn't exec banner parser:")+str(e)
447 self.widget.error = 1
449 if self.config[4] != "":
451 b_reply = reresult1.group( self.config[14] )
453 self.widget.error = 1
454 b_reply = _("Group not found: \n") + reply
456 # Pass to widget parser
457 if self.config[1] != "":
459 p = subprocess.Popen(smart_split_string(self.config[1], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE)
460 w_reply = p.communicate()[0].strip()
462 print _("Couldn't exec widget parser:")+str(e)
463 self.widget.error = 1
465 if self.config[4] != "":
467 w_reply = reresult1.group( self.config[14] )
469 self.widget.error = 1
470 w_reply = _("Group not found: \n") + reply
472 if self.config[2] != "":
474 p = subprocess.Popen(smart_split_string(self.config[2], reply, sms_reply, reresult1, reresult2))
476 print _("Couldn't exec chain:")+str(e)
477 self.widget.error = 1
479 banner = hildon.hildon_banner_show_information (self.widget, "", b_reply)
480 banner.set_timeout (5000)
482 self.widget.set_text(w_reply)
483 self.widget.processing = 0
485 def sms_timeout(self, version):
486 if version == self.sms_counter :
488 self.sms_ready = True
489 self.sms_signal.remove()
493 def timed_renew(self, version):
494 if version < self.timeout_version :
496 self.ussd_renew(self.widget, None)
499 def retry_renew(self,version):
500 if self.widget.error == 0 or self.widget.processing == 1 or version < self.retry_version :
502 self.ussd_renew(self.widget, None)
505 def reset_timed_renew (self) :
506 self.timeout_version += 1
507 if self.config[3] != 0 :
508 self.timer = gobject.timeout_add (60000*self.config[3], self.timed_renew, self.timeout_version)
510 class pHelpDialog(gtk.Dialog):
511 def __init__(self, heading, text):
512 gtk.Dialog.__init__(self, heading, None,
513 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
514 (_("OK").encode("utf-8"), gtk.RESPONSE_OK))
515 label = gtk.Label(text)
516 label.set_line_wrap (True)
521 class UssdConfigDialog(gtk.Dialog):
522 def __init__(self, config, bg_color, text_color, id):
523 gtk.Dialog.__init__(self, _("USSD widget : "+id), None,
524 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
525 (_("Save").encode("utf-8"), gtk.RESPONSE_OK))
527 self.font = config[8]
528 self.bg_color = bg_color
529 self.text_color = text_color
531 self.set_size_request(-1, 400)
532 self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO)
533 self.ussdNumber.set_text(config[0])
534 self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO)
535 self.parser.set_text(config[1])
536 self.b_parser = hildon.Entry(gtk.HILDON_SIZE_AUTO)
537 self.b_parser.set_text(config[12])
539 self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO)
540 self.chain.set_text(config[2])
541 self.update_interval = hildon.NumberEditor(0, 9999)
542 self.update_interval.set_value(config[3])
543 self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO)
544 self.regexp.set_text(config[4])
545 self.widthEdit = hildon.NumberEditor(0, 1000)
546 self.widthEdit.set_value(config[5])
547 self.retryEdit = hildon.Entry(gtk.HILDON_SIZE_AUTO)
548 self.args = hildon.Entry(gtk.HILDON_SIZE_AUTO)
549 self.args.set_text(config[13])
550 self.reggroup = hildon.NumberEditor(0, 255)
551 self.reggroup.set_value(config[14])
553 selector = hildon.TouchSelector(text=True)
554 for i in ussd_languages_localized:
555 selector.append_text(i)
556 self.language = hildon.PickerButton(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
557 self.language.set_selector(selector)
558 self.language.set_active(config[10])
559 self.language.set_title(_("USSD reply language"))
560 self.language.set_size_request(-1, -1)
562 self.wname = hildon.Entry(gtk.HILDON_SIZE_AUTO)
563 self.wname.set_text(config[9])
564 self.show_box = gtk.CheckButton(_("Enable banner. Parser:"))
565 self.show_box.connect("toggled", self.show_box_changed)
566 self.show_box.set_active(config[11])
573 self.retryEdit.set_text(text)
575 self.query_at_start = gtk.CheckButton(_("Execute query on start"))
576 self.query_at_start.set_active(config[6])
578 self.fontButton = gtk.Button(_("Font"))
579 self.fontButton.connect("clicked", self.on_show_font_selection)
581 self.colorButton = gtk.Button(_("Background color"))
582 self.colorButton.connect("clicked", self.on_show_color_selection)
583 self.textColorButton = gtk.Button(_("Text color"))
584 self.textColorButton.connect("clicked", self.on_show_text_color_selection)
586 phelp = gtk.Button("?")
587 phelp.connect("clicked", self.on_show_phelp)
589 bphelp = gtk.Button("?")
590 bphelp.connect("clicked", self.on_show_bphelp)
592 chelp = gtk.Button("?")
593 chelp.connect("clicked", self.on_show_chelp)
595 reghelp = gtk.Button("?")
596 reghelp.connect("clicked", self.on_show_reghelp)
598 retryhelp = gtk.Button("?")
599 retryhelp.connect("clicked", self.on_show_retryhelp)
601 numberhelp = gtk.Button("?")
602 numberhelp.connect("clicked", self.on_show_number_help)
604 area = hildon.PannableArea()
607 area.add_with_viewport(vbox)
609 numberBox = gtk.HBox()
610 numberLabel = gtk.Label(_("USSD number"))
611 numberLabel.set_alignment(0,0.6)
612 numberLabel.set_size_request(100, -1)
613 numberhelp.set_size_request(1, -1)
614 self.ussdNumber.set_size_request(200, -1)
615 numberBox.add(numberLabel)
616 numberBox.add(numberhelp)
617 numberBox.add(self.ussdNumber)
620 vbox.add(self.query_at_start)
623 nameLabel = gtk.Label(_("Name"))
624 nameLabel.set_alignment(0,0.6)
625 nameLabel.set_size_request(100, -1)
626 self.wname.set_size_request(200, -1)
627 nameBox.add(nameLabel)
628 nameBox.add(self.wname)
631 parserBox = gtk.HBox()
632 parserLabel = gtk.Label(_("Parser for widget"))
633 parserLabel.set_alignment(0,0.6)
634 parserLabel.set_size_request(200, -1)
635 phelp.set_size_request(10, -1)
636 parserBox.add(parserLabel)
639 vbox.add(self.parser)
641 b_parserBox = gtk.HBox()
642 self.show_box.set_size_request(200, -1)
643 bphelp.set_size_request(10, -1)
644 b_parserBox.add(self.show_box)
645 b_parserBox.add(bphelp)
646 vbox.add(b_parserBox)
647 vbox.add(self.b_parser)
649 chainBox = gtk.HBox()
650 chainLabel = gtk.Label(_("Chain"))
651 chainLabel.set_alignment(0,0.6)
652 chainLabel.set_size_request(200, -1)
653 chelp.set_size_request(10, -1)
654 chainBox.add(chainLabel)
659 regexpBox = gtk.HBox()
660 regexpLabel = gtk.Label(_("Regular expression"))
661 regexpLabel.set_alignment(0,0.6)
662 regexpLabel.set_size_request(200, -1)
663 regexpGroupLabel = gtk.Label(_("Group"))
664 regexpGroupLabel.set_size_request(1, -1)
665 reghelp.set_size_request(10, -1)
666 regexpBox.add(regexpLabel)
667 regexpBox.add(reghelp)
668 regexpBox.add(regexpGroupLabel)
670 self.reggroup.set_size_request(1,-1);
671 self.regexp.set_size_request(250,-1);
672 regexpInputBox = gtk.HBox()
673 regexpInputBox.add(self.regexp)
674 regexpInputBox.add(self.reggroup)
675 vbox.add(regexpInputBox)
677 widthBox = gtk.HBox()
678 widthLabel = gtk.Label(_("Max. width"))
679 widthLabel.set_alignment(0,0.6)
680 symbolsLabel = gtk.Label(_("symbols"))
681 widthLabel.set_size_request(140, -1)
682 self.widthEdit.set_size_request(50, -1)
683 symbolsLabel.set_size_request(40,-1)
684 widthBox.add(widthLabel)
685 widthBox.add(self.widthEdit)
686 widthBox.add(symbolsLabel)
689 updateBox = gtk.HBox()
690 updateLabel = gtk.Label(_("Update every"))
691 updateLabel.set_alignment(0,0.6)
692 minutesLabel = gtk.Label(_("minutes"))
693 updateLabel.set_size_request(140, -1)
694 self.update_interval.set_size_request(50, -1)
695 minutesLabel.set_size_request(40, -1)
696 updateBox.add(updateLabel)
697 updateBox.add(self.update_interval)
698 updateBox.add(minutesLabel)
701 retryBox = gtk.HBox()
702 retryLabel = gtk.Label(_("Retry pattern"))
703 retryLabel.set_alignment(0,0.6)
704 retryLabel.set_size_request(200, -1)
705 retryhelp.set_size_request(10, -1)
706 retryBox.add(retryLabel)
707 retryBox.add(retryhelp)
709 vbox.add(self.retryEdit)
711 argsLabel = gtk.Label(_("Additional ussdquery.py options"))
712 argsLabel.set_alignment(0,0.6)
717 viewBox.add(self.fontButton)
718 viewBox.add(self.textColorButton)
719 viewBox.add(self.colorButton)
722 self.sms_box = gtk.VBox()
723 self.sms_listener = gtk.CheckButton(_("Enable SMS listener."))
724 self.sms_listener.connect("toggled", self.sms_box_changed)
725 self.sms_listener.set_active(config[15])
726 vbox.add (self.sms_listener)
728 self.sms_number = hildon.Entry(gtk.HILDON_SIZE_AUTO)
729 self.sms_number.set_text(config[16])
730 smsNumberBox = gtk.HBox()
731 smsNumberLabel = gtk.Label(_("SMS number"))
732 smsNumberLabel.set_alignment(0,0.6)
733 smsNumberLabel.set_size_request(100, -1)
734 self.sms_number.set_size_request(200, -1)
735 smsNumberBox.add(smsNumberLabel)
736 smsNumberBox.add(self.sms_number)
737 self.sms_box.add(smsNumberBox)
739 smsRegexpLabel = gtk.Label(_("Regular expression"))
740 smsRegexpLabel.set_alignment(0,0.6)
741 self.sms_box.add(smsRegexpLabel)
743 self.sms_regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO)
744 self.sms_regexp.set_text(config[17])
745 self.sms_box.add(self.sms_regexp)
747 self.sms_timeout = hildon.NumberEditor(0, 9999)
748 self.sms_timeout.set_value(config[18])
749 sms_timeout_box = gtk.HBox()
750 timeoutLabel = gtk.Label(_("Timeout"))
751 timeoutLabel.set_alignment(0,0.6)
752 secondsLabel = gtk.Label(_("seconds"))
753 timeoutLabel.set_size_request(140, -1)
754 self.sms_timeout.set_size_request(50, -1)
755 secondsLabel.set_size_request(40, -1)
756 sms_timeout_box.add(timeoutLabel)
757 sms_timeout_box.add(self.sms_timeout)
758 sms_timeout_box.add(secondsLabel)
759 self.sms_box.add(sms_timeout_box)
761 vbox.add(self.sms_box)
763 vbox.add(gtk.Label(_("DO NOT CHANGE. Unspecified is what you want.")))
764 vbox.add(self.language)
767 self.show_box_changed(None)
768 self.sms_box_changed(None)
771 #============ Dialog helper functions =============
772 def on_show_phelp(self, widget):
773 dialog = pHelpDialog(_("Format help"), _("Reply would be passed to specified utility, output of utility would be shown to you on widget.\n Format:\n% would be replaced by reply\n%N with N'th regexp matching group\n& would be replaced with sms content\n&N with N'th sms regexp group\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility\n Hint: use echo \"Your string %\" to prepend your string to reply."))
777 def on_show_bphelp(self, widget):
778 dialog = pHelpDialog(_("Format help"), _("Reply would be passed to specified utility, output of utility would be shown to you on banner.\n Format:\n% would be replaced by reply\n%N with N'th regexp matching group\n& would be replaced with sms content\n&N with N'th sms regexp group\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility\n Hint: use echo \"Your string %\" to prepend your string to reply."))
782 def on_show_chelp(self, widget):
783 dialog = pHelpDialog(_("Format help"), _("Reply would be passed to specified utility after parser utility. May be used for logging, statistics etc.\n Format:\n% would be replaced by reply\n%N with N'th regexp matching group\n& would be replaced with sms content\n&N with N'th sms regexp group\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility\n"))
787 def on_show_reghelp(self, widget):
788 dialog = pHelpDialog(_("Format help"), _("Standard python regexps. Use\n (.+?[\d\,\.]+)\n to delete everything after first number."))
792 def on_show_retryhelp(self, widget):
793 dialog = pHelpDialog(_("Format help"), _("Pauses between attemps (in seconds), delimited by -. For example 15-15-300 means \"In case of failure wait 15 seconds, try again, on failure wait 15 more secodns and try again, on failure make last attempt after 5 minutes\""))
797 def on_show_number_help(self, widget):
798 dialog = pHelpDialog(_("Format help"), _("USSD number. To perform USSD menu navigation divide queries vith spacebars. For xample '*100# 1' means 1st entry in *100# menu."))
802 def on_error_regexp(self, error):
803 dialog = pHelpDialog(_("Regexp syntax error"), error )
807 def on_error_ussd_number(self):
808 dialog = pHelpDialog(_("Incorrect USSD number"), _("USSD number should contain only digits, +, * or #") )
812 def on_error_retry_pattern(self):
813 dialog = pHelpDialog(_("Incorrect retry pattern"), _("Retry pattern should contain only numbers, delimited by -") )
817 def on_show_color_selection (self, event):
818 colorDialog = gtk.ColorSelectionDialog(_("Choose background color"))
819 colorDialog.colorsel.set_current_color(self.bg_color)
820 if colorDialog.run() == gtk.RESPONSE_OK :
821 self.bg_color = colorDialog.colorsel.get_current_color()
822 colorDialog.destroy()
824 def on_show_text_color_selection (self, event):
825 colorDialog = gtk.ColorSelectionDialog(_("Choose text color"))
826 colorDialog.colorsel.set_current_color(self.text_color)
827 if colorDialog.run() == gtk.RESPONSE_OK :
828 self.text_color = colorDialog.colorsel.get_current_color()
829 colorDialog.destroy()
831 def on_show_font_selection (self, event):
832 fontDialog = gtk.FontSelectionDialog(_("Choose a font"))
833 fontDialog.set_font_name(self.font.to_string())
835 if fontDialog.run() != gtk.RESPONSE_OK :
839 self.font = pango.FontDescription (fontDialog.get_font_name())
842 def show_box_changed (self, event):
843 if self.show_box.get_active():
848 def sms_box_changed (self, event):
849 if self.sms_listener.get_active():
854 def smart_split_string (str, reply1, reply2, reres1 = None, reres2 = None) :
857 # Is simbol backslashed?
859 # Quotes: 1 - ", 2 - ', 0 - no quotes
863 # Current substitution simbol
866 for i in range(len(str)) :
868 if str[i] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] :
874 if reres2 != None and num != 0:
875 word += reres2.group(num)
879 if reres1 != None and num != 0:
880 word += reres1.group(num)
886 # Delete backslash if it delimites usual numbers from % or &
887 if str[i] == '\\' and i < len(str)-1 and str[i+1] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] :
889 if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) :
891 elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") :
896 elif bs == 0 and str[i] == '\\' :
898 elif bs == 0 and (str[i] == '%' or str[i] == '&') :
902 if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" :
904 if qs == 0 and (str[i] == " " or str[i] == "\t") :
913 if reres2 != None and num != 0 and num != -1:
914 word += reres2.group(num)
918 if reres1 != None and num != 0 and num != -1:
919 word += reres1.group(num)
926 def check_regexp(regexp):
933 def check_number(number):
935 if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#", " "]) :
939 #=============== The widget itself ================
941 def get_color(logicalcolorname):
942 settings = gtk.settings_get_default()
943 color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button)
944 return color_style.lookup_color(logicalcolorname)
946 class UssdWidgetPlugin(hildondesktop.HomePluginItem):
948 hildondesktop.HomePluginItem.__init__(self)
951 self.bg_color=gtk.gdk.color_parse('#000000')
952 self.text_color=gtk.gdk.color_parse('#ffffff')
954 self.timeout_version = 0
956 colormap = self.get_screen().get_rgba_colormap()
957 self.set_colormap (colormap)
959 self.controller = USSD_Controller(self)
961 # TODO Click event would be better
962 self.connect("button-press-event", self.controller.ussd_renew)
964 self.vbox = gtk.HBox()
967 self.set_settings(True)
968 self.connect("show-settings", self.controller.on_show_settings)
969 self.label = gtk.Label("")
971 self.vbox.add(self.label)
972 self.vbox.set_child_packing(self.label, False, False, 0, gtk.PACK_START)
973 self.label.set_padding(15, 10)
974 self.label.set_size_request(-1,-1)
975 self.set_size_request(-1,-1)
976 self.label.set_line_wrap (True)
980 DBusGMainLoop(set_as_default=True)
981 bus = dbus.SystemBus()
982 signal = bus.add_signal_receiver(self.set_bg_color_text, path='/su/kibergus/ussd_widget', dbus_interface='su.kibergus.ussd_widget', signal_name='set_bg_color')
983 signal = bus.add_signal_receiver(self.set_text_color_text, path='/su/kibergus/ussd_widget', dbus_interface='su.kibergus.ussd_widget', signal_name='set_text_color')
984 signal = bus.add_signal_receiver(self.ussd_renew, path='/su/kibergus/ussd_widget', dbus_interface='su.kibergus.ussd_widget', signal_name='renew')
987 config = self.controller.read_config(self.get_applet_id())
988 self.set_width(config[5])
989 self.set_text(config[9])
991 self.controller.ussd_renew(self, None)
993 self.label.modify_font(config[8])
994 self.controller.reset_timed_renew()
995 hildondesktop.HomePluginItem.do_show(self)
997 def error_return (self):
998 if self.error == 1 and self.processing == 0:
999 self.set_text(self.text)
1003 # -1 - This is a permanent text message
1004 # 0 - This is service message, but it shouldn't be hidden automatically
1005 # >0 - This is service message, show permament message after showfor milliseconds
1006 def set_text(self, text, showfor=-1):
1008 # Show previous text after 5 seconds
1009 gobject.timeout_add (showfor, self.error_return)
1014 config = self.controller.get_config()
1015 self.label.set_text(text)
1020 def set_width(self, width):
1022 self.label.set_width_chars (width)
1024 self.label.set_width_chars(-1)
1026 def ussd_renew(self, id):
1027 if id == self.get_applet_id():
1028 self.controller.ussd_renew(self, None)
1030 def set_bg_color_text(self, id, color):
1031 if id == self.get_applet_id():
1033 self.set_bg_color(gtk.gdk.color_parse(color.strip()))
1035 print _("Unable to parse colour specification")
1038 def set_text_color_text(self, id, color):
1039 if id == self.get_applet_id():
1041 self.set_text_color(gtk.gdk.color_parse(color.strip()))
1043 print _("Unable to parse colour specification")
1046 def set_bg_color(self, color):
1047 self.bg_color = color
1049 def get_bg_color(self):
1050 return self.bg_color
1052 def set_text_color(self, color):
1053 self.label.modify_fg(gtk.STATE_NORMAL, color)
1054 self.text_color = color
1056 def get_text_color(self):
1057 return self.text_color
1059 def _expose(self, event):
1060 cr = self.window.cairo_create()
1063 width, height = self.label.allocation[2], self.label.allocation[3]
1065 #/* a custom shape, that could be wrapped in a function */
1066 x0 = 0 #/*< parameters like cairo_rectangle */
1069 radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */
1074 cr.move_to (x0, y0 + radius)
1075 cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14)
1076 cr.line_to (x1 - radius, y0)
1077 cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0)
1078 cr.line_to (x1 , y1 - radius)
1079 cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14)
1080 cr.line_to (x0 + radius, y1)
1081 cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14)
1085 fg_color = get_color("ActiveTextColor")
1087 if self.processing :
1090 bg_color=self.bg_color
1092 cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7)
1096 cr.set_source_rgba (1.0, 0.0, 0.0, 0.5)
1098 cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7)
1101 def do_expose_event(self, event):
1103 self._expose (event)
1104 self.vbox.do_expose_event (self, event)
1106 hd_plugin_type = UssdWidgetPlugin
1108 # The code below is just for testing purposes.
1109 # It allows to run the widget as a standalone process.
1110 if __name__ == "__main__":
1111 plugin_id = "ussd-widget.console"
1112 if len(sys.argv) == 2:
1114 plugin_id = "ussd-widget.desktop-"+str(int(sys.argv[1]))
1116 print "Plugin id must be integer"
1120 gobject.type_register(hd_plugin_type)
1121 obj = gobject.new(hd_plugin_type, plugin_id=plugin_id)