Still some issues, but the start of SMS support
authorepage <eopage@byu.net>
Tue, 19 May 2009 03:14:54 +0000 (03:14 +0000)
committerepage <eopage@byu.net>
Tue, 19 May 2009 03:14:54 +0000 (03:14 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@290 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dialcentral.glade
src/gc_views.py
src/gtk_toolbox.py
src/gv_backend.py

index 860d698..58191fd 100644 (file)
@@ -926,6 +926,20 @@ Number:</property>
             <property name="visible">True</property>
             <property name="layout_style">end</property>
             <child>
+              <widget class="GtkButton" id="sms_button">
+                <property name="label" translatable="yes">SMS</property>
+                <property name="response_id">-4</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
               <widget class="GtkButton" id="dial_button">
                 <property name="label" translatable="yes">Dial</property>
                 <property name="visible">True</property>
@@ -935,7 +949,7 @@ Number:</property>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">0</property>
+                <property name="position">1</property>
               </packing>
             </child>
             <child>
@@ -949,7 +963,7 @@ Number:</property>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">1</property>
+                <property name="position">2</property>
               </packing>
             </child>
             <child>
@@ -963,7 +977,128 @@ Number:</property>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
-                <property name="position">2</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="smsDialog">
+    <property name="border_width">5</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox3">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <widget class="GtkLabel" id="smsMessage">
+                <property name="visible">True</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <child>
+                  <widget class="GtkTextView" id="smsEntry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="wrap_mode">word</property>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkLabel" id="smsLetterCount1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Letters Left:</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="smsLetterCount">
+                <property name="visible">True</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area3">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <widget class="GtkButton" id="sendSmsButton">
+                <property name="label" translatable="yes">Send</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkButton" id="cancelSmsButton">
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
               </packing>
             </child>
           </widget>
index c6ef32f..2cae8c9 100644 (file)
@@ -317,7 +317,12 @@ class PhoneTypeSelector(object):
        def __init__(self, widgetTree, gcBackend):
                self._gcBackend = gcBackend
                self._widgetTree = widgetTree
+
                self._dialog = self._widgetTree.get_widget("phonetype_dialog")
+               self._smsDialog = SmsEntryDialog(self._widgetTree, self._gcBackend)
+
+               self._smsButton = self._widgetTree.get_widget("sms_button")
+               self._smsButton.connect("clicked", self._on_phonetype_send_sms)
 
                self._dialButton = self._widgetTree.get_widget("dial_button")
                self._dialButton.connect("clicked", self._on_phonetype_dial)
@@ -381,6 +386,11 @@ class PhoneTypeSelector(object):
                self._gcBackend.dial(self._get_number())
                self._dialog.response(gtk.RESPONSE_CANCEL)
 
+       def _on_phonetype_send_sms(self, *args):
+               self._dialog.response(gtk.RESPONSE_CANCEL)
+               idly_run = gtk_toolbox.asynchronous_gtk_message(self._smsDialog.run)
+               idly_run(self._get_number(), self._message.get_text())
+
        def _on_phonetype_select(self, *args):
                self._dialog.response(gtk.RESPONSE_OK)
 
@@ -388,6 +398,58 @@ class PhoneTypeSelector(object):
                self._dialog.response(gtk.RESPONSE_CANCEL)
 
 
+class SmsEntryDialog(object):
+
+       MAX_CHAR = 160
+
+       def __init__(self, widgetTree, gcBackend):
+               self._gcBackend = gcBackend
+               self._widgetTree = widgetTree
+               self._dialog = self._widgetTree.get_widget("smsDialog")
+
+               self._smsButton = self._widgetTree.get_widget("sendSmsButton")
+               self._smsButton.connect("clicked", self._on_send)
+
+               self._cancelButton = self._widgetTree.get_widget("cancelSmsButton")
+               self._cancelButton.connect("clicked", self._on_cancel)
+
+               self._letterCountLabel = self._widgetTree.get_widget("smsLetterCount")
+               self._message = self._widgetTree.get_widget("smsMessage")
+               self._smsEntry = self._widgetTree.get_widget("smsEntry")
+               self._smsEntry.get_buffer().connect("changed", self._on_entry_changed)
+
+       def run(self, number, message = ""):
+               if message:
+                       self._message.show()
+                       self._message.set_text(message)
+               else:
+                       self._message.hide()
+               self._smsEntry.get_buffer().set_text("")
+               self._update_letter_count()
+
+               userResponse = self._dialog.run()
+               if userResponse == gtk.RESPONSE_OK:
+                       entryBuffer = self._smsEntry.get_buffer()
+                       enteredMessage = entryBuffer.get_text(entryBuffer.get_start_iter(), entryBuffer.get_end_iter())
+                       enteredMessage = enteredMessage[0:self.MAX_CHAR]
+                       self._gcBackend.send_sms(number, enteredMessage)
+
+               self._dialog.hide()
+
+       def _update_letter_count(self, *args):
+               entryLength = self._smsEntry.get_buffer().get_char_count()
+               self._letterCountLabel.set_text(str(self.MAX_CHAR - entryLength))
+
+       def _on_entry_changed(self, *args):
+               self._update_letter_count()
+
+       def _on_send(self, *args):
+               self._dialog.response(gtk.RESPONSE_OK)
+
+       def _on_cancel(self, *args):
+               self._dialog.response(gtk.RESPONSE_CANCEL)
+
+
 class Dialpad(object):
 
        def __init__(self, widgetTree, errorDisplay):
index 5c65139..9559b45 100644 (file)
@@ -48,7 +48,9 @@ def asynchronous_gtk_message(original_func):
 
        def execute(allArgs):
                args, kwargs = allArgs
-               original_func(*args, **kwargs)
+               with gtk_lock():
+                       original_func(*args, **kwargs)
+               return False
 
        @functools.wraps(original_func)
        def delayed_func(*args, **kwargs):
index f78c9b2..0660178 100644 (file)
@@ -81,6 +81,7 @@ class GVDialer(object):
        _contactDetailPhoneRe = re.compile(r"""<div.*?>([0-9\-\(\) \t]+?)<span.*?>\((\w+)\)</span>""", re.S)
 
        _clicktocallURL = "https://www.google.com/voice/m/sendcall"
+       _smsURL = "https://www.google.com/voice/m/sendsms"
        _contactsURL = "https://www.google.com/voice/mobile/contacts"
        _contactDetailURL = "https://www.google.com/voice/mobile/contact"
 
@@ -169,15 +170,7 @@ class GVDialer(object):
                """
                This is the main function responsible for initating the callback
                """
-               if not self.is_valid_syntax(number):
-                       raise ValueError('Number is not valid: "%s"' % number)
-               elif not self.is_authed():
-                       raise RuntimeError("Not Authenticated")
-
-               if len(number) == 11 and number[0] == 1:
-                       # Strip leading 1 from 11 digit dialing
-                       number = number[1:]
-
+               number = self._send_validation(number)
                try:
                        clickToCallData = urllib.urlencode({
                                "number": number,
@@ -197,6 +190,27 @@ class GVDialer(object):
 
                return True
 
+       def send_sms(self, number, message):
+               number = self._send_validation(number)
+               message = saxutils.escape(message)
+               try:
+                       smsData = urllib.urlencode({
+                               "number": number,
+                               "smstext": message,
+                               "_rnr_se": self._token,
+                               "id": "undefined",
+                               "c": "undefined",
+                       })
+                       otherData = {
+                               'Referer' : 'https://google.com/voice/m/sms',
+                       }
+                       smsSuccessPage = self._browser.download(self._smsURL, smsData, None, otherData)
+               except urllib2.URLError, e:
+                       warnings.warn(traceback.format_exc())
+                       raise RuntimeError("%s is not accesible" % self._clicktocallURL)
+
+               return True
+
        def clear_caches(self):
                self.__contacts = None
 
@@ -411,6 +425,17 @@ class GVDialer(object):
                        callbackName = match.group(1)
                        self._callbackNumbers[callbackNumber] = callbackName
 
+       def _send_validation(self, number):
+               if not self.is_valid_syntax(number):
+                       raise ValueError('Number is not valid: "%s"' % number)
+               elif not self.is_authed():
+                       raise RuntimeError("Not Authenticated")
+
+               if len(number) == 11 and number[0] == 1:
+                       # Strip leading 1 from 11 digit dialing
+                       number = number[1:]
+               return number
+
        def _get_recent(self):
                """
                @returns Iterable of (personsName, phoneNumber, exact date, relative date, action)