Filesystem backed contacts and minor cleanups
authorepage <eopage@byu.net>
Thu, 19 Feb 2009 02:59:47 +0000 (02:59 +0000)
committerepage <eopage@byu.net>
Thu, 19 Feb 2009 02:59:47 +0000 (02:59 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@193 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dialcentral.glade
src/file_backend.py [new file with mode: 0644]
src/gc_backend.py
src/gc_dialer.py
support/builddeb.py

index ef2f853..48b2d6f 100644 (file)
                   <widget class="GtkLabel" id="numberdisplay">
                     <property name="height_request">50</property>
                     <property name="visible">True</property>
-                    <property name="label" translatable="yes">&lt;span size="35000" weight="bold"&gt;(518) 555-1212&lt;/span&gt;</property>
+                    <property name="label" translatable="yes">&lt;span size="35000" weight="bold"&gt;&lt;/span&gt;</property>
                     <property name="use_markup">True</property>
                     <property name="justify">GTK_JUSTIFY_CENTER</property>
                   </widget>
diff --git a/src/file_backend.py b/src/file_backend.py
new file mode 100644 (file)
index 0000000..2aa77a2
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/python
+
+# DialCentral - Front end for Google's Grand Central service.
+# Copyright (C) 2008  Eric Warnke ericew AT gmail DOT com
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+"""
+Filesystem backend for contact support
+"""
+
+
+import os
+import csv
+
+
+class CsvAddressBook(object):
+       """
+       Currently supported file format
+       @li Has the first line as a header
+       @li Escapes with quotes
+       @li Comma as delimiter
+       @li Column 0 is name, column 1 is number
+       """
+
+       def __init__(self, csvPath):
+               self.__csvPath = csvPath
+               self.__contacts = list(
+                       self.read_csv(csvPath)
+               )
+
+       @staticmethod
+       def read_csv(csvPath):
+               csvReader = iter(csv.reader(open(csvPath, "rU")))
+               csvReader.next()
+               for i, row in enumerate(csvReader):
+                       yield str(i), row[0], row[1]
+
+       def clear_caches(self):
+               pass
+
+       @staticmethod
+       def factory_name():
+               return "csv"
+
+       @staticmethod
+       def contact_source_short_name(contactId):
+               return "csv"
+
+       def get_contacts(self):
+               """
+               @returns Iterable of (contact id, contact name)
+               """
+               for contact in self.__contacts:
+                       yield contact[0:2]
+
+       def get_contact_details(self, contactId):
+               """
+               @returns Iterable of (Phone Type, Phone Number)
+               """
+               contactId = int(contactId)
+               yield "", self.__contacts[contactId][2]
+
+
+class FilesystemAddressBookFactory(object):
+
+       FILETYPE_SUPPORT = {
+               "csv": CsvAddressBook,
+       }
+
+       def __init__(self, path):
+               self.__path = path
+
+       def clear_caches(self):
+               pass
+
+       def get_addressbooks(self):
+               """
+               @returns Iterable of (Address Book Factory, Book Id, Book Name)
+               """
+               for root, dirs, files in os.walk(self.__path):
+                       for file in files:
+                               name, ext = file.rsplit(".", 1)
+                               if ext in self.FILETYPE_SUPPORT:
+                                       yield self, os.path.join(root, file), name
+
+       def open_addressbook(self, bookId):
+               name, ext = bookId.rsplit(".", 1)
+               assert ext in self.FILETYPE_SUPPORT
+               return self.FILETYPE_SUPPORT[ext](bookId)
+
+       @staticmethod
+       def factory_name():
+               return "File"
+
+
+def print_books():
+       """
+       Included here for debugging.
+
+       Either insert it into the code or launch python with the "-i" flag
+       """
+       eab = FilesystemAddressBookFactory(os.path.expanduser("~/Desktop"))
+       for book in eab.get_addressbooks():
+               eab = eab.open_addressbook(book[1])
+               print book
+               for contact in eab.get_contacts():
+                       print "\t", contact
+                       for details in eab.get_contact_details(contact[0]):
+                               print "\t\t", details
index 67ca99b..aff8238 100644 (file)
@@ -51,8 +51,8 @@ class GCDialer(object):
        _inboxRe = re.compile(r"""<td>.*?(voicemail|received|missed|call return).*?</td>\s+<td>\s+<font size="2">\s+(.*?)\s+&nbsp;\|&nbsp;\s+<a href="/mobile/contacts/.*?">(.*?)\s?</a>\s+<br/>\s+(.*?)\s?<a href=""", re.S)
        _contactsRe = re.compile(r"""<a href="/mobile/contacts/detail/(\d+)">(.*?)</a>""", re.S)
        _contactsNextRe = re.compile(r""".*<a href="/mobile/contacts(\?page=\d+)">Next</a>""", re.S)
-       _contactDetailGroupRe   = re.compile(r"""Group:\s*(\w*)""", re.S)
-       _contactDetailPhoneRe   = re.compile(r"""(\w+):[0-9\-\(\) \t]*?<a href="/mobile/calls/click_to_call\?destno=(\d+).*?">call</a>""", re.S)
+       _contactDetailGroupRe = re.compile(r"""Group:\s*(\w*)""", re.S)
+       _contactDetailPhoneRe = re.compile(r"""(\w+):[0-9\-\(\) \t]*?<a href="/mobile/calls/click_to_call\?destno=(\d+).*?">call</a>""", re.S)
 
        _validateRe = re.compile("^[0-9]{10,}$")
 
@@ -70,7 +70,7 @@ class GCDialer(object):
 
                self._browser = MozillaEmulator(None, 0)
                if cookieFile is None:
-                       cookieFile = os.path.join(os.path.expanduser("~"), ".gc_dialer_cookies.txt")
+                       cookieFile = os.path.join(os.path.expanduser("~"), ".gc_cookies.txt")
                self._browser.cookies.filename = cookieFile
                if os.path.isfile(cookieFile):
                        self._browser.cookies.load()
index 7fe6737..fada203 100755 (executable)
@@ -50,6 +50,8 @@ class Dialcentral(object):
                os.path.join(os.path.dirname(__file__), "../lib/dialcentral.glade"),
        ]
 
