From 16caa090ba8cca92377e6617f36ef68dc51e6fb5 Mon Sep 17 00:00:00 2001 From: Alexey Guseynov Date: Mon, 9 Apr 2012 23:50:43 +0400 Subject: [PATCH] Fix zimbie process. Add more logging. --- .../src/usr/lib/hildon-desktop/ussd-widget.py | 2155 ++++++++++---------- 1 file changed, 1091 insertions(+), 1064 deletions(-) diff --git a/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py b/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py index a84841c..8ac0d02 100755 --- a/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py +++ b/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py @@ -24,14 +24,19 @@ import gsmdecode import sys from dbus.mainloop.glib import DBusGMainLoop +# Would be truncated on every reboot, and shouldn't write +# anythong if things go right way so it is OK not to have logrotate +log = open("/var/log/ussd-widget.log") +print >> sys.stderr, "Writing log to /var/log/ussd-widget.log" + try : - t = gettext.translation('ussd-widget', '/usr/share/locale') - _ = t.ugettext + t = gettext.translation('ussd-widget', '/usr/share/locale') + _ = t.ugettext except IOError: - print "Translation file for your language not found" - def retme(arg): - return arg - _ = retme + print >> log, "Translation file for your language not found" + def retme(arg): + return arg + _ = retme ussd_languages = ["German", "English", "Italian", "French", "Spanish", "Dutch", "Swedish", "Danish", "Portuguese", "Finnish", "Norwegian", "Greek", "Turkish", "Reserved1", "Reserved2", "Unspecified"] ussd_languages_localized = [_("German"), _("English"), _("Italian"), _("French"), _("Spanish"), _("Dutch"), _("Swedish"), _("Danish"), _("Portuguese"), _("Finnish"), _("Norwegian"), _("Greek"), _("Turkish"), _("Reserved1"), _("Reserved2"), _("Unspecified")] @@ -40,1084 +45,1106 @@ ussd_languages_localized = [_("German"), _("English"), _("Italian"), _("French") # how TODO widget vertical minimum size policy class USSD_Controller: - def __init__( self, widget ) : - self.widget = widget - # 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 - self.default_config = ["", "", "", 0, "", 0, True, [], pango.FontDescription("Nokia Sans 18"), _("Click to update"), 15, False, "", "", 1, False, "", "", 60] - self.config = self.default_config - self.timeout_version = 0 - self.retry_version = 0 - self.retry_state = 0 - self.sms_counter = 0 - self.sms_reply = "" - - def save_config( self ) : - configname = os.getenv("HOME")+"/.ussdWidget.conf" - # Aquire lock - lockf = open(configname+".lock", 'a') - fcntl.flock(lockf,fcntl.LOCK_EX) - - oldconfig="" - try: - fconfig = open(configname,"r") - #Read configuration of other instances - my_section = False - for line in fconfig : - if line[0] == '%': - my_section = line[1:].strip() == self.id - if not my_section: - oldconfig += line - fconfig.close() - except: - print _("Couldn't read previous config") - - fconfig = open(configname,"w") - fconfig.seek(0) - fconfig.write(oldconfig) - fconfig.write("%"+self.id+"\n"); - fconfig.writelines(["# USSD query to be run by widget\n", "number="+self.config[0], "\n"]) - fconfig.writelines(["#Parser command for widget\n", "parser="+self.config[1], "\n"]) - fconfig.writelines(["#Parser command for banner\n", "parser_box="+self.config[12], "\n"]) - fconfig.writelines(["#Chain command\n", "chain="+self.config[2], "\n"]) - fconfig.writelines(["#Update interval in minutes\n", "interval="+str(self.config[3]), "\n"]) - fconfig.writelines(["#RegExp pattern\n", "regexp="+self.config[4], "\n"]) - fconfig.writelines(["#Widget width\n", "width="+str(self.config[5]), "\n"]) - fconfig.writelines(["#Execute query at start\n", "query_at_start="+str(self.config[6]), "\n"]) - fconfig.writelines(["#Retry pattern\n"]) - fconfig.write("retry=") - first = True - for i in self.config[7]: - if not first: - fconfig.write ("-") - fconfig.write(str(i)) - first = False - fconfig.write("\n") - fconfig.writelines(["#Font description\n", "font="+self.config[8].to_string(), "\n"]) - fconfig.writelines(["#Font color\n", "text_color="+self.widget.get_text_color().to_string(), "\n"]) - fconfig.writelines(["#Background color\n", "bg_color="+self.widget.get_bg_color().to_string(), "\n"]) - fconfig.writelines(["#Widget name\n", "name="+self.config[9], "\n"]) - fconfig.writelines(["#Show banner\n", "show_box="+str(self.config[11]), "\n"]) - fconfig.writelines(["#USSD reply language\n", "language="+str(self.config[10]), "\n"]) - fconfig.writelines(["#Additional ussdquery.py arguments\n", "args="+self.config[13], "\n"]) - fconfig.writelines(["#Regexp matching group\n", "reggroup="+str(self.config[14]), "\n"]) - fconfig.writelines(["#Use SMS listener\n", "listen_sms="+str(self.config[15]), "\n"]) - fconfig.writelines(["#Number,from which SMS should come\n", "sms_number="+self.config[16], "\n"]) - fconfig.writelines(["#SMS RegExp pattern\n", "sms_regexp="+self.config[17], "\n"]) - fconfig.writelines(["#SMS timeout\n", "sms_timeout="+str(self.config[18]), "\n"]) - fconfig.close() - - fcntl.flock(lockf,fcntl.LOCK_UN) - lockf.close() - - def get_config(self): - return self.config - - def read_config( self, id ): - try : - self.id = id - config = open(os.getenv("HOME")+"/.ussdWidget.conf","r") - - error = False - i = 0 - my_section = False - for line in config : - i += 1 - if line[0] == '#': - continue - if line[0] == '%': - my_section = line[1:].strip() == id - continue - - if not my_section: - # This is config for another instace - continue - - line=line.split('=', 1) - - if len(line) != 2 : - error = True - print _("Error reading config on line %(line)d. = or # expected.")%{"line":i} - continue - if line[0] == "number" : - self.config[0] = line[1].strip() - elif line[0] == "parser" : - self.config[1] = line[1].strip() - elif line[0] == "parser_box" : - self.config[12] = line[1].strip() - elif line[0] == "chain" : - self.config[2] = line[1].strip() - elif line[0] == "interval" : - try: - self.config[3] = int(line[1].strip()) - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - continue - elif line[0] == "regexp" : - self.config[4] = line[1].strip() - elif line[0] == "width" : - try: - self.config[5] = int(line[1].strip()) - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - continue - elif line[0] == "query_at_start" : - if line[1].strip() == "True" : - self.config[6] = True - else : - self.config[6] = False - elif line[0] == "retry" : - line[1] = line[1].strip() - if line[1] != "": - line[1] = line[1].split("-") - i = 0 - while i < len(line[1]) : - try: - line[1][i] = int(line[1][i]) - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - i += 1 - self.config[7] = line[1] - else: - self.config[7] = [] - continue - elif line[0] == "font" : - try: - self.config[8] = pango.FontDescription(line[1].strip()) - except: - error = True - print _("Error reading config on line %(line)d. Pango font description expected.")%{"line":i} - continue - elif line[0] == "bg_color" : - try: - self.widget.set_bg_color(gtk.gdk.color_parse(line[1].strip())) - except: - error = True - print _("Error reading config on line %(line)d. Expected color definition.")%{"line":i} - elif line[0] == "text_color" : - try: - self.widget.set_text_color(gtk.gdk.color_parse(line[1].strip())) - except: - error = True - print _("Error reading config on line %(line)d. Expected color definition.")%{"line":i} - elif line[0] == "name" : - self.config[9] = line[1].strip() - elif line[0] == "show_box" : - if line[1].strip() == "True" : - self.config[11] = True - else : - self.config[11] = False - elif line[0] == "language" : - try: - if int(line[1].strip()) >=0 and int(line[1].strip()) < len(ussd_languages): - self.config[10] = int(line[1].strip()) - else: - error = True - print _("Error reading config on line %(line)d. Unknown language code.")%{"line":i} - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - elif line[0] == "args" : - self.config[13] = line[1].strip() - elif line[0] == "reggroup" : - try: - self.config[14] = int(line[1].strip()) - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - continue - elif line[0] == "listen_sms" : - if line[1].strip() == "True" : - self.config[15] = True - else : - self.config[15] = False - elif line[0] == "sms_number" : - self.config[16] = line[1].strip() - elif line[0] == "sms_regexp" : - self.config[17] = line[1].strip() - elif line[0] == "sms_timeout" : - try: - self.config[18] = int(line[1].strip()) - except: - error = True - print _("Error reading config on line %(line)d. Integer expected.")%{"line":i} - continue - else : - error = True - print _("Error reading config on line %(line)d. Unexpected variable: ")%{"line":i}+line[0] - continue - - config.close() - - if error : - self.widget.error = 1 - self.widget.set_text (_("Config error"), 5000) - - return self.config - except IOError: - self.widget.error = 1 - self.widget.set_text (_("Config error"), 0) - print _("IO error while reading config") - - return self.default_config - - def on_show_settings( self, widget ) : - dialog = UssdConfigDialog(self.config, self.widget.get_bg_color(), self.widget.get_text_color(), self.id) - - while True: - if dialog.run() != gtk.RESPONSE_OK : - dialog.destroy() - return - - test = check_regexp(dialog.regexp.get_text()) - if test : - dialog.on_error_regexp(test) - continue - - # Check, that we have ussd number - if not check_number(dialog.ussdNumber.get_text()): - dialog.on_error_ussd_number() - continue - - if not check_number(dialog.sms_number.get_text()): - dialog.on_error_sms_number() - continue - - # Parse retry pattern - retry = dialog.retryEdit.get_text().strip() - if retry != "" : - retry = retry.split("-") - i = 0 - while i < len(retry) : - try: - retry[i] = int(retry[i]) - except: - dialog.on_error_retry_pattern() - break - i += 1 - - if i < len(retry): - continue - else : - retry = [] - - break - - self.config = [ - dialog.ussdNumber.get_text(), - dialog.parser.get_text(), - dialog.chain.get_text(), - dialog.update_interval.get_value(), - dialog.regexp.get_text(), - dialog.widthEdit.get_value(), - dialog.query_at_start.get_active(), - retry, - dialog.font, - dialog.wname.get_text(), - dialog.language.get_active(), - dialog.show_box.get_active(), - dialog.b_parser.get_text(), - dialog.args.get_text(), - dialog.reggroup.get_value(), - dialog.sms_listener.get_active(), - dialog.sms_number.get_text(), - dialog.sms_regexp.get_text(), - dialog.sms_timeout.get_value() - ] - - widget.set_bg_color(dialog.bg_color) - widget.set_text_color(dialog.text_color) - - self.save_config() - - widget.set_width(self.config[5]) - self.reset_timed_renew() - self.widget.label.modify_font(self.config[8]) - - dialog.destroy() - - # Before running this function widget wasn't configured - if self.config == self.default_config: - self.widget.set_text(_("Click to update")) - return - - def handle_sms(self, pdumsg, msgcenter, message, sendernumber): - # Timeout was recieved first - if self.sms_ready: - return - - if self.config[16] == "" or self.config[16] == sendernumber: - pdu = gsmdecode.decode_pdu (pdumsg) - if pdu != None : - self.sms_reply += pdu['user_data'] - if not pdu['part']: - if self.config[17] == "" or re.search( self.config[17], message, re.MULTILINE | re.UNICODE ): - self.sms_ready = True - self.sms_signal.remove() - self.process_reply() - - def callback_ussd_data( self, source, condition ): - if condition == gobject.IO_IN or condition == gobject.IO_PRI : - data = source.read( ) - if len( data ) > 0 : - self.cb_reply += data - return True - else : - self.cb_ready = 1 - return False - - elif condition == gobject.IO_HUP or condition == gobject.IO_ERR : - self.cb_ready = 1 - self.ussd_ready = True - self.process_reply() - return False - - print (_("serious problems in program logic")) - # This will force widget to show error message - self.cb_reply = "" - self.cb_ready = 1 - self.process_reply() - return False - - - def call_external_script( self, ussd_code, language ): - self.cb_ready = 0 - self.cb_reply = ""; - p = subprocess.Popen(['/usr/bin/ussdquery.py', ussd_code, "-l", ussd_languages[language]] + smart_split_string(self.config[13],"%","&"), stdout=subprocess.PIPE) - gobject.io_add_watch( p.stdout, gobject.IO_IN | gobject.IO_PRI | gobject.IO_HUP | gobject.IO_ERR , self.callback_ussd_data ) - - def ussd_renew(self, widget, event): - if self.widget.processing == 0: - if self.config : - widget.processing = 1 - widget.set_text(_("Processing"), 0) - - self.ussd_ready = False - self.sms_ready = False - self.sms_reply = "" - - if self.config[15]: - self.sms_counter += 1 - self.retry_timer = gobject.timeout_add (1000*self.config[18], self.sms_timeout, self.sms_counter) - - self.bus = dbus.SystemBus() - self.sms_signal = self.bus.add_signal_receiver(self.handle_sms, path='/com/nokia/phone/SMS', dbus_interface='Phone.SMS', signal_name='IncomingSegment') - - self.call_external_script( self.config[0], self.config[10] ) - else : - widget.processing = 0 - widget.error = 1 - widget.set_text(_("No config"), 0) - - def process_reply( self ): - if not self.ussd_ready or not self.sms_ready and self.config[15]: - return - - reply = self.cb_reply.strip() - sms_reply = self.sms_reply.strip() - - if reply == "" or self.config[15] and sms_reply == "" : - self.widget.error = 1 - self.widget.set_text (_("Error"), 5000) - if self.retry_state == len(self.config[7]): - self.retry_version += 1 - self.retry_state = 0 - else : - self.retry_timer = gobject.timeout_add (1000*self.config[7][self.retry_state], self.retry_renew, self.retry_version) - self.retry_state += 1 - else : - self.widget.error = 0 - # Apply regexp - reresult1 = reresult2 = None - if self.config[4] != "": - reresult1 = re.search( self.config[4], reply, re.MULTILINE | re.UNICODE ) - if self.config[17] != "": - reresult2 = re.search( self.config[17], sms_reply, re.MULTILINE | re.UNICODE ) - w_reply = b_reply = reply - if self.widget.error == 0: - # Pass to box parser - if self.config[12] != "" and self.config[11]: - try: - p = subprocess.Popen(smart_split_string(self.config[12], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE) - b_reply = p.communicate()[0].strip() - except Exception, e: - print _("Couldn't exec banner parser:")+str(e) - self.widget.error = 1 - else: - if self.config[4] != "": - try : - b_reply = reresult1.group( self.config[14] ) - except Exception, e: - self.widget.error = 1 - b_reply = _("Group not found: \n") + reply - - # Pass to widget parser - if self.config[1] != "": - try: - p = subprocess.Popen(smart_split_string(self.config[1], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE) - w_reply = p.communicate()[0].strip() - except Exception, e: - print _("Couldn't exec widget parser:")+str(e) - self.widget.error = 1 - else: - if self.config[4] != "": - try : - w_reply = reresult1.group( self.config[14] ) - except Exception, e: - self.widget.error = 1 - w_reply = _("Group not found: \n") + reply - # Pass to chain - if self.config[2] != "": - try: - p = subprocess.Popen(smart_split_string(self.config[2], reply, sms_reply, reresult1, reresult2)) - except Exception, e: - print _("Couldn't exec chain:")+str(e) - self.widget.error = 1 - if self.config[11]: - banner = hildon.hildon_banner_show_information (self.widget, "", b_reply) - banner.set_timeout (5000) - b_reply - self.widget.set_text(w_reply) - self.widget.processing = 0 - - def sms_timeout(self, version): - if version == self.sms_counter : - self.sms_reply = "" - self.sms_ready = True - self.sms_signal.remove() - self.process_reply() - return False - - def timed_renew(self, version): - if version < self.timeout_version : - return False - self.ussd_renew(self.widget, None) - return True - - def retry_renew(self,version): - if self.widget.error == 0 or self.widget.processing == 1 or version < self.retry_version : - return False - self.ussd_renew(self.widget, None) - return False - - def reset_timed_renew (self) : - self.timeout_version += 1 - if self.config[3] != 0 : - self.timer = gobject.timeout_add (60000*self.config[3], self.timed_renew, self.timeout_version) + def __init__( self, widget ) : + self.widget = widget + # 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 + self.default_config = ["", "", "", 0, "", 0, True, [],\ + pango.FontDescription("Nokia Sans 18"), _("Click to update"),\ + 15, False, "", "", 1, False, "", "", 60] + self.config = self.default_config + self.timeout_version = 0 + self.retry_version = 0 + self.retry_state = 0 + self.sms_counter = 0 + self.sms_reply = "" + + def save_config( self ) : + configname = os.getenv("HOME")+"/.ussdWidget.conf" + # Aquire lock + lockf = open(configname+".lock", 'a') + fcntl.flock(lockf,fcntl.LOCK_EX) + + oldconfig="" + try: + fconfig = open(configname,"r") + #Read configuration of other instances + my_section = False + for line in fconfig : + if line[0] == '%': + my_section = line[1:].strip() == self.id + if not my_section: + oldconfig += line + fconfig.close() + except: + print >> log, _("Couldn't read previous config") + + fconfig = open(configname,"w") + fconfig.seek(0) + fconfig.write(oldconfig) + fconfig.write("%"+self.id+"\n"); + fconfig.writelines(["#USSD query to be run by widget\n", "number="+self.config[0], "\n"]) + fconfig.writelines(["#Parser command for widget\n", "parser="+self.config[1], "\n"]) + fconfig.writelines(["#Parser command for banner\n", "parser_box="+self.config[12], "\n"]) + fconfig.writelines(["#Chain command\n", "chain="+self.config[2], "\n"]) + fconfig.writelines(["#Update interval in minutes\n", "interval="+str(self.config[3]), "\n"]) + fconfig.writelines(["#RegExp pattern\n", "regexp="+self.config[4], "\n"]) + fconfig.writelines(["#Widget width\n", "width="+str(self.config[5]), "\n"]) + fconfig.writelines(["#Execute query at start\n", "query_at_start="+str(self.config[6]), "\n"]) + fconfig.writelines(["#Retry pattern\n"]) + fconfig.write("retry=") + first = True + for i in self.config[7]: + if not first: + fconfig.write ("-") + fconfig.write(str(i)) + first = False + fconfig.write("\n") + fconfig.writelines(["#Font description\n", "font="+self.config[8].to_string(), "\n"]) + fconfig.writelines(["#Font color\n", "text_color="+self.widget.get_text_color().to_string(), "\n"]) + fconfig.writelines(["#Background color\n", "bg_color="+self.widget.get_bg_color().to_string(), "\n"]) + fconfig.writelines(["#Widget name\n", "name="+self.config[9], "\n"]) + fconfig.writelines(["#Show banner\n", "show_box="+str(self.config[11]), "\n"]) + fconfig.writelines(["#USSD reply language\n", "language="+str(self.config[10]), "\n"]) + fconfig.writelines(["#Additional ussdquery.py arguments\n", "args="+self.config[13], "\n"]) + fconfig.writelines(["#Regexp matching group\n", "reggroup="+str(self.config[14]), "\n"]) + fconfig.writelines(["#Use SMS listener\n", "listen_sms="+str(self.config[15]), "\n"]) + fconfig.writelines(["#Number,from which SMS should come\n", "sms_number="+self.config[16], "\n"]) + fconfig.writelines(["#SMS RegExp pattern\n", "sms_regexp="+self.config[17], "\n"]) + fconfig.writelines(["#SMS timeout\n", "sms_timeout="+str(self.config[18]), "\n"]) + fconfig.close() + + fcntl.flock(lockf,fcntl.LOCK_UN) + lockf.close() + + def get_config(self): + return self.config + + def read_config( self, id ): + try : + self.id = id + config = open(os.getenv("HOME")+"/.ussdWidget.conf","r") + + error = False + i = 0 + my_section = False + for line in config : + i += 1 + if line[0] == '#': + continue + if line[0] == '%': + my_section = line[1:].strip() == id + continue + + if not my_section: + # This is config for another instace + continue + + line=line.split('=', 1) + + if len(line) != 2 : + error = True + print >> log, _("Error reading config on line %(line)d. = or # expected.")%{"line":i} + continue + if line[0] == "number" : + self.config[0] = line[1].strip() + elif line[0] == "parser" : + self.config[1] = line[1].strip() + elif line[0] == "parser_box" : + self.config[12] = line[1].strip() + elif line[0] == "chain" : + self.config[2] = line[1].strip() + elif line[0] == "interval" : + try: + self.config[3] = int(line[1].strip()) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + continue + elif line[0] == "regexp" : + self.config[4] = line[1].strip() + elif line[0] == "width" : + try: + self.config[5] = int(line[1].strip()) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + continue + elif line[0] == "query_at_start" : + if line[1].strip() == "True" : + self.config[6] = True + else : + self.config[6] = False + elif line[0] == "retry" : + line[1] = line[1].strip() + if line[1] != "": + line[1] = line[1].split("-") + i = 0 + while i < len(line[1]) : + try: + line[1][i] = int(line[1][i]) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + i += 1 + self.config[7] = line[1] + else: + self.config[7] = [] + continue + elif line[0] == "font" : + try: + self.config[8] = pango.FontDescription(line[1].strip()) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Pango font description expected.")%{"line":i} + continue + elif line[0] == "bg_color" : + try: + self.widget.set_bg_color(gtk.gdk.color_parse(line[1].strip())) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Expected color definition.")%{"line":i} + elif line[0] == "text_color" : + try: + self.widget.set_text_color(gtk.gdk.color_parse(line[1].strip())) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Expected color definition.")%{"line":i} + elif line[0] == "name" : + self.config[9] = line[1].strip() + elif line[0] == "show_box" : + if line[1].strip() == "True" : + self.config[11] = True + else : + self.config[11] = False + elif line[0] == "language" : + try: + if int(line[1].strip()) >=0 and int(line[1].strip()) < len(ussd_languages): + self.config[10] = int(line[1].strip()) + else: + error = True + print >> log, _("Error reading config on line %(line)d. Unknown language code.")%{"line":i} + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + elif line[0] == "args" : + self.config[13] = line[1].strip() + elif line[0] == "reggroup" : + try: + self.config[14] = int(line[1].strip()) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + continue + elif line[0] == "listen_sms" : + if line[1].strip() == "True" : + self.config[15] = True + else : + self.config[15] = False + elif line[0] == "sms_number" : + self.config[16] = line[1].strip() + elif line[0] == "sms_regexp" : + self.config[17] = line[1].strip() + elif line[0] == "sms_timeout" : + try: + self.config[18] = int(line[1].strip()) + except: + error = True + print >> log, _("Error reading config on line %(line)d. Integer expected.")%{"line":i} + continue + else : + error = True + print >> log, _("Error reading config on line %(line)d. Unexpected variable: ")%{"line":i}+line[0] + continue + + config.close() + + if error : + self.widget.error = 1 + self.widget.set_text (_("Config error"), 5000) + + return self.config + except IOError: + self.widget.error = 1 + self.widget.set_text (_("Config error"), 0) + print >> log, _("IO error while reading config") + + return self.default_config + + def on_show_settings( self, widget ) : + dialog = UssdConfigDialog(self.config, self.widget.get_bg_color(), self.widget.get_text_color(), self.id) + + while True: + if dialog.run() != gtk.RESPONSE_OK : + dialog.destroy() + return + + test = check_regexp(dialog.regexp.get_text()) + if test : + dialog.on_error_regexp(test) + continue + + # Check, that we have ussd number + if not check_number(dialog.ussdNumber.get_text()): + dialog.on_error_ussd_number() + continue + + if not check_number(dialog.sms_number.get_text()): + dialog.on_error_sms_number() + continue + + # Parse retry pattern + retry = dialog.retryEdit.get_text().strip() + if retry != "" : + retry = retry.split("-") + i = 0 + while i < len(retry) : + try: + retry[i] = int(retry[i]) + except: + dialog.on_error_retry_pattern() + break + i += 1 + + if i < len(retry): + continue + else : + retry = [] + + break + + self.config = [ + dialog.ussdNumber.get_text(), + dialog.parser.get_text(), + dialog.chain.get_text(), + dialog.update_interval.get_value(), + dialog.regexp.get_text(), + dialog.widthEdit.get_value(), + dialog.query_at_start.get_active(), + retry, + dialog.font, + dialog.wname.get_text(), + dialog.language.get_active(), + dialog.show_box.get_active(), + dialog.b_parser.get_text(), + dialog.args.get_text(), + dialog.reggroup.get_value(), + dialog.sms_listener.get_active(), + dialog.sms_number.get_text(), + dialog.sms_regexp.get_text(), + dialog.sms_timeout.get_value() + ] + + widget.set_bg_color(dialog.bg_color) + widget.set_text_color(dialog.text_color) + + self.save_config() + + widget.set_width(self.config[5]) + self.reset_timed_renew() + self.widget.label.modify_font(self.config[8]) + + dialog.destroy() + + # Before running this function widget wasn't configured + if self.config == self.default_config: + self.widget.set_text(_("Click to update")) + return + + def handle_sms(self, pdumsg, msgcenter, message, sendernumber): + # Timeout was recieved first + if self.sms_ready: + return + + if self.config[16] == "" or self.config[16] == sendernumber: + pdu = gsmdecode.decode_pdu (pdumsg) + if pdu != None : + self.sms_reply += pdu['user_data'] + if not pdu['part']: + if self.config[17] == "" or re.search( self.config[17], message, re.MULTILINE | re.UNICODE ): + self.sms_ready = True + self.sms_signal.remove() + self.process_reply() + + def callback_ussd_data(self, source, condition, process): + if condition == gobject.IO_IN or condition == gobject.IO_PRI: + data = source.read() + self.cb_reply += data + return True + + if condition == gobject.IO_ERR: + print >> log, "Communication error occured" + # This will force widget to show error message + self.cb_reply = "" + + if condition == gobject.IO_HUP: + # Pipe is broken, so ussd-query.py is already terminating + # and we wouldn't wait fot it too long + retcode = process.wait() + if retcode != 0: + self.cb_reply = "" + + self.ussd_ready = True + self.process_reply() + return False + + def callback_ussd_error(self, source, condition): + if condition == gobject.IO_IN or condition == gobject.IO_PRI: + self.error_message += source.read() + else: + if self.error_message != "": + print >> log, self.error_message + + def call_external_script(self, ussd_code, language): + self.cb_reply = ""; + process = subprocess.Popen( + ['/usr/bin/ussdquery.py', ussd_code, "-l", ussd_languages[language]] +\ + smart_split_string(self.config[13],"%","&"), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.stdin.close() + gobject.io_add_watch( + p.stdout, gobject.IO_IN | gobject.IO_PRI | gobject.IO_HUP | gobject.IO_ERR, + self.callback_ussd_data, + process) + self.error_message = ""; + gobject.io_add_watch( + p.stderr, gobject.IO_IN | gobject.IO_PRI | gobject.IO_HUP | gobject.IO_ERR, + self.callback_ussd_error) + + def ussd_renew(self, widget, event): + if self.widget.processing == 0: + if self.config : + widget.processing = 1 + widget.set_text(_("Processing"), 0) + + self.ussd_ready = False + self.sms_ready = False + self.sms_reply = "" + + if self.config[15]: + self.sms_counter += 1 + self.retry_timer = gobject.timeout_add (1000*self.config[18], self.sms_timeout, self.sms_counter) + + self.bus = dbus.SystemBus() + self.sms_signal = self.bus.add_signal_receiver(self.handle_sms, path='/com/nokia/phone/SMS', dbus_interface='Phone.SMS', signal_name='IncomingSegment') + + self.call_external_script( self.config[0], self.config[10] ) + else : + widget.processing = 0 + widget.error = 1 + widget.set_text(_("No config"), 0) + + def process_reply( self ): + if not self.ussd_ready or not self.sms_ready and self.config[15]: + return + + reply = self.cb_reply.strip() + sms_reply = self.sms_reply.strip() + + if reply == "" or self.config[15] and sms_reply == "" : + self.widget.error = 1 + self.widget.set_text (_("Error"), 5000) + if self.retry_state == len(self.config[7]): + self.retry_version += 1 + self.retry_state = 0 + else : + self.retry_timer = gobject.timeout_add (1000*self.config[7][self.retry_state], self.retry_renew, self.retry_version) + self.retry_state += 1 + else : + self.widget.error = 0 + # Apply regexp + reresult1 = reresult2 = None + if self.config[4] != "": + reresult1 = re.search( self.config[4], reply, re.MULTILINE | re.UNICODE ) + if self.config[17] != "": + reresult2 = re.search( self.config[17], sms_reply, re.MULTILINE | re.UNICODE ) + w_reply = b_reply = reply + if self.widget.error == 0: + # Pass to box parser + if self.config[12] != "" and self.config[11]: + try: + p = subprocess.Popen(smart_split_string(self.config[12], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE) + b_reply = p.communicate()[0].strip() + except Exception, e: + print >> log, _("Couldn't exec banner parser:")+str(e) + self.widget.error = 1 + else: + if self.config[4] != "": + try : + b_reply = reresult1.group( self.config[14] ) + except Exception, e: + self.widget.error = 1 + b_reply = _("Group not found: \n") + reply + + # Pass to widget parser + if self.config[1] != "": + try: + p = subprocess.Popen(smart_split_string(self.config[1], reply, sms_reply, reresult1, reresult2), stdout=subprocess.PIPE) + w_reply = p.communicate()[0].strip() + except Exception, e: + print >> log, _("Couldn't exec widget parser:")+str(e) + self.widget.error = 1 + else: + if self.config[4] != "": + try : + w_reply = reresult1.group( self.config[14] ) + except Exception, e: + self.widget.error = 1 + w_reply = _("Group not found: \n") + reply + # Pass to chain + if self.config[2] != "": + try: + p = subprocess.Popen(smart_split_string(self.config[2], reply, sms_reply, reresult1, reresult2)) + except Exception, e: + print >> log, _("Couldn't exec chain:")+str(e) + self.widget.error = 1 + if self.config[11]: + banner = hildon.hildon_banner_show_information (self.widget, "", b_reply) + banner.set_timeout (5000) + b_reply + self.widget.set_text(w_reply) + self.widget.processing = 0 + + def sms_timeout(self, version): + if version == self.sms_counter : + self.sms_reply = "" + self.sms_ready = True + self.sms_signal.remove() + self.process_reply() + return False + + def timed_renew(self, version): + if version < self.timeout_version : + return False + self.ussd_renew(self.widget, None) + return True + + def retry_renew(self,version): + if self.widget.error == 0 or self.widget.processing == 1 or version < self.retry_version : + return False + self.ussd_renew(self.widget, None) + return False + + def reset_timed_renew (self) : + self.timeout_version += 1 + if self.config[3] != 0 : + self.timer = gobject.timeout_add (60000*self.config[3], self.timed_renew, self.timeout_version) class pHelpDialog(gtk.Dialog): - def __init__(self, heading, text): - gtk.Dialog.__init__(self, heading, None, - gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, - (_("OK").encode("utf-8"), gtk.RESPONSE_OK)) - label = gtk.Label(text) - label.set_line_wrap (True) - self.vbox.add(label) - self.show_all() - self.parent + def __init__(self, heading, text): + gtk.Dialog.__init__(self, heading, None, + gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, + (_("OK").encode("utf-8"), gtk.RESPONSE_OK)) + label = gtk.Label(text) + label.set_line_wrap (True) + self.vbox.add(label) + self.show_all() + self.parent class UssdConfigDialog(gtk.Dialog): - def __init__(self, config, bg_color, text_color, id): - gtk.Dialog.__init__(self, _("USSD widget : "+id), None, - gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, - (_("Save").encode("utf-8"), gtk.RESPONSE_OK)) - - self.font = config[8] - self.bg_color = bg_color - self.text_color = text_color - - self.set_size_request(-1, 400) - self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.ussdNumber.set_text(config[0]) - self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.parser.set_text(config[1]) - self.b_parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.b_parser.set_text(config[12]) - - self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.chain.set_text(config[2]) - self.update_interval = hildon.NumberEditor(0, 9999) - self.update_interval.set_value(config[3]) - self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.regexp.set_text(config[4]) - self.widthEdit = hildon.NumberEditor(0, 1000) - self.widthEdit.set_value(config[5]) - self.retryEdit = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.args = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.args.set_text(config[13]) - self.reggroup = hildon.NumberEditor(0, 255) - self.reggroup.set_value(config[14]) - - selector = hildon.TouchSelector(text=True) - for i in ussd_languages_localized: - selector.append_text(i) - self.language = hildon.PickerButton(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_HORIZONTAL) - self.language.set_selector(selector) - self.language.set_active(config[10]) - self.language.set_title(_("USSD reply language")) - self.language.set_size_request(-1, -1) - - self.wname = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.wname.set_text(config[9]) - self.show_box = gtk.CheckButton(_("Enable banner. Parser:")) - self.show_box.connect("toggled", self.show_box_changed) - self.show_box.set_active(config[11]) - - text = "" - for i in config[7]: - if text != "": - text += "-" - text += str(i) - self.retryEdit.set_text(text) - - self.query_at_start = gtk.CheckButton(_("Execute query on start")) - self.query_at_start.set_active(config[6]) - - self.fontButton = gtk.Button(_("Font")) - self.fontButton.connect("clicked", self.on_show_font_selection) - - self.colorButton = gtk.Button(_("Background color")) - self.colorButton.connect("clicked", self.on_show_color_selection) - self.textColorButton = gtk.Button(_("Text color")) - self.textColorButton.connect("clicked", self.on_show_text_color_selection) - - phelp = gtk.Button("?") - phelp.connect("clicked", self.on_show_phelp) - - bphelp = gtk.Button("?") - bphelp.connect("clicked", self.on_show_bphelp) - - chelp = gtk.Button("?") - chelp.connect("clicked", self.on_show_chelp) - - reghelp = gtk.Button("?") - reghelp.connect("clicked", self.on_show_reghelp) - - retryhelp = gtk.Button("?") - retryhelp.connect("clicked", self.on_show_retryhelp) - - numberhelp = gtk.Button("?") - numberhelp.connect("clicked", self.on_show_number_help) - - area = hildon.PannableArea() - self.vbox.add(area) - vbox = gtk.VBox() - area.add_with_viewport(vbox) - - numberBox = gtk.HBox() - numberLabel = gtk.Label(_("USSD number")) - numberLabel.set_alignment(0,0.6) - numberLabel.set_size_request(100, -1) - numberhelp.set_size_request(1, -1) - self.ussdNumber.set_size_request(200, -1) - numberBox.add(numberLabel) - numberBox.add(numberhelp) - numberBox.add(self.ussdNumber) - vbox.add(numberBox) - - vbox.add(self.query_at_start) - - nameBox = gtk.HBox() - nameLabel = gtk.Label(_("Name")) - nameLabel.set_alignment(0,0.6) - nameLabel.set_size_request(100, -1) - self.wname.set_size_request(200, -1) - nameBox.add(nameLabel) - nameBox.add(self.wname) - vbox.add(nameBox) - - parserBox = gtk.HBox() - parserLabel = gtk.Label(_("Parser for widget")) - parserLabel.set_alignment(0,0.6) - parserLabel.set_size_request(200, -1) - phelp.set_size_request(10, -1) - parserBox.add(parserLabel) - parserBox.add(phelp) - vbox.add(parserBox) - vbox.add(self.parser) - - b_parserBox = gtk.HBox() - self.show_box.set_size_request(200, -1) - bphelp.set_size_request(10, -1) - b_parserBox.add(self.show_box) - b_parserBox.add(bphelp) - vbox.add(b_parserBox) - vbox.add(self.b_parser) - - chainBox = gtk.HBox() - chainLabel = gtk.Label(_("Chain")) - chainLabel.set_alignment(0,0.6) - chainLabel.set_size_request(200, -1) - chelp.set_size_request(10, -1) - chainBox.add(chainLabel) - chainBox.add(chelp) - vbox.add(chainBox) - vbox.add(self.chain) - - regexpBox = gtk.HBox() - regexpLabel = gtk.Label(_("Regular expression")) - regexpLabel.set_alignment(0,0.6) - regexpLabel.set_size_request(200, -1) - regexpGroupLabel = gtk.Label(_("Group")) - regexpGroupLabel.set_size_request(1, -1) - reghelp.set_size_request(10, -1) - regexpBox.add(regexpLabel) - regexpBox.add(reghelp) - regexpBox.add(regexpGroupLabel) - vbox.add(regexpBox) - self.reggroup.set_size_request(1,-1); - self.regexp.set_size_request(250,-1); - regexpInputBox = gtk.HBox() - regexpInputBox.add(self.regexp) - regexpInputBox.add(self.reggroup) - vbox.add(regexpInputBox) - - widthBox = gtk.HBox() - widthLabel = gtk.Label(_("Max. width")) - widthLabel.set_alignment(0,0.6) - symbolsLabel = gtk.Label(_("symbols")) - widthLabel.set_size_request(140, -1) - self.widthEdit.set_size_request(50, -1) - symbolsLabel.set_size_request(40,-1) - widthBox.add(widthLabel) - widthBox.add(self.widthEdit) - widthBox.add(symbolsLabel) - vbox.add(widthBox) - - updateBox = gtk.HBox() - updateLabel = gtk.Label(_("Update every")) - updateLabel.set_alignment(0,0.6) - minutesLabel = gtk.Label(_("minutes")) - updateLabel.set_size_request(140, -1) - self.update_interval.set_size_request(50, -1) - minutesLabel.set_size_request(40, -1) - updateBox.add(updateLabel) - updateBox.add(self.update_interval) - updateBox.add(minutesLabel) - vbox.add(updateBox) - - retryBox = gtk.HBox() - retryLabel = gtk.Label(_("Retry pattern")) - retryLabel.set_alignment(0,0.6) - retryLabel.set_size_request(200, -1) - retryhelp.set_size_request(10, -1) - retryBox.add(retryLabel) - retryBox.add(retryhelp) - vbox.add(retryBox) - vbox.add(self.retryEdit) - - argsLabel = gtk.Label(_("Additional ussdquery.py options")) - argsLabel.set_alignment(0,0.6) - vbox.add(argsLabel) - vbox.add(self.args) - - viewBox = gtk.HBox() - viewBox.add(self.fontButton) - viewBox.add(self.textColorButton) - viewBox.add(self.colorButton) - vbox.add(viewBox) - - self.sms_box = gtk.VBox() - self.sms_listener = gtk.CheckButton(_("Enable SMS listener.")) - self.sms_listener.connect("toggled", self.sms_box_changed) - self.sms_listener.set_active(config[15]) - vbox.add (self.sms_listener) - - self.sms_number = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.sms_number.set_text(config[16]) - smsNumberBox = gtk.HBox() - smsNumberLabel = gtk.Label(_("SMS number")) - smsNumberLabel.set_alignment(0,0.6) - smsNumberLabel.set_size_request(100, -1) - self.sms_number.set_size_request(200, -1) - smsNumberBox.add(smsNumberLabel) - smsNumberBox.add(self.sms_number) - self.sms_box.add(smsNumberBox) - - smsRegexpLabel = gtk.Label(_("Regular expression")) - smsRegexpLabel.set_alignment(0,0.6) - self.sms_box.add(smsRegexpLabel) - - self.sms_regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.sms_regexp.set_text(config[17]) - self.sms_box.add(self.sms_regexp) - - self.sms_timeout = hildon.NumberEditor(0, 9999) - self.sms_timeout.set_value(config[18]) - sms_timeout_box = gtk.HBox() - timeoutLabel = gtk.Label(_("Timeout")) - timeoutLabel.set_alignment(0,0.6) - secondsLabel = gtk.Label(_("seconds")) - timeoutLabel.set_size_request(140, -1) - self.sms_timeout.set_size_request(50, -1) - secondsLabel.set_size_request(40, -1) - sms_timeout_box.add(timeoutLabel) - sms_timeout_box.add(self.sms_timeout) - sms_timeout_box.add(secondsLabel) - self.sms_box.add(sms_timeout_box) - - vbox.add(self.sms_box) - - vbox.add(gtk.Label(_("DO NOT CHANGE. Unspecified is what you want."))) - vbox.add(self.language) - - self.show_all() - self.show_box_changed(None) - self.sms_box_changed(None) - self.parent - - #============ Dialog helper functions ============= - def on_show_phelp(self, widget): - 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.")) - dialog.run() - dialog.destroy() - - def on_show_bphelp(self, widget): - 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.")) - dialog.run() - dialog.destroy() - - def on_show_chelp(self, widget): - 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")) - dialog.run() - dialog.destroy() - - def on_show_reghelp(self, widget): - dialog = pHelpDialog(_("Format help"), _("Standard python regexps. Use\n (.+?[\d\,\.]+)\n to delete everything after first number.")) - dialog.run() - dialog.destroy() - - def on_show_retryhelp(self, widget): - 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\"")) - dialog.run() - dialog.destroy() - - def on_show_number_help(self, widget): - 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.")) - dialog.run() - dialog.destroy() - - def on_error_regexp(self, error): - dialog = pHelpDialog(_("Regexp syntax error"), error ) - dialog.run() - dialog.destroy() - - def on_error_ussd_number(self): - dialog = pHelpDialog(_("Incorrect USSD number"), _("USSD number should contain only digits, +, * or #") ) - dialog.run() - dialog.destroy() - - def on_error_retry_pattern(self): - dialog = pHelpDialog(_("Incorrect retry pattern"), _("Retry pattern should contain only numbers, delimited by -") ) - dialog.run() - dialog.destroy() - - def on_show_color_selection (self, event): - colorDialog = gtk.ColorSelectionDialog(_("Choose background color")) - colorDialog.colorsel.set_current_color(self.bg_color) - if colorDialog.run() == gtk.RESPONSE_OK : - self.bg_color = colorDialog.colorsel.get_current_color() - colorDialog.destroy() - - def on_show_text_color_selection (self, event): - colorDialog = gtk.ColorSelectionDialog(_("Choose text color")) - colorDialog.colorsel.set_current_color(self.text_color) - if colorDialog.run() == gtk.RESPONSE_OK : - self.text_color = colorDialog.colorsel.get_current_color() - colorDialog.destroy() - - def on_show_font_selection (self, event): - fontDialog = gtk.FontSelectionDialog(_("Choose a font")) - fontDialog.set_font_name(self.font.to_string()) - - if fontDialog.run() != gtk.RESPONSE_OK : - fontDialog.destroy() - return - - self.font = pango.FontDescription (fontDialog.get_font_name()) - fontDialog.destroy() - - def show_box_changed (self, event): - if self.show_box.get_active(): - self.b_parser.show() - else: - self.b_parser.hide() - - def sms_box_changed (self, event): - if self.sms_listener.get_active(): - self.sms_box.show() - else: - self.sms_box.hide() + def __init__(self, config, bg_color, text_color, id): + gtk.Dialog.__init__(self, _("USSD widget : "+id), None, + gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, + (_("Save").encode("utf-8"), gtk.RESPONSE_OK)) + + self.font = config[8] + self.bg_color = bg_color + self.text_color = text_color + + self.set_size_request(-1, 400) + self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.ussdNumber.set_text(config[0]) + self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.parser.set_text(config[1]) + self.b_parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.b_parser.set_text(config[12]) + + self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.chain.set_text(config[2]) + self.update_interval = hildon.NumberEditor(0, 9999) + self.update_interval.set_value(config[3]) + self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.regexp.set_text(config[4]) + self.widthEdit = hildon.NumberEditor(0, 1000) + self.widthEdit.set_value(config[5]) + self.retryEdit = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.args = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.args.set_text(config[13]) + self.reggroup = hildon.NumberEditor(0, 255) + self.reggroup.set_value(config[14]) + + selector = hildon.TouchSelector(text=True) + for i in ussd_languages_localized: + selector.append_text(i) + self.language = hildon.PickerButton(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_HORIZONTAL) + self.language.set_selector(selector) + self.language.set_active(config[10]) + self.language.set_title(_("USSD reply language")) + self.language.set_size_request(-1, -1) + + self.wname = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.wname.set_text(config[9]) + self.show_box = gtk.CheckButton(_("Enable banner. Parser:")) + self.show_box.connect("toggled", self.show_box_changed) + self.show_box.set_active(config[11]) + + text = "" + for i in config[7]: + if text != "": + text += "-" + text += str(i) + self.retryEdit.set_text(text) + + self.query_at_start = gtk.CheckButton(_("Execute query on start")) + self.query_at_start.set_active(config[6]) + + self.fontButton = gtk.Button(_("Font")) + self.fontButton.connect("clicked", self.on_show_font_selection) + + self.colorButton = gtk.Button(_("Background color")) + self.colorButton.connect("clicked", self.on_show_color_selection) + self.textColorButton = gtk.Button(_("Text color")) + self.textColorButton.connect("clicked", self.on_show_text_color_selection) + + phelp = gtk.Button("?") + phelp.connect("clicked", self.on_show_phelp) + + bphelp = gtk.Button("?") + bphelp.connect("clicked", self.on_show_bphelp) + + chelp = gtk.Button("?") + chelp.connect("clicked", self.on_show_chelp) + + reghelp = gtk.Button("?") + reghelp.connect("clicked", self.on_show_reghelp) + + retryhelp = gtk.Button("?") + retryhelp.connect("clicked", self.on_show_retryhelp) + + numberhelp = gtk.Button("?") + numberhelp.connect("clicked", self.on_show_number_help) + + area = hildon.PannableArea() + self.vbox.add(area) + vbox = gtk.VBox() + area.add_with_viewport(vbox) + + numberBox = gtk.HBox() + numberLabel = gtk.Label(_("USSD number")) + numberLabel.set_alignment(0,0.6) + numberLabel.set_size_request(100, -1) + numberhelp.set_size_request(1, -1) + self.ussdNumber.set_size_request(200, -1) + numberBox.add(numberLabel) + numberBox.add(numberhelp) + numberBox.add(self.ussdNumber) + vbox.add(numberBox) + + vbox.add(self.query_at_start) + + nameBox = gtk.HBox() + nameLabel = gtk.Label(_("Name")) + nameLabel.set_alignment(0,0.6) + nameLabel.set_size_request(100, -1) + self.wname.set_size_request(200, -1) + nameBox.add(nameLabel) + nameBox.add(self.wname) + vbox.add(nameBox) + + parserBox = gtk.HBox() + parserLabel = gtk.Label(_("Parser for widget")) + parserLabel.set_alignment(0,0.6) + parserLabel.set_size_request(200, -1) + phelp.set_size_request(10, -1) + parserBox.add(parserLabel) + parserBox.add(phelp) + vbox.add(parserBox) + vbox.add(self.parser) + + b_parserBox = gtk.HBox() + self.show_box.set_size_request(200, -1) + bphelp.set_size_request(10, -1) + b_parserBox.add(self.show_box) + b_parserBox.add(bphelp) + vbox.add(b_parserBox) + vbox.add(self.b_parser) + + chainBox = gtk.HBox() + chainLabel = gtk.Label(_("Chain")) + chainLabel.set_alignment(0,0.6) + chainLabel.set_size_request(200, -1) + chelp.set_size_request(10, -1) + chainBox.add(chainLabel) + chainBox.add(chelp) + vbox.add(chainBox) + vbox.add(self.chain) + + regexpBox = gtk.HBox() + regexpLabel = gtk.Label(_("Regular expression")) + regexpLabel.set_alignment(0,0.6) + regexpLabel.set_size_request(200, -1) + regexpGroupLabel = gtk.Label(_("Group")) + regexpGroupLabel.set_size_request(1, -1) + reghelp.set_size_request(10, -1) + regexpBox.add(regexpLabel) + regexpBox.add(reghelp) + regexpBox.add(regexpGroupLabel) + vbox.add(regexpBox) + self.reggroup.set_size_request(1,-1); + self.regexp.set_size_request(250,-1); + regexpInputBox = gtk.HBox() + regexpInputBox.add(self.regexp) + regexpInputBox.add(self.reggroup) + vbox.add(regexpInputBox) + + widthBox = gtk.HBox() + widthLabel = gtk.Label(_("Max. width")) + widthLabel.set_alignment(0,0.6) + symbolsLabel = gtk.Label(_("symbols")) + widthLabel.set_size_request(140, -1) + self.widthEdit.set_size_request(50, -1) + symbolsLabel.set_size_request(40,-1) + widthBox.add(widthLabel) + widthBox.add(self.widthEdit) + widthBox.add(symbolsLabel) + vbox.add(widthBox) + + updateBox = gtk.HBox() + updateLabel = gtk.Label(_("Update every")) + updateLabel.set_alignment(0,0.6) + minutesLabel = gtk.Label(_("minutes")) + updateLabel.set_size_request(140, -1) + self.update_interval.set_size_request(50, -1) + minutesLabel.set_size_request(40, -1) + updateBox.add(updateLabel) + updateBox.add(self.update_interval) + updateBox.add(minutesLabel) + vbox.add(updateBox) + + retryBox = gtk.HBox() + retryLabel = gtk.Label(_("Retry pattern")) + retryLabel.set_alignment(0,0.6) + retryLabel.set_size_request(200, -1) + retryhelp.set_size_request(10, -1) + retryBox.add(retryLabel) + retryBox.add(retryhelp) + vbox.add(retryBox) + vbox.add(self.retryEdit) + + argsLabel = gtk.Label(_("Additional ussdquery.py options")) + argsLabel.set_alignment(0,0.6) + vbox.add(argsLabel) + vbox.add(self.args) + + viewBox = gtk.HBox() + viewBox.add(self.fontButton) + viewBox.add(self.textColorButton) + viewBox.add(self.colorButton) + vbox.add(viewBox) + + self.sms_box = gtk.VBox() + self.sms_listener = gtk.CheckButton(_("Enable SMS listener.")) + self.sms_listener.connect("toggled", self.sms_box_changed) + self.sms_listener.set_active(config[15]) + vbox.add (self.sms_listener) + + self.sms_number = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.sms_number.set_text(config[16]) + smsNumberBox = gtk.HBox() + smsNumberLabel = gtk.Label(_("SMS number")) + smsNumberLabel.set_alignment(0,0.6) + smsNumberLabel.set_size_request(100, -1) + self.sms_number.set_size_request(200, -1) + smsNumberBox.add(smsNumberLabel) + smsNumberBox.add(self.sms_number) + self.sms_box.add(smsNumberBox) + + smsRegexpLabel = gtk.Label(_("Regular expression")) + smsRegexpLabel.set_alignment(0,0.6) + self.sms_box.add(smsRegexpLabel) + + self.sms_regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.sms_regexp.set_text(config[17]) + self.sms_box.add(self.sms_regexp) + + self.sms_timeout = hildon.NumberEditor(0, 9999) + self.sms_timeout.set_value(config[18]) + sms_timeout_box = gtk.HBox() + timeoutLabel = gtk.Label(_("Timeout")) + timeoutLabel.set_alignment(0,0.6) + secondsLabel = gtk.Label(_("seconds")) + timeoutLabel.set_size_request(140, -1) + self.sms_timeout.set_size_request(50, -1) + secondsLabel.set_size_request(40, -1) + sms_timeout_box.add(timeoutLabel) + sms_timeout_box.add(self.sms_timeout) + sms_timeout_box.add(secondsLabel) + self.sms_box.add(sms_timeout_box) + + vbox.add(self.sms_box) + + vbox.add(gtk.Label(_("DO NOT CHANGE. Unspecified is what you want."))) + vbox.add(self.language) + + self.show_all() + self.show_box_changed(None) + self.sms_box_changed(None) + self.parent + + #============ Dialog helper functions ============= + def on_show_phelp(self, widget): + 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.")) + dialog.run() + dialog.destroy() + + def on_show_bphelp(self, widget): + 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.")) + dialog.run() + dialog.destroy() + + def on_show_chelp(self, widget): + 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")) + dialog.run() + dialog.destroy() + + def on_show_reghelp(self, widget): + dialog = pHelpDialog(_("Format help"), _("Standard python regexps. Use\n (.+?[\d\,\.]+)\n to delete everything after first number.")) + dialog.run() + dialog.destroy() + + def on_show_retryhelp(self, widget): + 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\"")) + dialog.run() + dialog.destroy() + + def on_show_number_help(self, widget): + 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.")) + dialog.run() + dialog.destroy() + + def on_error_regexp(self, error): + dialog = pHelpDialog(_("Regexp syntax error"), error ) + dialog.run() + dialog.destroy() + + def on_error_ussd_number(self): + dialog = pHelpDialog(_("Incorrect USSD number"), _("USSD number should contain only digits, +, * or #") ) + dialog.run() + dialog.destroy() + + def on_error_retry_pattern(self): + dialog = pHelpDialog(_("Incorrect retry pattern"), _("Retry pattern should contain only numbers, delimited by -") ) + dialog.run() + dialog.destroy() + + def on_show_color_selection (self, event): + colorDialog = gtk.ColorSelectionDialog(_("Choose background color")) + colorDialog.colorsel.set_current_color(self.bg_color) + if colorDialog.run() == gtk.RESPONSE_OK : + self.bg_color = colorDialog.colorsel.get_current_color() + colorDialog.destroy() + + def on_show_text_color_selection (self, event): + colorDialog = gtk.ColorSelectionDialog(_("Choose text color")) + colorDialog.colorsel.set_current_color(self.text_color) + if colorDialog.run() == gtk.RESPONSE_OK : + self.text_color = colorDialog.colorsel.get_current_color() + colorDialog.destroy() + + def on_show_font_selection (self, event): + fontDialog = gtk.FontSelectionDialog(_("Choose a font")) + fontDialog.set_font_name(self.font.to_string()) + + if fontDialog.run() != gtk.RESPONSE_OK : + fontDialog.destroy() + return + + self.font = pango.FontDescription (fontDialog.get_font_name()) + fontDialog.destroy() + + def show_box_changed (self, event): + if self.show_box.get_active(): + self.b_parser.show() + else: + self.b_parser.hide() + + def sms_box_changed (self, event): + if self.sms_listener.get_active(): + self.sms_box.show() + else: + self.sms_box.hide() def smart_split_string (str, reply1, reply2, reres1 = None, reres2 = None) : - word = "" - result = [] - # Is simbol backslashed? - bs = 0 - # Quotes: 1 - ", 2 - ', 0 - no quotes - qs = 0 - # Read out number - num = -1 - # Current substitution simbol - subst = '' - - for i in range(len(str)) : - if num>= 0: - if str[i] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] : - num *= 10 - num += int(str[i]) - continue - else: - if subst == '&': - if reres2 != None and num != 0: - word += reres2.group(num) - else: - word += reply2 - else: - if reres1 != None and num != 0: - word += reres1.group(num) - else: - word += reply1 - ws = 0 - num = -1 - subst = '' - # Delete backslash if it delimites usual numbers from % or & - if str[i] == '\\' and i < len(str)-1 and str[i+1] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] : - continue - if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) : - qs = 0 - elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") : - if str[i] == '"': - qs = 1 - else : - qs = 2 - elif bs == 0 and str[i] == '\\' : - bs = 1 - elif bs == 0 and (str[i] == '%' or str[i] == '&') : - subst = str[i] - num = 0 - else : - if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" : - word += "\\" - if qs == 0 and (str[i] == " " or str[i] == "\t") : - if word != "" : - result.append(word) - word = "" - else : - word += str[i] - bs = 0 - - if subst == '&': - if reres2 != None and num != 0 and num != -1: - word += reres2.group(num) - else: - word += reply2 - elif subst == '%': - if reres1 != None and num != 0 and num != -1: - word += reres1.group(num) - else: - word += reply1 - if word != "" : - result.append(word) - return result + word = "" + result = [] + # Is simbol backslashed? + bs = 0 + # Quotes: 1 - ", 2 - ', 0 - no quotes + qs = 0 + # Read out number + num = -1 + # Current substitution simbol + subst = '' + + for i in range(len(str)) : + if num>= 0: + if str[i] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] : + num *= 10 + num += int(str[i]) + continue + else: + if subst == '&': + if reres2 != None and num != 0: + word += reres2.group(num) + else: + word += reply2 + else: + if reres1 != None and num != 0: + word += reres1.group(num) + else: + word += reply1 + ws = 0 + num = -1 + subst = '' + # Delete backslash if it delimites usual numbers from % or & + if str[i] == '\\' and i < len(str)-1 and str[i+1] in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] : + continue + if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) : + qs = 0 + elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") : + if str[i] == '"': + qs = 1 + else : + qs = 2 + elif bs == 0 and str[i] == '\\' : + bs = 1 + elif bs == 0 and (str[i] == '%' or str[i] == '&') : + subst = str[i] + num = 0 + else : + if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" : + word += "\\" + if qs == 0 and (str[i] == " " or str[i] == "\t") : + if word != "" : + result.append(word) + word = "" + else : + word += str[i] + bs = 0 + + if subst == '&': + if reres2 != None and num != 0 and num != -1: + word += reres2.group(num) + else: + word += reply2 + elif subst == '%': + if reres1 != None and num != 0 and num != -1: + word += reres1.group(num) + else: + word += reply1 + if word != "" : + result.append(word) + return result def check_regexp(regexp): - try : - re.compile( regexp ) - except Exception, e: - return str(e) - return False + try : + re.compile( regexp ) + except Exception, e: + return str(e) + return False def check_number(number): - for s in number : - if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#", " "]) : - return False - return True + for s in number : + if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#", " "]) : + return False + return True #=============== The widget itself ================ def get_color(logicalcolorname): - settings = gtk.settings_get_default() - color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button) - return color_style.lookup_color(logicalcolorname) + settings = gtk.settings_get_default() + color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button) + return color_style.lookup_color(logicalcolorname) class UssdWidgetPlugin(hildondesktop.HomePluginItem): - def __init__(self): - hildondesktop.HomePluginItem.__init__(self) - - self.processing = 0 - self.bg_color=gtk.gdk.color_parse('#000000') - self.text_color=gtk.gdk.color_parse('#ffffff') - self.error = 0 - self.timeout_version = 0 - - colormap = self.get_screen().get_rgba_colormap() - self.set_colormap (colormap) - - self.controller = USSD_Controller(self) - + def __init__(self): + hildondesktop.HomePluginItem.__init__(self) + + self.processing = 0 + self.bg_color=gtk.gdk.color_parse('#000000') + self.text_color=gtk.gdk.color_parse('#ffffff') + self.error = 0 + self.timeout_version = 0 + + colormap = self.get_screen().get_rgba_colormap() + self.set_colormap (colormap) + + self.controller = USSD_Controller(self) + # TODO Click event would be better - self.connect("button-press-event", self.controller.ussd_renew) - - self.vbox = gtk.HBox() - self.add(self.vbox) - - self.set_settings(True) - self.connect("show-settings", self.controller.on_show_settings) - self.label = gtk.Label("") - - self.vbox.add(self.label) - self.vbox.set_child_packing(self.label, False, False, 0, gtk.PACK_START) - self.label.set_padding(15, 10) - self.label.set_size_request(-1,-1) - self.set_size_request(-1,-1) - self.label.set_line_wrap (True) - - self.vbox.show_all() - - DBusGMainLoop(set_as_default=True) - bus = dbus.SystemBus() - 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') - 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') - signal = bus.add_signal_receiver(self.ussd_renew, path='/su/kibergus/ussd_widget', dbus_interface='su.kibergus.ussd_widget', signal_name='renew') - - def do_show(self): - config = self.controller.read_config(self.get_applet_id()) - self.set_width(config[5]) - self.set_text(config[9]) - if config[6]: - self.controller.ussd_renew(self, None) - - self.label.modify_font(config[8]) - self.controller.reset_timed_renew() - hildondesktop.HomePluginItem.do_show(self) - - def error_return (self): - if self.error == 1 and self.processing == 0: - self.set_text(self.text) - return False - - # showfor = - # -1 - This is a permanent text message - # 0 - This is service message, but it shouldn't be hidden automatically - # >0 - This is service message, show permament message after showfor milliseconds - def set_text(self, text, showfor=-1): - if showfor > 0 : - # Show previous text after 5 seconds - gobject.timeout_add (showfor, self.error_return) - else : - if showfor == -1 : - self.text = text - - config = self.controller.get_config() - self.label.set_text(text) - - def get_text(self): - return self.text - - def set_width(self, width): - if width != 0: - self.label.set_width_chars (width) - else : - self.label.set_width_chars(-1) - - def ussd_renew(self, id): - if id == self.get_applet_id(): - self.controller.ussd_renew(self, None) - - def set_bg_color_text(self, id, color): - if id == self.get_applet_id(): - try : - self.set_bg_color(gtk.gdk.color_parse(color.strip())) - except: - print _("Unable to parse colour specification") - self.queue_draw() - - def set_text_color_text(self, id, color): - if id == self.get_applet_id(): - try: - self.set_text_color(gtk.gdk.color_parse(color.strip())) - except: - print _("Unable to parse colour specification") - self.queue_draw() - - def set_bg_color(self, color): - self.bg_color = color - - def get_bg_color(self): - return self.bg_color - - def set_text_color(self, color): - self.label.modify_fg(gtk.STATE_NORMAL, color) - self.text_color = color - - def get_text_color(self): - return self.text_color - - def _expose(self, event): - cr = self.window.cairo_create() - - # draw rounded rect - width, height = self.label.allocation[2], self.label.allocation[3] - - #/* a custom shape, that could be wrapped in a function */ - x0 = 0 #/*< parameters like cairo_rectangle */ - y0 = 0 - - radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */ - - x1 = x0 + width - y1 = y0 + height - - cr.move_to (x0, y0 + radius) - cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14) - cr.line_to (x1 - radius, y0) - cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0) - cr.line_to (x1 , y1 - radius) - cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14) - cr.line_to (x0 + radius, y1) - cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14) - - cr.close_path () - - fg_color = get_color("ActiveTextColor") - - if self.processing : - bg_color=fg_color - else : - bg_color=self.bg_color - - cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7) - cr.fill_preserve () - - if self.error : - cr.set_source_rgba (1.0, 0.0, 0.0, 0.5) - else : - cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7) - cr.stroke () - - def do_expose_event(self, event): - self.chain(event) - self._expose (event) - self.vbox.do_expose_event (self, event) + self.connect("button-press-event", self.controller.ussd_renew) + + self.vbox = gtk.HBox() + self.add(self.vbox) + + self.set_settings(True) + self.connect("show-settings", self.controller.on_show_settings) + self.label = gtk.Label("") + + self.vbox.add(self.label) + self.vbox.set_child_packing(self.label, False, False, 0, gtk.PACK_START) + self.label.set_padding(15, 10) + self.label.set_size_request(-1,-1) + self.set_size_request(-1,-1) + self.label.set_line_wrap (True) + + self.vbox.show_all() + + DBusGMainLoop(set_as_default=True) + bus = dbus.SystemBus() + 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') + 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') + signal = bus.add_signal_receiver(self.ussd_renew, path='/su/kibergus/ussd_widget', dbus_interface='su.kibergus.ussd_widget', signal_name='renew') + + def do_show(self): + config = self.controller.read_config(self.get_applet_id()) + self.set_width(config[5]) + self.set_text(config[9]) + if config[6]: + self.controller.ussd_renew(self, None) + + self.label.modify_font(config[8]) + self.controller.reset_timed_renew() + hildondesktop.HomePluginItem.do_show(self) + + def error_return (self): + if self.error == 1 and self.processing == 0: + self.set_text(self.text) + return False + + # showfor = + # -1 - This is a permanent text message + # 0 - This is service message, but it shouldn't be hidden automatically + # >0 - This is service message, show permament message after showfor milliseconds + def set_text(self, text, showfor=-1): + if showfor > 0 : + # Show previous text after 5 seconds + gobject.timeout_add (showfor, self.error_return) + else : + if showfor == -1 : + self.text = text + + config = self.controller.get_config() + self.label.set_text(text) + + def get_text(self): + return self.text + + def set_width(self, width): + if width != 0: + self.label.set_width_chars (width) + else : + self.label.set_width_chars(-1) + + def ussd_renew(self, id): + if id == self.get_applet_id(): + self.controller.ussd_renew(self, None) + + def set_bg_color_text(self, id, color): + if id == self.get_applet_id(): + try : + self.set_bg_color(gtk.gdk.color_parse(color.strip())) + except: + print >> log, _("Unable to parse colour specification") + self.queue_draw() + + def set_text_color_text(self, id, color): + if id == self.get_applet_id(): + try: + self.set_text_color(gtk.gdk.color_parse(color.strip())) + except: + print >> log, _("Unable to parse colour specification") + self.queue_draw() + + def set_bg_color(self, color): + self.bg_color = color + + def get_bg_color(self): + return self.bg_color + + def set_text_color(self, color): + self.label.modify_fg(gtk.STATE_NORMAL, color) + self.text_color = color + + def get_text_color(self): + return self.text_color + + def _expose(self, event): + cr = self.window.cairo_create() + + # draw rounded rect + width, height = self.label.allocation[2], self.label.allocation[3] + + #/* a custom shape, that could be wrapped in a function */ + x0 = 0 #/*< parameters like cairo_rectangle */ + y0 = 0 + + radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */ + + x1 = x0 + width + y1 = y0 + height + + cr.move_to (x0, y0 + radius) + cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14) + cr.line_to (x1 - radius, y0) + cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0) + cr.line_to (x1 , y1 - radius) + cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14) + cr.line_to (x0 + radius, y1) + cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14) + + cr.close_path () + + fg_color = get_color("ActiveTextColor") + + if self.processing : + bg_color=fg_color + else : + bg_color=self.bg_color + + cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7) + cr.fill_preserve () + + if self.error : + cr.set_source_rgba (1.0, 0.0, 0.0, 0.5) + else : + cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7) + cr.stroke () + + def do_expose_event(self, event): + self.chain(event) + self._expose (event) + self.vbox.do_expose_event (self, event) hd_plugin_type = UssdWidgetPlugin # The code below is just for testing purposes. # It allows to run the widget as a standalone process. if __name__ == "__main__": - plugin_id = "ussd-widget.console" - if len(sys.argv) == 2: - try: - plugin_id = "ussd-widget.desktop-"+str(int(sys.argv[1])) - except: - print "Plugin id must be integer" - sys.exit(-1) - - import gobject - gobject.type_register(hd_plugin_type) - obj = gobject.new(hd_plugin_type, plugin_id=plugin_id) - obj.show_all() - gtk.main() + plugin_id = "ussd-widget.console" + if len(sys.argv) == 2: + try: + plugin_id = "ussd-widget.desktop-"+str(int(sys.argv[1])) + except: + print >> log, "Plugin id must be integer" + sys.exit(-1) + + import gobject + gobject.type_register(hd_plugin_type) + obj = gobject.new(hd_plugin_type, plugin_id=plugin_id) + obj.show_all() + gtk.main() -- 1.7.9.5