Index: conduit/modules/GoogleModule/GoogleModule.py
===================================================================
--- conduit/modules/GoogleModule/GoogleModule.py	(revision 1351)
+++ conduit/modules/GoogleModule/GoogleModule.py	(working copy)
@@ -12,9 +12,11 @@
 import conduit.Utils as Utils
 import conduit.Exceptions as Exceptions
 from conduit.datatypes import Rid
+import conduit.datatypes.Contact as Contact
 import conduit.datatypes.Event as Event
 import conduit.datatypes.Photo as Photo
 import conduit.datatypes.Video as Video
+import conduit.datatypes.File as File
 
 from gettext import gettext as _
 
@@ -35,6 +37,8 @@
 MODULES = {
     "GoogleCalendarTwoWay" : { "type": "dataprovider" },
     "PicasaTwoWay" :         { "type": "dataprovider" },
+    "GContactConverter":     { "type": "converter"},
+    "ContactsSource" :       { "type": "dataprovider" },
     "YouTubeSource" :        { "type": "dataprovider" },       
 }
 
@@ -667,6 +671,113 @@
             return False
         return True
 
+class GContact(Contact.Contact):
+    _name_ = "contact-gdata"
+
+    def __init__(self):
+        Contact.Contact.__init__(self)
+        self.gdata = ""
+
+    def set_gdata(self, gdata):
+        self.gdata = gdata
+
+    def get_gdata(self):
+        return self.gdata
+
+    def get_hash(self):
+        return hash(str(self.gdata))
+
+class GContactConverter:
+    def __init__(self):
+        self.conversions =  {
+            "contact-gdata,file"     :   self.contact_to_file,    
+            "file,contact-gdata"     :   self.file_to_contact,
+        }
+
+    def contact_to_file(self, contact, **kwargs):
+        f = File.TempFile(str(contact.get_gdata()))
+        return f
+
+    def file_to_contact(self, f, **kwargs):
+        c = GContact()
+        return c
+
+class ContactsSource(GoogleBase, DataProvider.DataSource):
+    """
+    Contacts GData provider
+    """
+    _name_ = _("Contacts")
+    _description_ = _("Sync contacts from Google")
+    _category_ = conduit.dataproviders.CATEGORY_MISC
+    _module_type_ = "source"
+    _out_type_ = "contact-gdata"
+    _icon_ = "contact"
+
+    FEED = "http://www.google.com/m8/feeds/contacts/%s/base"
+
+    def __init__(self, *args):
+        GoogleBase.__init__(self)
+        DataProvider.DataSource.__init__(self)
+        self.entries = None
+        self.feed = ""
+
+    def _set_username(self, username):
+        GoogleBase._set_username(self, username)
+        self.feed = self.FEED % self.username
+
+    def _do_login(self):
+        self.service = gdata.service.GDataService(service="cp", server="www.google.com")
+        self.service.ClientLogin(self.username, self.password)
+
+    def get_all(self):
+        # we can ask the server for everything thats changed after a certain date, including deletions
+        self._login()
+        contacts = self.service.GetFeed(self.feed).entry
+        return [str(contact.id.text) for contact in contacts]
+
+    def get(self, LUID):
+        DataProvider.DataSource.get(self, LUID)
+        self._login()
+        gdata = self.service.Get(LUID)
+        print str(gdata)
+        c = GContact()
+        c.set_UID(LUID)
+        #c.set_mtime(convert_madness_to_datetime(gdata.updated.text))
+        c.set_gdata(gdata)
+        return c
+
+    def delete(self, LUID):
+        self._login()
+        self.service.Delete(LUID)
+
+    def finish(self, aborted, error, conflict):
+        DataProvider.DataSource.finish(self)
+
+    def configure(self, window):
+        """
+        Configures the PicasaTwoWay
+        """
+        widget = Utils.dataprovider_glade_get_widget(
+                        __file__, 
+                        "contacts-config.glade", 
+                        "GoogleContactsConfigDialog")
+                        
+        #get a whole bunch of widgets
+        username = widget.get_widget("username")
+        password = widget.get_widget("password")
+        
+        #preload the widgets        
+        username.set_text(self.username)
+        password.set_text(self.password)
+        
+        dlg = widget.get_widget("GoogleContactsConfigDialog")
+        response = Utils.run_dialog (dlg, window)
+        if response == True:
+            self._set_username(username.get_text())
+            self._set_password(password.get_text())
+        dlg.destroy()    
+
+
 class YouTubeSource(DataProvider.DataSource):
     """
     Downloads YouTube videos using the gdata API.
Index: conduit/modules/GoogleModule/contacts-config.glade
===================================================================
--- conduit/modules/GoogleModule/contacts-config.glade	(revision 0)
+++ conduit/modules/GoogleModule/contacts-config.glade	(revision 0)
@@ -0,0 +1,199 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="GoogleContactsConfigDialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Google Contacts</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">250</property>
+  <property name="default_height">350</property>
+  <property name="resizable">False</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+  <property name="has_separator">True</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="vbox30">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">5</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="hbuttonbox12">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="button32">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="okBtn">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-ok</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkLabel" id="label74">
+	  <property name="visible">True</property>
+	  <property name="label" translatable="yes">&lt;b&gt;Account Details&lt;/b&gt;</property>
+	  <property name="use_underline">False</property>
+	  <property name="use_markup">True</property>
+	  <property name="justify">GTK_JUSTIFY_LEFT</property>
+	  <property name="wrap">False</property>
+	  <property name="selectable">False</property>
+	  <property name="xalign">0.5</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xpad">0</property>
+	  <property name="ypad">0</property>
+	  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	  <property name="width_chars">-1</property>
+	  <property name="single_line_mode">False</property>
+	  <property name="angle">0</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkLabel" id="label75">
+	  <property name="visible">True</property>
+	  <property name="label" translatable="yes">Email:</property>
+	  <property name="use_underline">False</property>
+	  <property name="use_markup">False</property>
+	  <property name="justify">GTK_JUSTIFY_LEFT</property>
+	  <property name="wrap">False</property>
+	  <property name="selectable">False</property>
+	  <property name="xalign">0</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xpad">0</property>
+	  <property name="ypad">0</property>
+	  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	  <property name="width_chars">-1</property>
+	  <property name="single_line_mode">False</property>
+	  <property name="angle">0</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkEntry" id="username">
+	  <property name="visible">True</property>
+	  <property name="can_focus">True</property>
+	  <property name="editable">True</property>
+	  <property name="visibility">True</property>
+	  <property name="max_length">0</property>
+	  <property name="text" translatable="yes"></property>
+	  <property name="has_frame">True</property>
+	  <property name="invisible_char">●</property>
+	  <property name="activates_default">False</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkLabel" id="label76">
+	  <property name="visible">True</property>
+	  <property name="label" translatable="yes">Password:</property>
+	  <property name="use_underline">False</property>
+	  <property name="use_markup">False</property>
+	  <property name="justify">GTK_JUSTIFY_LEFT</property>
+	  <property name="wrap">False</property>
+	  <property name="selectable">False</property>
+	  <property name="xalign">0</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xpad">0</property>
+	  <property name="ypad">0</property>
+	  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	  <property name="width_chars">-1</property>
+	  <property name="single_line_mode">False</property>
+	  <property name="angle">0</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkEntry" id="password">
+	  <property name="visible">True</property>
+	  <property name="can_focus">True</property>
+	  <property name="editable">True</property>
+	  <property name="visibility">False</property>
+	  <property name="max_length">0</property>
+	  <property name="text" translatable="yes"></property>
+	  <property name="has_frame">True</property>
+	  <property name="invisible_char">●</property>
+	  <property name="activates_default">False</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHButtonBox" id="hbuttonbox13">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+	  <property name="spacing">0</property>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