+       _data_path = os.path.join(os.path.expanduser("~"), ".dialcentral")
+
        def __init__(self):
                self._gcBackend = None
                self._clipboard = gtk.clipboard_get()
@@ -65,7 +67,7 @@ class Dialcentral(object):
                                self._widgetTree = gtk.glade.XML(path)
                                break
                else:
-                       self.display_error_message("Cannot find gc_dialer.glade")
+                       self.display_error_message("Cannot find dialcentral.glade")
                        gtk.main_quit()
                        return
 
@@ -148,12 +150,19 @@ class Dialcentral(object):
                        warnings.warn("No Internet Connectivity API ", UserWarning, 2)
 
                import gc_backend
+               import file_backend
                import evo_backend
                # import gmail_backend
                # import maemo_backend
                import views
 
-               self._gcBackend = gc_backend.GCDialer()
+               cookieFile = os.path.join(self._data_path, "cookies.txt")
+               try:
+                       os.makedirs(os.path.dirname(cookieFile))
+               except OSError, e:
+                       if e.errno != 17:
+                               raise
+               self._gcBackend = gc_backend.GCDialer(cookieFile)
                gtk.gdk.threads_enter()
                try:
                        self._dialpad = views.Dialpad(self._widgetTree)
@@ -178,9 +187,11 @@ class Dialcentral(object):
                else:
                        self.attempt_login(2)
 
+               fsContactsPath = os.path.join(self._data_path, "contacts")
                addressBooks = [
                        self._gcBackend,
                        evo_backend.EvolutionAddressBook(),
+                       file_backend.FilesystemAddressBookFactory(fsContactsPath),
                ]
                mergedBook = views.MergedAddressBook(addressBooks, views.MergedAddressBook.basic_lastname_sorter)
                self._contactsView.append(mergedBook)
index 0016d0a..ebd98f4 100755 (executable)
@@ -13,6 +13,7 @@ __changelog__ = '''\
 0.8.4 - ""
  * Caching of contacts
  * Refactoring to make working with the code easier
+ * Filesystem backed contacts but currently only supporting a specific csv format
 
 0.8.3 - "Extras Love"
  * Version bump fighting the extras autobuilder, I hope this works