New version
[ussd-widget] / ussd-widget / src / usr / lib / hildon-desktop / ussd-widget.py
index 4854980..2b1ab82 100755 (executable)
@@ -23,16 +23,17 @@ except IOError:
        _ = 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")]
 
 # TODO Cutt off too long messages and show them in separate dialog
 # how TODO widget vertical minimum size policy
-# TODO interface for queryng from scripts. For example query from one widget can change color of another widget
+# TODO interface for queryng from scripts. For example query from one widget can change color of another widget 
 
 class USSD_Controller:
        def __init__( self, widget ) :
                self.widget = widget
-               # number, parser, chain, interval, regexp, width, execute_at_start, retry pattern, font, [name, always show], language 
-               self.default_config = ["", "", "", 0, "", 0, True, [], pango.FontDescription("Nokia Sans 18"), [_("Click to update"), False], 15]
+               # number, parser, chain, interval, regexp, width, execute_at_start, retry pattern, font, name, language, show_message_box, message_box_parser, additional arguments, regexp group 
+               self.default_config = ["", "", "", 0, "", 0, True, [], pango.FontDescription("Nokia Sans 18"), _("Click to update"), 15, False, "", "", 1]
                self.config = self.default_config
                self.timeout_version = 0
                self.retry_version = 0
@@ -63,7 +64,8 @@ class USSD_Controller:
                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\n", "parser="+self.config[1], "\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"])
@@ -81,9 +83,11 @@ class USSD_Controller:
                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][0], "\n"])
-               fconfig.writelines(["#Always show widget name\n", "show_name="+str(self.config[9][1]), "\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="+self.config[14], "\n"])
                fconfig.close()
 
                fcntl.flock(lockf,fcntl.LOCK_UN)
@@ -122,6 +126,8 @@ class USSD_Controller:
                                        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" :
@@ -181,12 +187,12 @@ class USSD_Controller:
                                                error = True
                                                print _("Error reading config on line %(line)d. Expected color definition.")%{"line":i}
                                elif line[0] == "name" :
-                                       self.config[9][0] = line[1].strip()
-                               elif line[0] == "show_name" :
+                                       self.config[9] = line[1].strip()
+                               elif line[0] == "show_box" :
                                        if line[1].strip() == "True" :
-                                               self.config[9][1] = True
+                                               self.config[11] = True
                                        else :
-                                               self.config[9][1] = False
+                                               self.config[11] = False
                                elif line[0] == "language" :
                                        try:
                                                if int(line[1].strip()) >=0 and int(line[1].strip()) < len(ussd_languages):
@@ -197,6 +203,15 @@ class USSD_Controller:
                                        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
                                else :
                                        error = True
                                        print _("Error reading config on line %(line)d. Unexpected variable: ")%{"line":i}+line[0]
@@ -264,8 +279,12 @@ class USSD_Controller:
                        dialog.query_at_start.get_active(),
                        retry,
                        dialog.font,
-                       [dialog.wname.get_text(), dialog.show_name.get_active()],
-                       dialog.language.get_active()
+                       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()
                ]
 
                widget.set_bg_color(dialog.bg_color)
@@ -310,7 +329,7 @@ class USSD_Controller:
        def call_external_script( self, ussd_code, language ):
                self.cb_ready = 0
                self.cb_reply = "";
-               p = Popen(['/usr/bin/ussdquery.py', ussd_code, ussd_languages[language]], stdout=PIPE)
+               p = Popen(['/usr/bin/ussdquery.py', ussd_code, "-l", ussd_languages[language]] + smart_split_string(self.config[13],"%"), stdout=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):
@@ -338,23 +357,43 @@ class USSD_Controller:
                                self.retry_state += 1
                else :
                        self.widget.error = 0
-                       # Pass to parser
-                       if self.config[1] != "":
-                               p = Popen(smart_split_string(self.config[1], reply), stdout=PIPE)
-                               reply = p.communicate(reply+"\n")[0].strip()
-                       # Pass to chain
-                       if self.config[2] != "":
-                               p = Popen(smart_split_string(self.config[2], reply))
                        # Apply regexp
                        if self.config[4] != "":
                                try :
-                                       r = re.match( self.config[4], reply ).group( 1 )
+                                       reply = re.search( self.config[4], reply, re.MULTILINE | re.UNICODE ).group( self.config[14] )
                                except Exception, e:
-                                       r = _("Regexp Error: ") + str( e ) + "\n" + reply
-
-                               if r :
-                                       reply = r
-                       self.widget.set_text(reply)
+                                       self.widget.error = 1
+                                       reply = _("Regexp Error: ") + str( e ) + "\n" + reply
+                       w_reply = b_reply = reply
+                       if self.widget.error == 0:
+                               # Pass to box parser
+                               if self.config[12] != "" and self.config[11]:
+                                       try:
+                                               p = Popen(smart_split_string(self.config[12], reply), stdout=PIPE)
+                                               b_reply = p.communicate()[0].strip()
+                                       except Exception, e:
+                                               print _("Couldn't exec banner parser:")+str(e)
+                                               self.widget.error = 1
+                               # Pass to widget parser
+                               if self.config[1] != "":
+                                       try:
+                                               p = Popen(smart_split_string(self.config[1], reply), stdout=PIPE)
+                                               w_reply = p.communicate()[0].strip()
+                                       except Exception, e:
+                                               print _("Couldn't exec widget parser:")+str(e)
+                                               self.widget.error = 1
+                               # Pass to chain
+                               if self.config[2] != "":
+                                       try:
+                                               p = Popen(smart_split_string(self.config[2], reply))
+                                       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 timed_renew(self, version):
@@ -400,6 +439,9 @@ class UssdConfigDialog(gtk.Dialog):
                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)
