-#!/usr/bin/python
+#!/usr/bin/python2.5
+
+
+"""
+Grandcentral Dialer
+Python front-end to a wget script to use grandcentral.com to place outbound VOIP calls.
+(C) 2008 Mark Bergman
+bergman@merctech.com
+"""
-# Grandcentral Dialer
-# Python front-end to a wget script to use grandcentral.com to place outbound VOIP calls.
-# (C) 2008 Mark Bergman
-# bergman@merctech.com
import sys
+import gc
import os
+import threading
import time
import re
-try:
- import pygtk
- pygtk.require("2.0")
-except:
- pass
-try:
- import gtk
- import gtk.glade
-except:
- sys.exit(1)
+import warnings
-histfile=os.path.expanduser("~")
-histfile=os.path.join(histfile,".gcdialerhist") # Use the native OS file separator
-liststore = gtk.ListStore(str)
+import gobject
+import gtk
+import gtk.glade
-class GCDialer:
- _wgetOKstrRe = re.compile("This may take a few seconds", re.M) # string from Grandcentral.com on successful dial
- _validateRe = re.compile("^[0-9]{7,}$")
+try:
+ import hildon
+except ImportError:
+ hildon = None
- _wgetoutput = "/tmp/gc_dialer.output" # results from wget command
- _cookiefile = os.path.join(os.path.expanduser("~"),".mozilla/microb/cookies.txt") # file with browser cookies
- _wgetcmd = "wget -nv -O %s --load-cookie=\"%s\" --referer=http://www.grandcentral.com/mobile/messages http://www.grandcentral.com/mobile/calls/click_to_call?destno=%s"
+try:
+ import osso
+ try:
+ import abook
+ import evolution.ebook as evobook
+ except ImportError:
+ abook = None
+ evobook = None
+except ImportError:
+ osso = None
- def __init__(self):
- self._msg = ""
- if ( os.path.isfile(GCDialer._cookiefile) == False ) :
- self._msg = 'Error: Failed to locate a file with saved browser cookies at \"' + cookiefile + '\".\n\tPlease use the web browser on your tablet to connect to www.grandcentral.com and then re-run Grandcentral Dialer.'
+try:
+ import conic
+except ImportError:
+ conic = None
- def validate(self,number):
- return GCDialer._validateRe.match(number) != None
+try:
+ import doctest
+ import optparse
+except ImportError:
+ doctest = None
+ optparse = None
- def dial(self,number):
- self._msg = ""
- if self.validate(number) == False:
- self._msg = "Invalid number format %s" % (number)
- return False
+from gcbackend import GCDialer
- # Remove any existing output file...
- if os.path.isfile(GCDialer._wgetoutput) :
- os.unlink(GCDialer._wgetoutput)
- child_stdout, child_stdin, child_stderr = os.popen3(GCDialer._wgetcmd % (GCDialer._wgetoutput, GCDialer._cookiefile, number))
- stderr=child_stderr.read()
+import socket
- child_stdout.close()
- child_stderr.close()
- child_stdin.close()
- try:
- wgetresults = open(GCDialer._wgetoutput, 'r' )
- except IOError:
- self._msg = 'IOError: No /tmp/gc_dialer.output file...dial attempt failed\n\tThis probably means that there is no active internet connection, or that\nthe site www.grandcentral.com is inacessible.'
- return False
-
- data = wgetresults.read()
- wgetresults.close()
+socket.setdefaulttimeout(5)
- if GCDialer._wgetOKstrRe.search(data) != None:
- return True
- else:
- self._msg = 'Error: Failed to login to www.grandcentral.com.\n\tThis probably means that there is no saved cookie for that site.\n\tPlease use the web browser on your tablet to connect to www.grandcentral.com and then re-run Grandcentral Dialer.'
- return False
-
-
-def load_history_list(histfile,liststore):
- # read the history list, load it into the liststore variable for later
- # assignment to the combobox menu
-
- # clear out existing entries
- dialhist = []
- liststore.clear()
- if os.path.isfile(histfile) :
- histFH = open(histfile,"r")
- for line in histFH.readlines() :
- fields = line.split() # split the input lines on whitespace
- number=fields[0] #...save only the first field (the phone number)
- search4num=re.compile('^' + number + '$')
- newnumber=True # set a flag that the current phone number is not on the history menu
- for num in dialhist :
- if re.match(search4num,num):
- # the number is already in the drop-down menu list...set the
- # flag and bail out
- newnumber = False
- break
- if newnumber == True :
- dialhist.append(number) # append the number to the history list
-
- histlen=len(dialhist)
- if histlen > 10 :
- dialhist=dialhist[histlen - 10:histlen] # keep only the last 10 entries
- dialhist.reverse() # reverse the list, so that the most recent entry is now first
-
- # Now, load the liststore with the entries, for later assignment to the Gtk.combobox menu
- for entry in dialhist :
- entry=makepretty(entry)
- liststore.append([entry])
- # else :
- # print "The history file " + histfile + " does not exist"
def makeugly(prettynumber):
- # function to take a phone number and strip out all non-numeric
- # characters
- uglynumber=re.sub('\D','',prettynumber)
+ """
+ function to take a phone number and strip out all non-numeric
+ characters
+
+ >>> makeugly("+012-(345)-678-90")
+ '01234567890'
+ """
+ uglynumber = re.sub('\D', '', prettynumber)
return uglynumber
+
def makepretty(phonenumber):
- # Function to take a phone number and return the pretty version
- # pretty numbers:
- # if phonenumber begins with 0:
- # ...-(...)-...-....
- # else
- # if phonenumber is 13 digits:
- # (...)-...-....
- # else if phonenumber is 10 digits:
- # ...-....
- if len(phonenumber) < 3 :
+ """
+ Function to take a phone number and return the pretty version
+ pretty numbers:
+ if phonenumber begins with 0:
+ ...-(...)-...-....
+ if phonenumber begins with 1: ( for gizmo callback numbers )
+ 1 (...)-...-....
+ if phonenumber is 13 digits:
+ (...)-...-....
+ if phonenumber is 10 digits:
+ ...-....
+ >>> makepretty("12")
+ '12'
+ >>> makepretty("1234567")
+ '123-4567'
+ >>> makepretty("2345678901")
+ '(234)-567-8901'
+ >>> makepretty("12345678901")
+ '1 (234)-567-8901'
+ >>> makepretty("01234567890")
+ '+012-(345)-678-90'
+ """
+ if phonenumber is None:
+ return ""
+
+ if len(phonenumber) < 3:
return phonenumber
- if phonenumber[0] == "0" :
- if len(phonenumber) <=3:
- prettynumber = "+" + phonenumber[0:3]
- elif len(phonenumber) <=6:
- prettynumber = "+" + phonenumber[0:3] + "-(" + phonenumber[3:6] + ")"
- elif len(phonenumber) <=9:
- prettynumber = "+" + phonenumber[0:3] + "-(" + phonenumber[3:6] + ")-" + phonenumber[6:9]
- else:
- prettynumber = "+" + phonenumber[0:3] + "-(" + phonenumber[3:6] + ")-" + phonenumber[6:9] + "-" + phonenumber[9:]
- return prettynumber
- elif len(phonenumber) <= 7 :
- prettynumber = phonenumber[0:3] + "-" + phonenumber[3:]
- elif len(phonenumber) > 7 :
- prettynumber = "(" + phonenumber[0:3] + ")-" + phonenumber[3:6] + "-" + phonenumber[6:]
+ if phonenumber[0] == "0":
+ prettynumber = ""
+ prettynumber += "+%s" % phonenumber[0:3]
+ if 3 < len(phonenumber):
+ prettynumber += "-(%s)" % phonenumber[3:6]
+ if 6 < len(phonenumber):
+ prettynumber += "-%s" % phonenumber[6:9]
+ if 9 < len(phonenumber):
+ prettynumber += "-%s" % phonenumber[9:]
+ return prettynumber
+ elif len(phonenumber) <= 7:
+ prettynumber = "%s-%s" % (phonenumber[0:3], phonenumber[3:])
+ elif len(phonenumber) > 8 and phonenumber[0] == "1":
+ prettynumber = "1 (%s)-%s-%s" %(phonenumber[1:4], phonenumber[4:7], phonenumber[7:])
+ elif len(phonenumber) > 7:
+ prettynumber = "(%s)-%s-%s" % (phonenumber[0:3], phonenumber[3:6], phonenumber[6:])
return prettynumber
-class Dialpad:
- phonenumber = ""
+class Dialpad(object):
+
+ __app_name__ = "gc_dialer"
+ __version__ = "0.7.0"
+ __app_magic__ = 0xdeadbeef
+
+ _glade_files = [
+ './gc_dialer.glade',
+ '../lib/gc_dialer.glade',
+ '/usr/local/lib/gc_dialer.glade',
+ ]
def __init__(self):
- if os.path.isfile("/usr/local/lib/gc_dialer.glade") :
- self.gladefile = "/usr/local/lib/gc_dialer.glade"
- elif os.path.isfile("./gc_dialer.glade") :
- self.gladefile = "./gc_dialer.glade"
+ self.phonenumber = ""
+ self.prettynumber = ""
+ self.areacode = "518"
+ self.clipboard = gtk.clipboard_get()
+ self.recentmodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.recentviewselection = None
+ self.callbackNeedsSetup = True
+ self.recenttime = 0.0
+
+ for path in Dialpad._glade_files:
+ if os.path.isfile(path):
+ self.wTree = gtk.glade.XML(path)
+ break
+ else:
+ self.ErrPopUp("Cannot find gc_dialer.glade")
+ gtk.main_quit()
+ return
- self.gcd = GCDialer()
- if self.gcd._msg != "":
- self.ErrPopUp(self.gcd._msg)
- sys.exit(1)
+ self.wTree.get_widget("about_title").set_label(self.wTree.get_widget("about_title").get_label()+"\nVersion "+Dialpad.__version__)
- self.wTree = gtk.glade.XML(self.gladefile)
- self.window = self.wTree.get_widget("Dialpad")
- if (self.window):
- self.window.connect("destroy", gtk.main_quit)
#Get the buffer associated with the number display
self.numberdisplay = self.wTree.get_widget("numberdisplay")
- self.dialer_history = self.wTree.get_widget("dialer_history")
+ self.setNumber("")
+ self.notebook = self.wTree.get_widget("notebook")
- # Load the liststore array with the numbers from the history file
- load_history_list(histfile,liststore)
- # load the dropdown menu with the numbers from the dial history
- self.dialer_history.set_model(liststore)
- cell = gtk.CellRendererText()
- self.dialer_history.pack_start(cell, True)
- self.dialer_history.set_active(-1)
- self.dialer_history.set_attributes(cell, text=0)
+ self.window = self.wTree.get_widget("Dialpad")
+
+ global hildon
+ self.app = None
+ if hildon is not None and isinstance(self.window, gtk.Window):
+ warnings.warn("Hildon installed but glade file not updated to work with hildon", UserWarning, 2)
+ hildon = None
+ elif hildon is not None:
+ self.app = hildon.Program()
+ self.window.set_title("Keypad")
+ self.app.add_window(self.window)
+ self.wTree.get_widget("callbackcombo").get_child().set_property('hildon-input-mode', (1 << 4))
+ self.wTree.get_widget("usernameentry").set_property('hildon-input-mode', 7)
+ self.wTree.get_widget("passwordentry").set_property('hildon-input-mode', 7|(1 << 29))
+ else:
+ warnings.warn("No Hildon", UserWarning, 2)
+
+ self.osso = None
+ self.ebook = None
+ if osso is not None:
+ self.osso = osso.Context(__name__, Dialpad.__version__, False)
+ device = osso.DeviceState(self.osso)
+ device.set_device_state_callback(self.on_device_state_change, 0)
+ if abook is not None and evobook is not None:
+ abook.init_with_name(__name__, self.osso)
+ self.ebook = evo.open_addressbook("default")
+ else:
+ warnings.warn("No abook and No evolution address book support", UserWarning, 2)
+ else:
+ warnings.warn("No OSSO", UserWarning, 2)
- self.about_dialog = None
- self.error_dialog = None
+ self.connection = None
+ if conic is not None:
+ self.connection = conic.Connection()
+ self.connection.connect("connection-event", on_connection_change, Dialpad.__app_magic__)
+ self.connection.request_connection(conic.CONNECT_FLAG_NONE)
- dic = {
- # Routine for processing signal from the combobox (ie., when the
- # user selects an entry from the dropdown history
- "on_dialer_history_changed" : self.on_dialer_history_changed,
+ if self.window:
+ self.window.connect("destroy", gtk.main_quit)
+ self.window.show_all()
+ callbackMapping = {
# Process signals from buttons
- "on_number_clicked" : self.on_number_clicked,
- "on_Clear_clicked" : self.on_Clear_clicked,
- "on_Dial_clicked" : self.on_Dial_clicked,
- "on_Backspace_clicked" : self.Backspace,
- "on_Cancel_clicked" : self.on_Cancel_clicked,
- "on_About_clicked" : self.on_About_clicked}
- self.wTree.signal_autoconnect(dic)
-
- def ErrPopUp(self,msg):
- error_dialog = gtk.MessageDialog(None,0,gtk.MESSAGE_ERROR,gtk.BUTTONS_CLOSE,msg)
+ "on_digit_clicked" : self.on_digit_clicked,
+ "on_dial_clicked" : self.on_dial_clicked,
+ "on_loginbutton_clicked" : self.on_loginbutton_clicked,
+ "on_loginclose_clicked" : self.on_loginclose_clicked,
+ "on_clearcookies_clicked" : self.on_clearcookies_clicked,
+ "on_notebook_switch_page" : self.on_notebook_switch_page,
+ "on_recentview_row_activated" : self.on_recentview_row_activated,
+ "on_back_clicked" : self.on_backspace
+ }
+ self.wTree.signal_autoconnect(callbackMapping)
+ self.wTree.get_widget("callbackcombo").get_child().connect("changed", self.on_callbackentry_changed)
+
+ # Defer initalization of recent view
+ self.gcd = GCDialer()
+
+ self.attemptLogin(2)
+ gobject.idle_add(self._init_grandcentral)
+ gobject.idle_add(self._init_recent_view)
+
+ def _init_grandcentral(self):
+ """ deferred initalization of the grandcentral info """
+
+ try:
+ if self.gcd.isAuthed():
+ if self.gcd.getCallbackNumber() is None:
+ self.gcd.setSaneCallback()
+ except:
+ pass
+
+ self.setAccountNumber()
+ print "exit init_gc"
+ return False
+
+ def _init_recent_view(self):
+ """ deferred initalization of the recent view treeview """
+
+ recentview = self.wTree.get_widget("recentview")
+ recentview.set_model(self.recentmodel)
+ textrenderer = gtk.CellRendererText()
+
+ # Add the column to the treeview
+ column = gtk.TreeViewColumn("Calls", textrenderer, text=1)
+ column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+
+ recentview.append_column(column)
+
+ self.recentviewselection = recentview.get_selection()
+ self.recentviewselection.set_mode(gtk.SELECTION_SINGLE)
+
+ return False
+
+ def _setupCallbackCombo(self):
+ combobox = self.wTree.get_widget("callbackcombo")
+ self.callbacklist = gtk.ListStore(gobject.TYPE_STRING)
+ combobox.set_model(self.callbacklist)
+ combobox.set_text_column(0)
+ for number, description in self.gcd.getCallbackNumbers().iteritems():
+ self.callbacklist.append([makepretty(number)] )
+
+ self.wTree.get_widget("callbackcombo").get_child().set_text(makepretty(self.gcd.getCallbackNumber()))
+ self.callbackNeedsSetup = False
+
+ def populate_recentview(self):
+ print "Populating"
+ self.recentmodel.clear()
+ for item in self.gcd.get_recent():
+ self.recentmodel.append(item)
+ self.recenttime = time.time()
+
+ return False
+
+ def attemptLogin(self, times = 1):
+ dialog = self.wTree.get_widget("login_dialog")
+
+ while (0 < times) and not self.gcd.isAuthed():
+ if dialog.run() != gtk.RESPONSE_OK:
+ times = 0
+ continue
+
+ username = self.wTree.get_widget("usernameentry").get_text()
+ password = self.wTree.get_widget("passwordentry").get_text()
+ self.wTree.get_widget("passwordentry").set_text("")
+ print "Attempting login"
+ self.gcd.login(username, password)
+ print "hiding dialog"
+ dialog.hide()
+ times = times - 1
+
+ return False
+
+ def ErrPopUp(self, msg):
+ error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
+
def close(dialog, response, editor):
editor.about_dialog = None
dialog.destroy()
error_dialog.connect("response", close, self)
- # error_dialog.connect("delete-event", delete_event, self)
- self.error_dialog = error_dialog
error_dialog.run()
- def on_About_clicked(self, menuitem, data=None):
- if self.about_dialog:
- self.about_dialog.present()
+ def setNumber(self, number):
+ self.phonenumber = makeugly(number)
+ self.prettynumber = makepretty(self.phonenumber)
+ self.numberdisplay.set_label("<span size='30000' weight='bold'>%s</span>" % ( self.prettynumber ) )
+
+ def setAccountNumber(self):
+ accountnumber = self.gcd.getAccountNumber()
+ self.wTree.get_widget("gcnumberlabel").set_label("<span size='23000' weight='bold'>%s</span>" % (accountnumber))
+
+ def on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
+ """
+ For shutdown or save_unsaved_data, our only state is cookies and I think the cookie manager handles that for us.
+ For system_inactivity, we have no background tasks to pause
+
+ @note Hildon specific
+ """
+ if memory_low:
+ self.gcd.clear_caches()
+ re.purge()
+ gc.collect()
+
+ def on_connection_change(self, connection, event, magicIdentifier):
+ """
+ @note Hildon specific
+ """
+ status = event.get_status()
+ error = event.get_error()
+ iap_id = event.get_iap_id()
+ bearer = event.get_bearer_type()
+
+ if status == conic.STATUS_CONNECTED:
+ self.window.set_sensitive(True)
+ elif status == conic.STATUS_DISCONNECTED:
+ self.window.set_sensitive(False)
+
+ def on_loginbutton_clicked(self, data=None):
+ self.wTree.get_widget("login_dialog").response(gtk.RESPONSE_OK)
+
+ def on_loginclose_clicked(self, data=None):
+ sys.exit(0)
+
+ def on_clearcookies_clicked(self, data=None):
+ self.gcd.reset()
+ self.callbackNeedsSetup = True
+ self.recenttime = 0.0
+ self.recentmodel.clear()
+ self.wTree.get_widget("callbackcombo").get_child().set_text("")
+
+ # re-run the inital grandcentral setup
+ self.attemptLogin(2)
+ gobject.idle_add(self._init_grandcentral)
+
+ def on_callbackentry_changed(self, data=None):
+ text = makeugly(self.wTree.get_widget("callbackcombo").get_child().get_text())
+ if self.gcd.validate(text) and text != self.gcd.getCallbackNumber():
+ self.gcd.setCallbackNumber(text)
+
+ def on_recentview_row_activated(self, treeview, path, view_column):
+ model, itr = self.recentviewselection.get_selected()
+ if not itr:
return
- authors = [ "Mark Bergman <bergman@merctech.com>",
- "Eric Warnke <ericew@gmail.com>" ]
+ self.setNumber(self.recentmodel.get_value(itr, 0))
+ self.notebook.set_current_page(0)
+ self.recentviewselection.unselect_all()
+
+ def on_notebook_switch_page(self, notebook, page, page_num):
+ if page_num == 1 and (time.time() - self.recenttime) > 300:
+ gobject.idle_add(self.populate_recentview)
+ elif page_num ==2 and self.callbackNeedsSetup:
+ gobject.idle_add(self._setupCallbackCombo)
+ if hildon:
+ try:
+ self.window.set_title(self.notebook.get_tab_label(self.notebook.get_nth_page(page_num)).get_text())
+ except:
+ self.window.set_title("")
+
+ def on_dial_clicked(self, widget):
+ self.attemptLogin(3)
+
+ if not self.gcd.isAuthed() or self.gcd.getCallbackNumber() == "":
+ self.ErrPopUp("Backend link with grandcentral is not working, please try again")
+ return
- about_dialog = gtk.AboutDialog()
- about_dialog.set_transient_for(None)
- about_dialog.set_destroy_with_parent(True)
- about_dialog.set_name("Grandcentral Dialer")
- about_dialog.set_version("0.5")
- about_dialog.set_copyright("Copyright \xc2\xa9 2008 Mark Bergman")
- about_dialog.set_comments("GUI front-end to initiate outbound call from Grandcentral.com, typically with Grancentral configured to connect the outbound call to a VOIP number accessible via Gizmo on the Internet Tablet.\n\nRequires an existing browser cookie from a previous login session to http://www.grandcentral.com/mobile/messages and the program 'wget'.")
- about_dialog.set_authors (authors)
- about_dialog.set_logo_icon_name (gtk.STOCK_EDIT)
+ try:
+ callSuccess = self.gcd.dial(self.phonenumber)
+ except ValueError, e:
+ self.gcd._msg = e.message
+ callSuccess = False
- # callbacks for destroying the dialog
- def close(dialog, response, editor):
- editor.about_dialog = None
- dialog.destroy()
+ if not callSuccess:
+ self.ErrPopUp(self.gcd._msg)
+ else:
+ self.setNumber("")
- def delete_event(dialog, event, editor):
- editor.about_dialog = None
- return True
-
- about_dialog.connect("response", close, self)
- about_dialog.connect("delete-event", delete_event, self)
- self.about_dialog = about_dialog
- about_dialog.show()
-
- def on_Dial_clicked(self, widget):
- # Strip the leading "1" before the area code, if present
- if len(Dialpad.phonenumber) == 11 and Dialpad.phonenumber[0] == "1" :
- Dialpad.phonenumber = Dialpad.phonenumber[1:]
- prettynumber = makepretty(Dialpad.phonenumber)
- if len(Dialpad.phonenumber) < 7 :
- # It's too short to be a phone number
- msg = 'Phone number "%s" is too short' % ( prettynumber )
- self.ErrPopUp(msg)
- else :
- timestamp=time.asctime(time.localtime())
-
- if self.gcd.dial(Dialpad.phonenumber) == True :
- histFH = open(histfile,"a")
- histFH.write("%s dialed at %s\n" % ( Dialpad.phonenumber, timestamp ) )
- histFH.close()
-
- # Re-load the updated history of dialed numbers
- load_history_list(histfile,liststore)
- self.dialer_history.set_active(-1)
- self.on_Clear_clicked(widget)
- else:
- self.ErrPopUp(self.gcd._msg)
+ self.recentmodel.clear()
+ self.recenttime = 0.0
+
+ def on_paste(self, data=None):
+ contents = self.clipboard.wait_for_text()
+ phoneNumber = re.sub('\D', '', contents)
+ self.setNumber(phoneNumber)
+
+ def on_digit_clicked(self, widget):
+ self.setNumber(self.phonenumber + widget.get_name()[5])
- def on_Cancel_clicked(self, widget):
- sys.exit(1)
+ def on_backspace(self, widget):
+ self.setNumber(self.phonenumber[:-1])
- def Backspace(self, widget):
- Dialpad.phonenumber = Dialpad.phonenumber[:-1]
- prettynumber = makepretty(Dialpad.phonenumber)
- self.numberdisplay.set_text(prettynumber)
- def on_Clear_clicked(self, widget):
- Dialpad.phonenumber = ""
- self.numberdisplay.set_text(Dialpad.phonenumber)
+def run_doctest():
+ failureCount, testCount = doctest.testmod()
+ if not failureCount:
+ print "Tests Successful"
+ sys.exit(0)
+ else:
+ sys.exit(1)
- def on_dialer_history_changed(self,widget):
- # Set the displayed number to the number chosen from the history list
- history_list = self.dialer_history.get_model()
- history_index = self.dialer_history.get_active()
- prettynumber = history_list[history_index][0]
- Dialpad.phonenumber = makeugly(prettynumber)
- self.numberdisplay.set_text(prettynumber)
- def on_number_clicked(self, widget):
- Dialpad.phonenumber = Dialpad.phonenumber + re.sub('\D','',widget.get_label())
- prettynumber = makepretty(Dialpad.phonenumber)
- self.numberdisplay.set_text(prettynumber)
+def run_dialpad():
+ gtk.gdk.threads_init()
+ title = 'Dialpad'
+ handle = Dialpad()
+ gtk.main()
+ sys.exit(0)
+class DummyOptions(object):
+ def __init__(self):
+ self.test = False
+
if __name__ == "__main__":
- title = 'Dialpad'
- handle = Dialpad()
- gtk.main()
- sys.exit(1)
+ if hildon:
+ gtk.set_application_name("Dialer")
+
+ try:
+ parser = optparse.OptionParser()
+ parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests")
+ (options, args) = parser.parse_args()
+ except:
+ args = []
+ options = DummyOptions()
+
+ if options.test:
+ run_doctest()
+ else:
+ run_dialpad()