@@ -409,11 +451,13 @@ class UssdConfigDialog(gtk.Dialog):
                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.hildon_touch_selector_new_text()
                selector = hildon.TouchSelector(text=True)
-               for i in ussd_languages:
+               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)
@@ -422,9 +466,9 @@ class UssdConfigDialog(gtk.Dialog):
                self.language.set_size_request(-1, -1)
 
                self.wname = hildon.Entry(gtk.HILDON_SIZE_AUTO)
-               self.wname.set_text(config[9][0])
-               self.show_name = gtk.CheckButton(_("Always show name"))
-               self.show_name.set_active(config[9][1])
+               self.wname.set_text(config[9])
+               self.show_box = gtk.CheckButton(_("Enable banner. Parser:"))
+               self.show_box.set_active(config[11])
 
                text = ""
                for i in config[7]:
@@ -446,6 +490,9 @@ class UssdConfigDialog(gtk.Dialog):
                
                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)
@@ -455,6 +502,9 @@ class UssdConfigDialog(gtk.Dialog):
 
                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)
@@ -463,37 +513,47 @@ class UssdConfigDialog(gtk.Dialog):
                
                numberBox = gtk.HBox()
                numberLabel = gtk.Label(_("USSD number"))
-               numberLabel.set_alignment(0,0)
+               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.language)
-
                vbox.add(self.query_at_start)
 
                nameBox = gtk.HBox()
-               self.show_name.set_size_request(100, -1)
-               self.wname.set_size_request(100, -1)
-               nameBox.add(self.show_name)
+               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"))
-               parserLabel.set_alignment(0,0)
+               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)
+               chainLabel.set_alignment(0,0.6)
                chainLabel.set_size_request(200, -1)
                chelp.set_size_request(10, -1)
                chainBox.add(chainLabel)
@@ -502,18 +562,26 @@ class UssdConfigDialog(gtk.Dialog):
                vbox.add(self.chain)
 
                regexpBox = gtk.HBox()
-               regexpLabel = gtk.Label(_("RegExp"))
-               regexpLabel.set_alignment(0,0)
+               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)
-               vbox.add(self.regexp)           
+               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)
+               widthLabel.set_alignment(0,0.6)
                symbolsLabel = gtk.Label(_("symbols"))
                widthLabel.set_size_request(140, -1)
                self.widthEdit.set_size_request(50, -1)
@@ -525,7 +593,7 @@ class UssdConfigDialog(gtk.Dialog):
 
                updateBox = gtk.HBox()
                updateLabel = gtk.Label(_("Update every"))
-               updateLabel.set_alignment(0,0)
+               updateLabel.set_alignment(0,0.6)
                minutesLabel = gtk.Label(_("minutes"))
                updateLabel.set_size_request(140, -1)
                self.update_interval.set_size_request(50, -1)
@@ -537,7 +605,7 @@ class UssdConfigDialog(gtk.Dialog):
 
                retryBox = gtk.HBox()
                retryLabel = gtk.Label(_("Retry pattern"))
-               retryLabel.set_alignment(0,0)
+               retryLabel.set_alignment(0,0.6)
                retryLabel.set_size_request(200, -1)
                retryhelp.set_size_request(10, -1)
                retryBox.add(retryLabel)
@@ -545,21 +613,34 @@ class UssdConfigDialog(gtk.Dialog):
                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)
+               
+               vbox.add(gtk.Label(_("DO NOT CHANGE. Unspecified is what you want.")))
+               vbox.add(self.language)
 
                self.show_all()
                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.\n       Format:\n% would be replaced by reply\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility"))
+               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\\ 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\\ 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\\ invalidates special meaning of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility"))
                dialog.run()
@@ -575,6 +656,11 @@ class UssdConfigDialog(gtk.Dialog):
                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()
@@ -658,7 +744,7 @@ def check_regexp(regexp):
 
 def check_number(number):
        for s in number :
-               if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#"]) :
+               if not (s in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "*", "#", " "]) :
                        return False
        return True
 
@@ -706,10 +792,11 @@ class UssdWidgetPlugin(hildondesktop.HomePluginItem):
        def do_show(self):
                config = self.controller.read_config(self.get_applet_id())
                self.set_width(config[5])
-               self.set_text("")               
+               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)
        
@@ -731,8 +818,6 @@ class UssdWidgetPlugin(hildondesktop.HomePluginItem):
                                self.text = text
                
                config = self.controller.get_config()
-               if config[9][1] or text == "":
-                       text = config[9][0]+text
                self.label.set_text(text)
 
        def get_text(self):