Evolution-python - Patch to add EBookView and EBookQuery



Here's a patch adding support to EBookView and EBookQuery objects.

You can use the BookView to search the address books using the
BookQuery as a filter. The results are then sent through a few signals
in the BookView, but they were implemented in this patch as callbacks
instead of gobject signals, as they are called with a GList as
argument and  pygobject's closure handling doesn't support signals
with lists.

-- 
Lauro Moura ("lmoura" on Freenode)
http://lauro.wordpress.com
Index: test/bookquery.py
===================================================================
--- test/bookquery.py	(revision 0)
+++ test/bookquery.py	(revision 0)
@@ -0,0 +1,101 @@
+import evolution.ebook as e
+import unittest
+
+class TestBookQuery(unittest.TestCase):
+    
+    def setUp(self):
+        pass
+
+    def testUninitialized(self):
+        q1 = e.EBookQuery()
+        self.assertEqual(q1.__str__(), "<Uninitialized>")
+
+    def testFieldExists(self):
+        q1 = e.EBookQuery.field_exists(e.CONTACT_PHOTO)
+        self.assertEqual(q1.__str__(), "(exists \"photo\")")
+
+    def testFieldExists_Raise(self):
+        self.assertRaises(TypeError, e.EBookQuery.field_exists)
+        self.assertRaises(TypeError, e.EBookQuery.field_exists, "foobar")
+
+    def testVCardFieldExists(self):
+        q1 = e.EBookQuery.vcard_field_exists("FN")
+        self.assertEqual(q1.__str__(), "(exists_vcard \"FN\")")
+
+    def testVCardFieldExists_Raise(self):
+        self.assertRaises(TypeError, e.EBookQuery.vcard_field_exists)
+        self.assertRaises(TypeError, e.EBookQuery.vcard_field_exists, 3)
+
+    def testFieldTest_BeginsWith(self):
+        q1 = e.EBookQuery.field_test(e.CONTACT_NAME,
+                                    e.BOOK_QUERY_BEGINS_WITH,
+                                    "dummy")
+        self.assertEqual(q1.__str__(),
+                         "(beginswith \"name\"  \"dummy\")")
+        
+    def testFieldTest_Contains(self):
+        q1 = e.EBookQuery.field_test(e.CONTACT_NAME, e.BOOK_QUERY_CONTAINS,
+                                    "dummy")
+        self.assertEqual(q1.__str__(),
+                         "(contains \"name\"  \"dummy\")")
+
+    def testFieldTest_EndsWith(self):
+        q1 = e.EBookQuery.field_test(e.CONTACT_NAME,
+                                     e.BOOK_QUERY_ENDS_WITH,
+                                     "dummy")
+        self.assertEqual(q1.__str__(),
+                         "(endswith \"name\"  \"dummy\")")
+    def testFieldTest_Is(self):
+        q1 = e.EBookQuery.field_test(e.CONTACT_NAME, e.BOOK_QUERY_IS,
+                           "dummy")
+        self.assertEqual(q1.__str__(),
+                         "(is \"name\"  \"dummy\")")
+
+    def testAnyFieldContains(self):
+        q1 = e.EBookQuery.any_field_contains("dummy")
+        self.assertEqual(q1.__str__(),
+                         "(contains \"x-evolution-any-field\" \"dummy\")")
+
+    def testAnd(self):
+        q1 = e.EBookQuery.field_exists(e.CONTACT_PHOTO)
+        q2 = e.EBookQuery.field_exists(e.CONTACT_NAME)
+        q3 = e.EBookQuery.any_field_contains("dummy")
+
+        q4 = q1._and([q2, q3])
+
+        self.assertEqual(q4.__str__(),
+        """(and (exists \"photo\") (exists \"name\") \
+(contains \"x-evolution-any-field\" \"dummy\") )""")
+
+        q5 = e.EBookQuery()
+        q6 = q5._and(queries=[q1,q2])
+
+        self.assertEqual(q6.__str__(),
+                    "(and (exists \"photo\") (exists \"name\") )")
+
+    def testOr(self):
+        q1 = e.EBookQuery.field_exists(e.CONTACT_PHOTO)
+        q2 = e.EBookQuery.field_exists(e.CONTACT_NAME)
+        q3 = e.EBookQuery.any_field_contains("dummy")
+
+        q4 = q1._or([q2, q3])
+
+        self.assertEqual(q4.__str__(),
+        """(or (exists \"photo\") (exists \"name\") \
+(contains \"x-evolution-any-field\" \"dummy\") )""")
+
+        q5 = e.EBookQuery()
+        q6 = q5._or([q1,q2])
+
+        self.assertEqual(q6.__str__(),
+                    "(or (exists \"photo\") (exists \"name\") )")
+
+    def testNot(self):
+        q1 = e.EBookQuery.field_exists(e.CONTACT_EMAIL)
+        q2 = q1._not()
+
+    def testFromString(self):
+        q1 = e.EBookQuery.from_string("(exists \"name\")")
+        self.assertEqual(q1.__str__(), "(exists \"name\")")
+if __name__ == "__main__":
+    unittest.main()
Index: test/bookview.py
===================================================================
--- test/bookview.py	(revision 0)
+++ test/bookview.py	(revision 0)
@@ -0,0 +1,215 @@
+#!/usr/bin/python2.5
+
+import time
+import unittest
+
+import evolution.ebook as e
+import gobject
+
+class TestBookView(unittest.TestCase):
+
+    def setUp(self):
+        self.loop = gobject.MainLoop()
+        self.context = self.loop.get_context()
+        self.book = e.open_addressbook("default")
+        self.contact_id = None # Id of created contacts for cleanup
+        self.contacts = None # Contact list from callbacks
+
+    def testCommit(self):
+        c1 = e.EContact()
+        c1.props.full_name = "Original Name"
+        id1 = self.book.add_contact(c1)
+
+        c2 = self.book.get_contact(id1)
+        c2.props.full_name = "Modified Name"
+        self.book.commit_contact(c2)
+
+        c3 = self.book.get_contact(id1)
+        self.assertEqual(c2.props.full_name, c3.props.full_name)
+
+        self.contact_id = id1
+
+
+    def testContactsAddedCb_NoArgs(self):
+        query = e.EBookQuery.field_test(e.CONTACT_FULL_NAME,
+                                        e.BOOK_QUERY_CONTAINS,
+                                        "Dummy")
+        view = self.book.get_book_view(query)
+
+        h1 = view.set_contacts_added_cb(self.added_cb)
+        view.start()
+
+        c1 = e.EContact()
+        c1.props.full_name = "Dummy Contact"
+
+        self.book.add_contact(c1) # Generates the signal
+        self.contact_id = c1.props.id
+        self.refresh_gui()
+
+        if (self.contacts):
+            self.assertEqual(self.contacts[0].props.full_name,
+                             c1.props.full_name)
+            self.assertEqual(self.contacts[0].props.id,
+                             c1.props.id)
+        else:
+            raise TypeError("Contacts not updated")
+
+        view.remove_contacts_added_cb(h1)
+
+    def testContactsAddedCb_Args(self):
+        extra_data = "Extra Data"
+        query = e.EBookQuery.field_test(e.CONTACT_FULL_NAME,
+                                        e.BOOK_QUERY_CONTAINS,
+                                        "Dummy")
+
+        view = self.book.get_book_view(query)
+
+        h1 = view.set_contacts_added_cb(self.added_cb, extra_data)
+        view.start()
+
+        c1 = e.EContact()
+        c1.props.full_name = "Dummy Contact"
+
+        self.book.add_contact(c1)
+        self.contact_id = c1.props.id
+        self.refresh_gui()
+
+        if (self.contacts):
+            self.assertEqual(self.contacts[0].props.full_name,
+                             c1.props.full_name)
+            self.assertEqual(extra_data, self.extra_data)
+        else:
+            raise TypeError("Contacts not updated")
+
+        view.remove_contacts_added_cb(h1)
+
+    def testContactsChangedCb_NoArgs(self):
+
+        new_name = "Dummy Modified"
+
+        query = e.EBookQuery.field_test(e.CONTACT_FULL_NAME,
+                                        e.BOOK_QUERY_CONTAINS,
+                                        "Dummy")
+        view = self.book.get_book_view(query)
+
+        c1 = e.EContact()
+        c1.props.full_name = "Dummy Contact"
+
+        id1 = self.book.add_contact(c1)
+        self.contact_id = id1
+
+        h1 = view.set_contacts_changed_cb(self.added_cb)
+        view.start()
+
+        c2 = self.book.get_contact(id1)
+        c2.props.full_name = new_name
+        self.book.commit_contact(c2) # Generates the signal
+
+        self.refresh_gui()
+
+        if (self.contacts):
+            self.assertEqual(self.contacts[0].props.full_name,
+                             new_name)
+            self.assertEqual(self.contacts[0].props.id,
+                             c2.props.id)
+        else:
+            raise TypeError("Contacts not updated")
+
+        view.remove_contacts_changed_cb(h1)
+
+    def testContactsChangedCb_Args(self):
+        extra_data = "Extra Data"
+        new_name = "Dummy Modified"
+        query = e.EBookQuery.field_test(e.CONTACT_FULL_NAME,
+                                        e.BOOK_QUERY_CONTAINS,
+                                        "Dummy")
+
+        view = self.book.get_book_view(query)
+
+        c1 = e.EContact()
+        c1.props.full_name = "Dummy Contact"
+        h1 = view.set_contacts_changed_cb(self.added_cb, extra_data)
+        view.start()
+
+        id1 = self.book.add_contact(c1)
+        self.contact_id = c1.props.id
+
+        c2 = self.book.get_contact(id1)
+        c2.props.full_name = new_name
+
+        self.book.commit_contact(c2) # Generates the signal
+        self.refresh_gui()
+
+        if (self.contacts):
+            self.assertEqual(self.contacts[0].props.full_name,
+                             new_name)
+            self.assertEqual(extra_data, self.extra_data)
+        else:
+            raise TypeError("Contacts not updated")
+
+        view.remove_contacts_changed_cb(h1)
+
+    def testGetBookViewWithFields(self):
+        query = e.EBookQuery.field_test(e.CONTACT_FULL_NAME,
+                                        e.BOOK_QUERY_CONTAINS,
+                                        "Dummy")
+
+        print query
+
+        view = self.book.get_book_view(query, [e.CONTACT_NICKNAME])
+        view.start()
+
+        print view
+        self.refresh_gui()
+
+    def added_cb(self, view, contacts, extra_data=None):
+        self.contacts = contacts
+        self.extra_data = extra_data
+
+    def tearDown(self):
+        if self.contact_id:
+            self.book.remove_contact_by_id(self.contact_id)
+
+        self.loop.quit()
+        del(self.loop)
+        del(self.book)
+
+    def refresh_gui(self, delay=0):
+        while self.context.pending():
+            self.context.iteration()
+        time.sleep(delay)
+
+    def build_view(self, name, query):
+        c1 = e.EContact()
+        c1.props.full_name = name
+        view = self.book.get_book_view(query)
+
+        return (view, c1)
+
+
+def added_cb(view, contacts, *user_data):
+    print view
+    print contacts
+    print user_data
+
+def main():
+    book = e.open_addressbook("default")
+
+    query = e.EBookQuery.field_exists(e.CONTACT_FULL_NAME)
+
+    view = book.get_book_view(query)
+    handler = view.set_contacts_added_cb(added_cb)
+    h2 = view.set_contacts_added_cb(added_cb, "one")
+    h3 = view.set_contacts_removed_cb(added_cb, "removed", "extra_args")
+    h4 = view.set_contacts_changed_cb(added_cb, "changed")
+    #print view.set_contacts_added_cb(added_cb, None)
+
+    view.remove_contacts_added_cb(handler)
+
+    view.start()
+
+    gtk.main()
+
+
+if __name__ == "__main__":
+    unittest.main()
Index: src/ebook.defs
===================================================================
--- src/ebook.defs	(revision 41)
+++ src/ebook.defs	(working copy)
@@ -23,6 +23,13 @@
   (gtype-id "E_TYPE_BOOK")
 )
 
+(define-object EBookView
+  (in-module "EBook")
+  (parent "GObject")
+  (c-name "EBookView")
+  (gtype-id "E_TYPE_BOOK_VIEW")
+)
+
 ;;------------------------------------------------------------------------------
 ;; EVContact
 ;;------------------------------------------------------------------------------
@@ -73,6 +80,136 @@
   )
 )
 
+; Contact enums
+(define-enum EContactField
+  (in-module "evolution")
+  (c-name "EContactField")
+  (gtype-id "E_TYPE_CONTACT_FIELD")
+  (values
+    '("uid" "E_CONTACT_UID")
+    '("file-as" "E_CONTACT_FILE_AS")
+    '("book-uri" "E_CONTACT_BOOK_URI")
+    '("full-name" "E_CONTACT_FULL_NAME")
+    '("given-name" "E_CONTACT_GIVEN_NAME")
+    '("family-name" "E_CONTACT_FAMILY_NAME")
+    '("nickname" "E_CONTACT_NICKNAME")
+    '("email-1" "E_CONTACT_EMAIL_1")
+    '("email-2" "E_CONTACT_EMAIL_2")
+    '("email-3" "E_CONTACT_EMAIL_3")
+    '("email-4" "E_CONTACT_EMAIL_4")
+    '("mailer" "E_CONTACT_MAILER")
+    '("address-label-home" "E_CONTACT_ADDRESS_LABEL_HOME")
+    '("address-label-work" "E_CONTACT_ADDRESS_LABEL_WORK")
+    '("address-label-other" "E_CONTACT_ADDRESS_LABEL_OTHER")
+    '("phone-assistant" "E_CONTACT_PHONE_ASSISTANT")
+    '("phone-business" "E_CONTACT_PHONE_BUSINESS")
+    '("phone-business-2" "E_CONTACT_PHONE_BUSINESS_2")
+    '("phone-business-fax" "E_CONTACT_PHONE_BUSINESS_FAX")
+    '("phone-callback" "E_CONTACT_PHONE_CALLBACK")
+    '("phone-car" "E_CONTACT_PHONE_CAR")
+    '("phone-company" "E_CONTACT_PHONE_COMPANY")
+    '("phone-home" "E_CONTACT_PHONE_HOME")
+    '("phone-home-2" "E_CONTACT_PHONE_HOME_2")
+    '("phone-home-fax" "E_CONTACT_PHONE_HOME_FAX")
+    '("phone-isdn" "E_CONTACT_PHONE_ISDN")
+    '("phone-mobile" "E_CONTACT_PHONE_MOBILE")
+    '("phone-other" "E_CONTACT_PHONE_OTHER")
+    '("phone-other-fax" "E_CONTACT_PHONE_OTHER_FAX")
+    '("phone-pager" "E_CONTACT_PHONE_PAGER")
+    '("phone-primary" "E_CONTACT_PHONE_PRIMARY")
+    '("phone-radio" "E_CONTACT_PHONE_RADIO")
+    '("phone-telex" "E_CONTACT_PHONE_TELEX")
+    '("phone-ttytdd" "E_CONTACT_PHONE_TTYTDD")
+    '("org" "E_CONTACT_ORG")
+    '("org-unit" "E_CONTACT_ORG_UNIT")
+    '("office" "E_CONTACT_OFFICE")
+    '("title" "E_CONTACT_TITLE")
+    '("role" "E_CONTACT_ROLE")
+    '("manager" "E_CONTACT_MANAGER")
+    '("assistant" "E_CONTACT_ASSISTANT")
+    '("homepage-url" "E_CONTACT_HOMEPAGE_URL")
+    '("blog-url" "E_CONTACT_BLOG_URL")
+    '("categories" "E_CONTACT_CATEGORIES")
+    '("calendar-uri" "E_CONTACT_CALENDAR_URI")
+    '("freebusy-url" "E_CONTACT_FREEBUSY_URL")
+    '("ics-calendar" "E_CONTACT_ICS_CALENDAR")
+    '("video-url" "E_CONTACT_VIDEO_URL")
+    '("spouse" "E_CONTACT_SPOUSE")
+    '("note" "E_CONTACT_NOTE")
+    '("im-aim-home-1" "E_CONTACT_IM_AIM_HOME_1")
+    '("im-aim-home-2" "E_CONTACT_IM_AIM_HOME_2")
+    '("im-aim-home-3" "E_CONTACT_IM_AIM_HOME_3")
+    '("im-aim-work-1" "E_CONTACT_IM_AIM_WORK_1")
+    '("im-aim-work-2" "E_CONTACT_IM_AIM_WORK_2")
+    '("im-aim-work-3" "E_CONTACT_IM_AIM_WORK_3")
+    '("im-groupwise-home-1" "E_CONTACT_IM_GROUPWISE_HOME_1")
+    '("im-groupwise-home-2" "E_CONTACT_IM_GROUPWISE_HOME_2")
+    '("im-groupwise-home-3" "E_CONTACT_IM_GROUPWISE_HOME_3")
+    '("im-groupwise-work-1" "E_CONTACT_IM_GROUPWISE_WORK_1")
+    '("im-groupwise-work-2" "E_CONTACT_IM_GROUPWISE_WORK_2")
+    '("im-groupwise-work-3" "E_CONTACT_IM_GROUPWISE_WORK_3")
+    '("im-jabber-home-1" "E_CONTACT_IM_JABBER_HOME_1")
+    '("im-jabber-home-2" "E_CONTACT_IM_JABBER_HOME_2")
+    '("im-jabber-home-3" "E_CONTACT_IM_JABBER_HOME_3")
+    '("im-jabber-work-1" "E_CONTACT_IM_JABBER_WORK_1")
+    '("im-jabber-work-2" "E_CONTACT_IM_JABBER_WORK_2")
+    '("im-jabber-work-3" "E_CONTACT_IM_JABBER_WORK_3")
+    '("im-yahoo-home-1" "E_CONTACT_IM_YAHOO_HOME_1")
+    '("im-yahoo-home-2" "E_CONTACT_IM_YAHOO_HOME_2")
+    '("im-yahoo-home-3" "E_CONTACT_IM_YAHOO_HOME_3")
+    '("im-yahoo-work-1" "E_CONTACT_IM_YAHOO_WORK_1")
+    '("im-yahoo-work-2" "E_CONTACT_IM_YAHOO_WORK_2")
+    '("im-yahoo-work-3" "E_CONTACT_IM_YAHOO_WORK_3")
+    '("im-msn-home-1" "E_CONTACT_IM_MSN_HOME_1")
+    '("im-msn-home-2" "E_CONTACT_IM_MSN_HOME_2")
+    '("im-msn-home-3" "E_CONTACT_IM_MSN_HOME_3")
+    '("im-msn-work-1" "E_CONTACT_IM_MSN_WORK_1")
+    '("im-msn-work-2" "E_CONTACT_IM_MSN_WORK_2")
+    '("im-msn-work-3" "E_CONTACT_IM_MSN_WORK_3")
+    '("im-icq-home-1" "E_CONTACT_IM_ICQ_HOME_1")
+    '("im-icq-home-2" "E_CONTACT_IM_ICQ_HOME_2")
+    '("im-icq-home-3" "E_CONTACT_IM_ICQ_HOME_3")
+    '("im-icq-work-1" "E_CONTACT_IM_ICQ_WORK_1")
+    '("im-icq-work-2" "E_CONTACT_IM_ICQ_WORK_2")
+    '("im-icq-work-3" "E_CONTACT_IM_ICQ_WORK_3")
+    '("rev" "E_CONTACT_REV")
+    '("name-or-org" "E_CONTACT_NAME_OR_ORG")
+    '("address" "E_CONTACT_ADDRESS")
+    '("address-home" "E_CONTACT_ADDRESS_HOME")
+    '("address-work" "E_CONTACT_ADDRESS_WORK")
+    '("address-other" "E_CONTACT_ADDRESS_OTHER")
+    '("category-list" "E_CONTACT_CATEGORY_LIST")
+    '("photo" "E_CONTACT_PHOTO")
+    '("logo" "E_CONTACT_LOGO")
+    '("name" "E_CONTACT_NAME")
+    '("email" "E_CONTACT_EMAIL")
+    '("im-aim" "E_CONTACT_IM_AIM")
+    '("im-groupwise" "E_CONTACT_IM_GROUPWISE")
+    '("im-jabber" "E_CONTACT_IM_JABBER")
+    '("im-yahoo" "E_CONTACT_IM_YAHOO")
+    '("im-msn" "E_CONTACT_IM_MSN")
+    '("im-icq" "E_CONTACT_IM_ICQ")
+    '("wants-html" "E_CONTACT_WANTS_HTML")
+    '("is-list" "E_CONTACT_IS_LIST")
+    '("list-show-addresses" "E_CONTACT_LIST_SHOW_ADDRESSES")
+    '("birth-date" "E_CONTACT_BIRTH_DATE")
+    '("anniversary" "E_CONTACT_ANNIVERSARY")
+    '("x509-cert" "E_CONTACT_X509_CERT")
+    '("field-last" "E_CONTACT_FIELD_LAST")
+    '("field-first" "E_CONTACT_FIELD_FIRST")
+    '("last-simple-string" "E_CONTACT_LAST_SIMPLE_STRING")
+    '("first-phone-id" "E_CONTACT_FIRST_PHONE_ID")
+    '("last-phone-id" "E_CONTACT_LAST_PHONE_ID")
+    '("first-email-id" "E_CONTACT_FIRST_EMAIL_ID")
+    '("last-email-id" "E_CONTACT_LAST_EMAIL_ID")
+    '("first-address-id" "E_CONTACT_FIRST_ADDRESS_ID")
+    '("last-address-id" "E_CONTACT_LAST_ADDRESS_ID")
+    '("first-label-id" "E_CONTACT_FIRST_LABEL_ID")
+    '("last-label-id" "E_CONTACT_LAST_LABEL_ID")
+  )
+)
+
+
 ;;------------------------------------------------------------------------------
 ;; EBook
 ;;------------------------------------------------------------------------------
@@ -167,8 +304,109 @@
   )
 )
 
+(define-method commit_contact
+  (of-object "EBook")
+  (c-name "e_book_commit_contact")
+  (return-type "gboolean")
+  (parameters
+    '("EContact*" "contact")
+  )
+)
 
+; New get_book_view
+(define-method get_book_view
+  (of-object "EBook")
+  (c-name "e_book_get_book_view")
+  (return-type "gboolean")
+  (parameters
+    '("EBookQuery*" "query")
+    '("GList*" "requested_fields")
+    '("int" "max_results")
+    '("EBookView**" "book_view")
+    '("GError**" "error")
+  )
+)
+
+;; EBookQuery enumerations
+(define-enum EBookQueryTest
+  (in-module "evolution")
+  (c-name "EBookQueryTest")
+  (gtype-id "E_TYPE_BOOK_QUERY_TEST")
+  (values
+    '("is" "E_BOOK_QUERY_IS")
+    '("contains" "E_BOOK_QUERY_CONTAINS")
+    '("begins-with" "E_BOOK_QUERY_BEGINS_WITH")
+    '("ends-with" "E_BOOK_QUERY_ENDS_WITH")
+  )
+)
+
 ;;------------------------------------------------------------------------------
+;; EBookView
+;;------------------------------------------------------------------------------
+
+(define-function e_book_view_get_type
+  (c-name "e_book_view_get_type")
+  (return-type "GType")
+)
+
+(define-method start
+  (of-object "EBookView")
+  (c-name "e_book_view_start")
+  (return-type "none")
+)
+
+(define-method stop
+  (of-object "EBookView")
+  (c-name "e_book_view_stop")
+  (return-type "none")
+)
+
+(define-method set_contacts_added_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_set_contacts_added_cb")
+  (return-type "int")
+)
+
+(define-method remove_contacts_added_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_remove_contacts_added_cb")
+  (parameters
+    '("int" "handler_id")
+  )
+  (return-type "none")
+)
+
+(define-method set_contacts_changed_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_set_contacts_changed_cb")
+  (return-type "int")
+)
+
+(define-method remove_contacts_changed_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_remove_contacts_changed_cb")
+  (parameters
+    '("int" "handler_id")
+  )
+  (return-type "none")
+)
+
+(define-method set_contacts_removed_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_set_contacts_removed_cb")
+  (return-type "int")
+)
+
+(define-method remove_contacts_removed_cb
+  (of-object "EBookView")
+  (c-name "e_book_view_remove_contacts_removed_cb")
+  (parameters
+    '("int" "handler_id")
+  )
+  (return-type "none")
+)
+
+;;------------------------------------------------------------------------------
 ;; evo-environment
 ;;------------------------------------------------------------------------------
 (define-function list_addressbooks
Index: src/ebookmodule.c
===================================================================
--- src/ebookmodule.c	(revision 41)
+++ src/ebookmodule.c	(working copy)
@@ -23,9 +23,10 @@
 #include <pygobject.h>
 
 void pyebook_register_classes(PyObject *d);
-/*void pyebook_add_constants(PyObject *m, const gchar *strip_prefix);*/
+void pyebook_add_constants(PyObject *m, const gchar *strip_prefix);
 
 extern PyMethodDef pyebook_functions[];
+extern PyObject PyEBookQuery_Type;
 
 DL_EXPORT(void)
 initebook(void)
@@ -41,7 +42,7 @@
     
     pyebook_register_classes(d);
 
-    /*pyebook_add_constants(m, "E_");*/
+    pyebook_add_constants(m, "E_");
 
     PyModule_AddObject(m, "__version__",
                        Py_BuildValue("iii",
@@ -49,6 +50,8 @@
                                      EVOLUTION_MINOR_VERSION,
                                      EVOLUTION_PATCH_VERSION));
     
+    PyModule_AddObject(m, "EBookQuery", (PyObject *)&PyEBookQuery_Type);
+
     if (PyErr_Occurred())
         Py_FatalError("could not initialise module _ebook");
 }
Index: src/ebook-enums.c
===================================================================
--- src/ebook-enums.c	(revision 0)
+++ src/ebook-enums.c	(revision 0)
@@ -0,0 +1,178 @@
+#include <ebook-enums.h>
+
+/* Generated data (by glib-mkenums) */
+
+
+/* enumerations from "/usr/include/evolution-data-server-1.4/libebook/e-contact.h" */
+GType
+e_contact_field_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0) {
+    static const GEnumValue values[] = {
+      { E_CONTACT_UID, "E_CONTACT_UID", "uid" },
+      { E_CONTACT_FILE_AS, "E_CONTACT_FILE_AS", "file-as" },
+      { E_CONTACT_BOOK_URI, "E_CONTACT_BOOK_URI", "book-uri" },
+      { E_CONTACT_FULL_NAME, "E_CONTACT_FULL_NAME", "full-name" },
+      { E_CONTACT_GIVEN_NAME, "E_CONTACT_GIVEN_NAME", "given-name" },
+      { E_CONTACT_FAMILY_NAME, "E_CONTACT_FAMILY_NAME", "family-name" },
+      { E_CONTACT_NICKNAME, "E_CONTACT_NICKNAME", "nickname" },
+      { E_CONTACT_EMAIL_1, "E_CONTACT_EMAIL_1", "email-1" },
+      { E_CONTACT_EMAIL_2, "E_CONTACT_EMAIL_2", "email-2" },
+      { E_CONTACT_EMAIL_3, "E_CONTACT_EMAIL_3", "email-3" },
+      { E_CONTACT_EMAIL_4, "E_CONTACT_EMAIL_4", "email-4" },
+      { E_CONTACT_MAILER, "E_CONTACT_MAILER", "mailer" },
+      { E_CONTACT_ADDRESS_LABEL_HOME, "E_CONTACT_ADDRESS_LABEL_HOME", "address-label-home" },
+      { E_CONTACT_ADDRESS_LABEL_WORK, "E_CONTACT_ADDRESS_LABEL_WORK", "address-label-work" },
+      { E_CONTACT_ADDRESS_LABEL_OTHER, "E_CONTACT_ADDRESS_LABEL_OTHER", "address-label-other" },
+      { E_CONTACT_PHONE_ASSISTANT, "E_CONTACT_PHONE_ASSISTANT", "phone-assistant" },
+      { E_CONTACT_PHONE_BUSINESS, "E_CONTACT_PHONE_BUSINESS", "phone-business" },
+      { E_CONTACT_PHONE_BUSINESS_2, "E_CONTACT_PHONE_BUSINESS_2", "phone-business-2" },
+      { E_CONTACT_PHONE_BUSINESS_FAX, "E_CONTACT_PHONE_BUSINESS_FAX", "phone-business-fax" },
+      { E_CONTACT_PHONE_CALLBACK, "E_CONTACT_PHONE_CALLBACK", "phone-callback" },
+      { E_CONTACT_PHONE_CAR, "E_CONTACT_PHONE_CAR", "phone-car" },
+      { E_CONTACT_PHONE_COMPANY, "E_CONTACT_PHONE_COMPANY", "phone-company" },
+      { E_CONTACT_PHONE_HOME, "E_CONTACT_PHONE_HOME", "phone-home" },
+      { E_CONTACT_PHONE_HOME_2, "E_CONTACT_PHONE_HOME_2", "phone-home-2" },
+      { E_CONTACT_PHONE_HOME_FAX, "E_CONTACT_PHONE_HOME_FAX", "phone-home-fax" },
+      { E_CONTACT_PHONE_ISDN, "E_CONTACT_PHONE_ISDN", "phone-isdn" },
+      { E_CONTACT_PHONE_MOBILE, "E_CONTACT_PHONE_MOBILE", "phone-mobile" },
+      { E_CONTACT_PHONE_OTHER, "E_CONTACT_PHONE_OTHER", "phone-other" },
+      { E_CONTACT_PHONE_OTHER_FAX, "E_CONTACT_PHONE_OTHER_FAX", "phone-other-fax" },
+      { E_CONTACT_PHONE_PAGER, "E_CONTACT_PHONE_PAGER", "phone-pager" },
+      { E_CONTACT_PHONE_PRIMARY, "E_CONTACT_PHONE_PRIMARY", "phone-primary" },
+      { E_CONTACT_PHONE_RADIO, "E_CONTACT_PHONE_RADIO", "phone-radio" },
+      { E_CONTACT_PHONE_TELEX, "E_CONTACT_PHONE_TELEX", "phone-telex" },
+      { E_CONTACT_PHONE_TTYTDD, "E_CONTACT_PHONE_TTYTDD", "phone-ttytdd" },
+      { E_CONTACT_ORG, "E_CONTACT_ORG", "org" },
+      { E_CONTACT_ORG_UNIT, "E_CONTACT_ORG_UNIT", "org-unit" },
+      { E_CONTACT_OFFICE, "E_CONTACT_OFFICE", "office" },
+      { E_CONTACT_TITLE, "E_CONTACT_TITLE", "title" },
+      { E_CONTACT_ROLE, "E_CONTACT_ROLE", "role" },
+      { E_CONTACT_MANAGER, "E_CONTACT_MANAGER", "manager" },
+      { E_CONTACT_ASSISTANT, "E_CONTACT_ASSISTANT", "assistant" },
+      { E_CONTACT_HOMEPAGE_URL, "E_CONTACT_HOMEPAGE_URL", "homepage-url" },
+      { E_CONTACT_BLOG_URL, "E_CONTACT_BLOG_URL", "blog-url" },
+      { E_CONTACT_CATEGORIES, "E_CONTACT_CATEGORIES", "categories" },
+      { E_CONTACT_CALENDAR_URI, "E_CONTACT_CALENDAR_URI", "calendar-uri" },
+      { E_CONTACT_FREEBUSY_URL, "E_CONTACT_FREEBUSY_URL", "freebusy-url" },
+      { E_CONTACT_ICS_CALENDAR, "E_CONTACT_ICS_CALENDAR", "ics-calendar" },
+      { E_CONTACT_VIDEO_URL, "E_CONTACT_VIDEO_URL", "video-url" },
+      { E_CONTACT_SPOUSE, "E_CONTACT_SPOUSE", "spouse" },
+      { E_CONTACT_NOTE, "E_CONTACT_NOTE", "note" },
+      { E_CONTACT_IM_AIM_HOME_1, "E_CONTACT_IM_AIM_HOME_1", "im-aim-home-1" },
+      { E_CONTACT_IM_AIM_HOME_2, "E_CONTACT_IM_AIM_HOME_2", "im-aim-home-2" },
+      { E_CONTACT_IM_AIM_HOME_3, "E_CONTACT_IM_AIM_HOME_3", "im-aim-home-3" },
+      { E_CONTACT_IM_AIM_WORK_1, "E_CONTACT_IM_AIM_WORK_1", "im-aim-work-1" },
+      { E_CONTACT_IM_AIM_WORK_2, "E_CONTACT_IM_AIM_WORK_2", "im-aim-work-2" },
+      { E_CONTACT_IM_AIM_WORK_3, "E_CONTACT_IM_AIM_WORK_3", "im-aim-work-3" },
+      { E_CONTACT_IM_GROUPWISE_HOME_1, "E_CONTACT_IM_GROUPWISE_HOME_1", "im-groupwise-home-1" },
+      { E_CONTACT_IM_GROUPWISE_HOME_2, "E_CONTACT_IM_GROUPWISE_HOME_2", "im-groupwise-home-2" },
+      { E_CONTACT_IM_GROUPWISE_HOME_3, "E_CONTACT_IM_GROUPWISE_HOME_3", "im-groupwise-home-3" },
+      { E_CONTACT_IM_GROUPWISE_WORK_1, "E_CONTACT_IM_GROUPWISE_WORK_1", "im-groupwise-work-1" },
+      { E_CONTACT_IM_GROUPWISE_WORK_2, "E_CONTACT_IM_GROUPWISE_WORK_2", "im-groupwise-work-2" },
+      { E_CONTACT_IM_GROUPWISE_WORK_3, "E_CONTACT_IM_GROUPWISE_WORK_3", "im-groupwise-work-3" },
+      { E_CONTACT_IM_JABBER_HOME_1, "E_CONTACT_IM_JABBER_HOME_1", "im-jabber-home-1" },
+      { E_CONTACT_IM_JABBER_HOME_2, "E_CONTACT_IM_JABBER_HOME_2", "im-jabber-home-2" },
+      { E_CONTACT_IM_JABBER_HOME_3, "E_CONTACT_IM_JABBER_HOME_3", "im-jabber-home-3" },
+      { E_CONTACT_IM_JABBER_WORK_1, "E_CONTACT_IM_JABBER_WORK_1", "im-jabber-work-1" },
+      { E_CONTACT_IM_JABBER_WORK_2, "E_CONTACT_IM_JABBER_WORK_2", "im-jabber-work-2" },
+      { E_CONTACT_IM_JABBER_WORK_3, "E_CONTACT_IM_JABBER_WORK_3", "im-jabber-work-3" },
+      { E_CONTACT_IM_YAHOO_HOME_1, "E_CONTACT_IM_YAHOO_HOME_1", "im-yahoo-home-1" },
+      { E_CONTACT_IM_YAHOO_HOME_2, "E_CONTACT_IM_YAHOO_HOME_2", "im-yahoo-home-2" },
+      { E_CONTACT_IM_YAHOO_HOME_3, "E_CONTACT_IM_YAHOO_HOME_3", "im-yahoo-home-3" },
+      { E_CONTACT_IM_YAHOO_WORK_1, "E_CONTACT_IM_YAHOO_WORK_1", "im-yahoo-work-1" },
+      { E_CONTACT_IM_YAHOO_WORK_2, "E_CONTACT_IM_YAHOO_WORK_2", "im-yahoo-work-2" },
+      { E_CONTACT_IM_YAHOO_WORK_3, "E_CONTACT_IM_YAHOO_WORK_3", "im-yahoo-work-3" },
+      { E_CONTACT_IM_MSN_HOME_1, "E_CONTACT_IM_MSN_HOME_1", "im-msn-home-1" },
+      { E_CONTACT_IM_MSN_HOME_2, "E_CONTACT_IM_MSN_HOME_2", "im-msn-home-2" },
+      { E_CONTACT_IM_MSN_HOME_3, "E_CONTACT_IM_MSN_HOME_3", "im-msn-home-3" },
+      { E_CONTACT_IM_MSN_WORK_1, "E_CONTACT_IM_MSN_WORK_1", "im-msn-work-1" },
+      { E_CONTACT_IM_MSN_WORK_2, "E_CONTACT_IM_MSN_WORK_2", "im-msn-work-2" },
+      { E_CONTACT_IM_MSN_WORK_3, "E_CONTACT_IM_MSN_WORK_3", "im-msn-work-3" },
+      { E_CONTACT_IM_ICQ_HOME_1, "E_CONTACT_IM_ICQ_HOME_1", "im-icq-home-1" },
+      { E_CONTACT_IM_ICQ_HOME_2, "E_CONTACT_IM_ICQ_HOME_2", "im-icq-home-2" },
+      { E_CONTACT_IM_ICQ_HOME_3, "E_CONTACT_IM_ICQ_HOME_3", "im-icq-home-3" },
+      { E_CONTACT_IM_ICQ_WORK_1, "E_CONTACT_IM_ICQ_WORK_1", "im-icq-work-1" },
+      { E_CONTACT_IM_ICQ_WORK_2, "E_CONTACT_IM_ICQ_WORK_2", "im-icq-work-2" },
+      { E_CONTACT_IM_ICQ_WORK_3, "E_CONTACT_IM_ICQ_WORK_3", "im-icq-work-3" },
+      { E_CONTACT_REV, "E_CONTACT_REV", "rev" },
+      { E_CONTACT_NAME_OR_ORG, "E_CONTACT_NAME_OR_ORG", "name-or-org" },
+      { E_CONTACT_ADDRESS, "E_CONTACT_ADDRESS", "address" },
+      { E_CONTACT_ADDRESS_HOME, "E_CONTACT_ADDRESS_HOME", "address-home" },
+      { E_CONTACT_ADDRESS_WORK, "E_CONTACT_ADDRESS_WORK", "address-work" },
+      { E_CONTACT_ADDRESS_OTHER, "E_CONTACT_ADDRESS_OTHER", "address-other" },
+      { E_CONTACT_CATEGORY_LIST, "E_CONTACT_CATEGORY_LIST", "category-list" },
+      { E_CONTACT_PHOTO, "E_CONTACT_PHOTO", "photo" },
+      { E_CONTACT_LOGO, "E_CONTACT_LOGO", "logo" },
+      { E_CONTACT_NAME, "E_CONTACT_NAME", "name" },
+      { E_CONTACT_EMAIL, "E_CONTACT_EMAIL", "email" },
+      { E_CONTACT_IM_AIM, "E_CONTACT_IM_AIM", "im-aim" },
+      { E_CONTACT_IM_GROUPWISE, "E_CONTACT_IM_GROUPWISE", "im-groupwise" },
+      { E_CONTACT_IM_JABBER, "E_CONTACT_IM_JABBER", "im-jabber" },
+      { E_CONTACT_IM_YAHOO, "E_CONTACT_IM_YAHOO", "im-yahoo" },
+      { E_CONTACT_IM_MSN, "E_CONTACT_IM_MSN", "im-msn" },
+      { E_CONTACT_IM_ICQ, "E_CONTACT_IM_ICQ", "im-icq" },
+      { E_CONTACT_WANTS_HTML, "E_CONTACT_WANTS_HTML", "wants-html" },
+      { E_CONTACT_IS_LIST, "E_CONTACT_IS_LIST", "is-list" },
+      { E_CONTACT_LIST_SHOW_ADDRESSES, "E_CONTACT_LIST_SHOW_ADDRESSES", "list-show-addresses" },
+      { E_CONTACT_BIRTH_DATE, "E_CONTACT_BIRTH_DATE", "birth-date" },
+      { E_CONTACT_ANNIVERSARY, "E_CONTACT_ANNIVERSARY", "anniversary" },
+      { E_CONTACT_X509_CERT, "E_CONTACT_X509_CERT", "x509-cert" },
+      { E_CONTACT_FIELD_LAST, "E_CONTACT_FIELD_LAST", "field-last" },
+      { E_CONTACT_FIELD_FIRST, "E_CONTACT_FIELD_FIRST", "field-first" },
+      { E_CONTACT_LAST_SIMPLE_STRING, "E_CONTACT_LAST_SIMPLE_STRING", "last-simple-string" },
+      { E_CONTACT_FIRST_PHONE_ID, "E_CONTACT_FIRST_PHONE_ID", "first-phone-id" },
+      { E_CONTACT_LAST_PHONE_ID, "E_CONTACT_LAST_PHONE_ID", "last-phone-id" },
+      { E_CONTACT_FIRST_EMAIL_ID, "E_CONTACT_FIRST_EMAIL_ID", "first-email-id" },
+      { E_CONTACT_LAST_EMAIL_ID, "E_CONTACT_LAST_EMAIL_ID", "last-email-id" },
+      { E_CONTACT_FIRST_ADDRESS_ID, "E_CONTACT_FIRST_ADDRESS_ID", "first-address-id" },
+      { E_CONTACT_LAST_ADDRESS_ID, "E_CONTACT_LAST_ADDRESS_ID", "last-address-id" },
+      { E_CONTACT_FIRST_LABEL_ID, "E_CONTACT_FIRST_LABEL_ID", "first-label-id" },
+      { E_CONTACT_LAST_LABEL_ID, "E_CONTACT_LAST_LABEL_ID", "last-label-id" },
+      { 0, NULL, NULL }
+    };
+    etype = g_enum_register_static ("EContactField", values);
+  }
+  return etype;
+}
+GType
+e_contact_photo_type_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0) {
+    static const GEnumValue values[] = {
+      { E_CONTACT_PHOTO_TYPE_INLINED, "E_CONTACT_PHOTO_TYPE_INLINED", "inlined" },
+      { E_CONTACT_PHOTO_TYPE_URI, "E_CONTACT_PHOTO_TYPE_URI", "uri" },
+      { 0, NULL, NULL }
+    };
+    etype = g_enum_register_static ("EContactPhotoType", values);
+  }
+  return etype;
+}
+
+/* Generated data ends here */
+
+/* Generated data (by glib-mkenums) */
+
+
+/* enumerations from "/usr/include/evolution-data-server-1.4/libebook/e-book-query.h" */
+GType
+e_book_query_test_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0) {
+    static const GEnumValue values[] = {
+      { E_BOOK_QUERY_IS, "E_BOOK_QUERY_IS", "is" },
+      { E_BOOK_QUERY_CONTAINS, "E_BOOK_QUERY_CONTAINS", "contains" },
+      { E_BOOK_QUERY_BEGINS_WITH, "E_BOOK_QUERY_BEGINS_WITH", "begins-with" },
+      { E_BOOK_QUERY_ENDS_WITH, "E_BOOK_QUERY_ENDS_WITH", "ends-with" },
+      { 0, NULL, NULL }
+    };
+    etype = g_enum_register_static ("EBookQueryTest", values);
+  }
+  return etype;
+}
+
+/* Generated data ends here */
+
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 41)
+++ src/Makefile.am	(working copy)
@@ -32,10 +32,12 @@
 	evo-ebook-environment.c \
 	evo-contact.c \
 	evo-addressbook.c \
+	ebook-enums.c \
 	override_common.h \
 	evo-ebook-environment.h \
 	evo-contact.h \
-	evo-addressbook.h
+	evo-addressbook.h \
+	ebook-enums.h
 
 
 nodist_ecal_la_SOURCES = ecal.c
Index: src/ebook-enums.h
===================================================================
--- src/ebook-enums.h	(revision 0)
+++ src/ebook-enums.h	(revision 0)
@@ -0,0 +1,41 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EVO_ENUMS_H
+#define EVO_ENUMS_H
+
+#include <libebook/e-contact.h>
+#include <libebook/e-book-query.h>
+
+/* Generated data (by glib-mkenums) */
+
+/* enumerations from "/usr/include/evolution-data-server-1.4/libebook/e-contact.h" */
+GType e_contact_field_get_type (void) G_GNUC_CONST;
+#define E_TYPE_CONTACT_FIELD (e_contact_field_get_type())
+GType e_contact_photo_type_get_type (void) G_GNUC_CONST;
+#define E_TYPE_CONTACT_PHOTO_TYPE (e_contact_photo_type_get_type())
+
+/* Generated data ends here */
+
+/* Generated data (by glib-mkenums) */
+
+/* enumerations from "/usr/include/evolution-data-server-1.4/libebook/e-book-query.h" */
+GType e_book_query_test_get_type (void) G_GNUC_CONST;
+#define E_TYPE_BOOK_QUERY_TEST (e_book_query_test_get_type())
+
+/* Generated data ends here */
+
+#endif
Index: src/ebook.override
===================================================================
--- src/ebook.override	(revision 41)
+++ src/ebook.override	(working copy)
@@ -10,6 +10,7 @@
 #include "evo-ebook-environment.h"
 #include "evo-contact.h"
 #include "evo-addressbook.h"
+#include "ebook-enums.h"
 
 static PyObject *
 _helper_wrap_glist_of_evo_locations(GList *locations)
@@ -44,7 +45,488 @@
 	return result;
 }
 
+/* EBookQuery */
+
+typedef struct {
+	PyObject_HEAD
+	EBookQuery *query;
+} PyEBookQuery;
+
+/* Forward function declarations */
+static PyObject *pyebook_query_new(EBookQuery *query);
+static void pyebook_query_dealloc(PyEBookQuery *self);
+static PyObject *pyebook_query_str(PyEBookQuery *self);
+
+static PyObject *pyebook_query_from_string(PyEBookQuery *self,
+                                           PyObject *args,
+                                           PyObject *kwargs);
+static PyObject *pyebook_query_field_exists(PyEBookQuery *self,
+                                            PyObject *args,
+                                            PyObject *kwargs);
+static PyObject *pyebook_query_vcard_field_exists(PyEBookQuery *self,
+                                                  PyObject *args,
+                                                  PyObject *kwargs);
+static PyObject *pyebook_query_field_test(PyEBookQuery *self,
+                                          PyObject *args,
+                                          PyObject *kwargs);
+static PyObject *pyebook_query_any_field_contains(PyEBookQuery *self,
+                                                  PyObject *args,
+                                                  PyObject *kwargs);
+static PyObject *pyebook_query_and(PyEBookQuery *self,
+                                   PyObject *args,
+                                   PyObject *kwargs);
+static PyObject *pyebook_query_or(PyEBookQuery *self,
+                                   PyObject *args,
+                                   PyObject *kwargs);
+static PyObject *pyebook_query_not(PyEBookQuery *self,
+                                   PyObject *args);
+static PyObject *pyebook_query_copy(PyEBookQuery *self,
+                                    PyObject *args);
+
+static PyMethodDef PyEBookQuery_methods[] = {
+    {"from_string", (PyCFunctionWithKeywords)pyebook_query_from_string,
+        METH_KEYWORDS | METH_VARARGS | METH_CLASS,
+        "Creates a new query from a string."},
+    {"field_exists", (PyCFunctionWithKeywords)pyebook_query_field_exists,
+        METH_KEYWORDS | METH_VARARGS | METH_CLASS,
+        "Replaces this query with a new query to check if the given \
+        field exists"},
+    {"vcard_field_exists",
+        (PyCFunctionWithKeywords)pyebook_query_vcard_field_exists,
+        METH_KEYWORDS | METH_VARARGS | METH_CLASS,
+        "Replaces this query with a new query to check if the given \
+        vcard field exists"},
+    {"field_test", (PyCFunctionWithKeywords)pyebook_query_field_test,
+        METH_KEYWORDS | METH_VARARGS | METH_CLASS,
+        "Replaces this query with a new query with a given test."},
+    {"any_field_contains",
+        (PyCFunctionWithKeywords)pyebook_query_any_field_contains,
+        METH_KEYWORDS | METH_VARARGS | METH_CLASS,
+        "Replaces this query with a new 'generic' query."},
+    {"_and",
+        (PyCFunctionWithKeywords)pyebook_query_and,
+        METH_KEYWORDS | METH_VARARGS,
+        "Creates a new query with a 'and' operation with the given \
+        query list and this query."},
+     {"_or",
+        (PyCFunctionWithKeywords)pyebook_query_or,
+        METH_KEYWORDS | METH_VARARGS,
+        "Creates a new querywith a 'or' operation with the given \
+        query list and this query."},
+     {"_not",
+     (PyCFunction)pyebook_query_not,
+        METH_NOARGS,
+        "Creates a new query with a 'not' operation with this query."},
+     {"copy",
+     (PyCFunction)pyebook_query_copy,
+        METH_NOARGS,
+        "Copies this query."},
+   {NULL}
+};
+
+PyTypeObject PyEBookQuery_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,                  /* ob_size */
+	"ebook.EBookQuery",          /* tp_name */
+	sizeof(PyEBookQuery),       /* tp_basicsize */
+	0,                  /* tp_itemsize */
+	/* methods */
+	(destructor)pyebook_query_dealloc,   /* tp_dealloc */
+	(printfunc)0,           /* tp_print */
+	(getattrfunc)0,   /* tp_getattr */
+	(setattrfunc)0,         /* tp_setattr */
+	(cmpfunc)0,  /* tp_compare */
+	(reprfunc)0,            /* tp_repr */
+	0,                  /* tp_as_number */
+	0,                  /* tp_as_sequence */
+	0,                  /* tp_as_mapping */
+	(hashfunc)0,    /* tp_hash */
+	(ternaryfunc)0,         /* tp_call */
+	pyebook_query_str,            /* tp_str */
+	(getattrofunc)0,            /* tp_getattro */
+	(setattrofunc)0,            /* tp_setattro */
+	0,                  /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,         /* tp_flags */
+	NULL, /* Documentation string */
+	(traverseproc)0,            /* tp_traverse */
+	(inquiry)0,             /* tp_clear */
+	(richcmpfunc)0,         /* tp_richcompare */
+	0,                  /* tp_weaklistoffset */
+	(getiterfunc)0,         /* tp_iter */
+	(iternextfunc)0,            /* tp_iternext */
+	PyEBookQuery_methods,       /* tp_methods */
+	0,                  /* tp_members */
+	0,       /* tp_getset */
+	(PyTypeObject *)0,          /* tp_base */
+	(PyObject *)0,          /* tp_dict */
+	0,                  /* tp_descr_get */
+	0,                  /* tp_descr_set */
+	0,                  /* tp_dictoffset */
+	(initproc)0,            /* tp_init */
+	(allocfunc)0,           /* tp_alloc */
+	(newfunc)0,             /* tp_new */
+	0,                  /* tp_free */
+	(inquiry)0,             /* tp_is_gc */
+	(PyObject *)0,          /* tp_bases */
+};
+
+static PyObject *
+pyebook_query_new(EBookQuery *query)
+{
+	PyEBookQuery *self;
+
+	self = (PyEBookQuery *)PyObject_NEW(PyEBookQuery, &PyEBookQuery_Type);
+
+	if (self == NULL)
+		return NULL;
+
+	self->query = query;
+
+	return (PyObject *)self;
+}
+
+static void
+pyebook_query_dealloc(PyEBookQuery *self)
+{
+	if (self == NULL)
+		return;
+
+    if (self->query != NULL)
+    	e_book_query_unref(self->query);
+    PyObject_DEL(self);
+}
+
+static PyObject *
+pyebook_query_str(PyEBookQuery *self){
+
+    char *repr = NULL;
+    PyObject *ret;
+
+    if (self->query != NULL)
+        repr = e_book_query_to_string(self->query);
+
+    ret = PyString_FromString( repr != NULL ? repr : "<Uninitialized>");
+
+    if (repr != NULL)
+        free(repr);
+
+    return ret;
+}
+
+static PyObject *
+pyebook_query_from_string(PyEBookQuery *self,
+                          PyObject *args,
+                          PyObject *kwargs)
+{
+    static char *kwlist[] = { "query", NULL };
+    char *query;
+    EBookQuery *new_query;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &query))
+        return NULL;
+
+    new_query = e_book_query_from_string(query);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_field_exists(PyEBookQuery *self,
+                           PyObject *args,
+                           PyObject *kwargs)
+{
+    static char *kwlist[] = { "field", NULL };
+    PyObject *py_type;
+    EContactField field;
+    EBookQuery *new_query;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &py_type))
+        return NULL;
+
+    if(pyg_enum_get_value(E_TYPE_CONTACT_FIELD, py_type, (gint *)&field))
+        return NULL;
+
+    new_query = e_book_query_field_exists(field);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_vcard_field_exists(PyEBookQuery *self,
+                                 PyObject *args,
+                                 PyObject *kwargs)
+{
+    static char *kwlist[] = { "field", NULL };
+    char *field;
+    EBookQuery *new_query;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &field))
+        return NULL;
+
+    new_query = e_book_query_vcard_field_exists(field);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_field_test(PyEBookQuery *self,
+                         PyObject *args,
+                         PyObject *kwargs)
+{
+    static char *kwlist[] = { "field", "test", "value", NULL };
+    PyObject *py_field;
+    PyObject *py_test;
+    EContactField field;
+    EBookQueryTest test;
+    char *value;
+    EBookQuery *new_query;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOs", kwlist,
+                                     &py_field, &py_test, &value))
+        return NULL;
+
+    if(pyg_enum_get_value(E_TYPE_CONTACT_FIELD, py_field, (gint *)&field))
+        return NULL;
+
+    if(pyg_enum_get_value(E_TYPE_BOOK_QUERY_TEST, py_test, (gint *)&test))
+        return NULL;
+
+    new_query = e_book_query_field_test(field, test, value);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_any_field_contains(PyEBookQuery *self,
+                                 PyObject *args,
+                                 PyObject *kwargs)
+{
+    static char *kwlist[] = { "field", NULL };
+    char *field;
+    EBookQuery *new_query;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &field))
+        return NULL;
+
+    new_query = e_book_query_any_field_contains(field);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_and(PyEBookQuery *self,
+                  PyObject *args,
+                  PyObject *kwargs)
+{
+    static char *kwlist[] = { "queries", NULL };
+    PyObject *list;
+    int size;
+    int i;
+    int has_self = 0;
+    EBookQuery **queries = NULL;
+    EBookQuery *new_query = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist,
+                                     &PyList_Type, &list))
+        return NULL;
+
+    size = PyList_Size(list);
+
+    if (size == 0){
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    if (self->query != NULL) {
+        queries = (EBookQuery **)malloc(sizeof(EBookQuery *)*(size+1));
+        queries[0] = self->query;
+        has_self = 1;
+    } else {
+        queries = (EBookQuery **)malloc(sizeof(EBookQuery *)*(size));
+    }
+
+    for (i = 0; i < size; i++){
+        PyEBookQuery *query;
+
+        /* FIXME Check for EBookQuery type */
+        query = (PyEBookQuery *) PyList_GetItem(list, i);
+
+        queries[i+has_self] = query->query;
+    }
+
+    new_query = e_book_query_and(size+has_self, queries, FALSE);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_or(PyEBookQuery *self,
+                 PyObject *args,
+                 PyObject *kwargs)
+{
+    static char *kwlist[] = { "queries", NULL };
+    PyObject *list;
+    int size;
+    int i;
+    int has_self = 0;
+    EBookQuery **queries = NULL;
+    EBookQuery *new_query = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist,
+                                     &PyList_Type, &list))
+        return NULL;
+
+    size = PyList_Size(list);
+
+    if (size == 0){
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    if (self->query != NULL) {
+        queries = (EBookQuery **)malloc(sizeof(EBookQuery *)*(size+1));
+        queries[0] = self->query;
+        has_self = 1;
+    } else {
+        queries = (EBookQuery **)malloc(sizeof(EBookQuery *)*(size));
+    }
+
+    for (i = 0; i < size; i++){
+        PyEBookQuery *query;
+
+        /* FIXME Check for EBookQuery type */
+        query = (PyEBookQuery *) PyList_GetItem(list, i);
+
+        queries[i+has_self] = query->query;
+    }
+
+    new_query = e_book_query_or(size+has_self, queries, FALSE);
+
+    return pyebook_query_new(new_query);
+}
+
+static PyObject *
+pyebook_query_not(PyEBookQuery *self,
+                  PyObject *args)
+{
+    EBookQuery *new_query = NULL;
+
+    if (self->query != NULL)
+        new_query = e_book_query_not(self->query, FALSE);
+
+    return pyebook_query_new(new_query);
+}
+
+
+static PyObject *
+pyebook_query_copy(PyEBookQuery *self,
+                   PyObject *args)
+{
+	return pyebook_query_new(e_book_query_copy(self->query));
+}
+
+/*** Types, helper functions and callbacks for EBookView ***/
+
+/* Struct used to pack data passed to EBookView signals */
+struct bookview_cb_t{
+    PyObject *(*converter)(gpointer);
+    PyObject *callback;
+    PyObject *extra_data;
+};
+
+static PyObject *
+glist_to_pylist(GList *list, PyObject *(*converter)(gpointer))
+{
+    PyObject *pylist;
+    GList *node;
+    int size;
+    int i;
+
+    size = g_list_length(list);
+    pylist = PyList_New(size);
+    node = list;
+
+    for (i=0; i < size; i++){
+        PyObject *pyobj;
+
+        pyobj = converter(node->data);
+        PyList_SetItem(pylist, i, pyobj);
+
+        node = node->next;
+    }
+
+    return pylist;
+}
+
+PyObject *econtact_to_pycontact(EContact *contact)
+{
+    return pygobject_new(G_OBJECT(contact));
+}
+
+/* wrapper for callbacks that receive a GList as parameter */
+static void
+contacts_list_cb(EBookView *ebookview, GList *contacts, gpointer user_data)
+{
+    PyObject *list;
+    PyObject *pybookview;
+    PyObject *extra_args;
+    PyObject *callback;
+    PyObject *arguments;
+    PyObject *result;
+    struct bookview_cb_t *data;
+    int i;
+    int extra_size;
+
+    pybookview = pygobject_new(ebookview);
+    if (pybookview == NULL){
+    }
+
+    data = (struct bookview_cb_t*)user_data;
+
+    callback = data->callback;
+    extra_args = data->extra_data;
+
+    list = glist_to_pylist(contacts, data->converter);
+
+    if (extra_args != NULL){
+        extra_size = PyTuple_Size(extra_args);
+    } else {
+        extra_size = 0;
+    }
+
+    arguments = PyTuple_New(extra_size+2);
+
+    Py_INCREF(pybookview);
+    PyTuple_SetItem(arguments, 0, pybookview);
+    Py_INCREF(list);
+    PyTuple_SetItem(arguments, 1, list);
+
+    for (i = 2; i < extra_size+2; i++) {
+        PyObject *obj;
+
+        obj = PyTuple_GetItem(extra_args, i-2);
+        Py_INCREF(obj);
+        PyTuple_SetItem(arguments, i, obj);
+    }
+
+    result = PyObject_CallObject(callback, arguments);
+
+    Py_XDECREF(result);
+    Py_XDECREF(arguments);
+    Py_XDECREF(pybookview);
+    Py_XDECREF(list); /* Will decref its childs too? */
+
+    return;
+}
+
 %%
+init
+	PyEBookQuery_Type.tp_alloc = PyType_GenericAlloc;
+	PyEBookQuery_Type.tp_new = PyType_GenericNew;
+	if (PyType_Ready(&PyEBookQuery_Type) < 0)
+		return;
+
+%%
 modulename ebook
 %%
 import gobject.GObject as PyGObject_Type  
@@ -169,4 +651,271 @@
 
     return PyLong_FromLong((long) seconds);
 }
+%%
+override e_book_commit_contact kwargs
+static PyObject *
+_wrap_e_book_commit_contact(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"contact", NULL};
+    PyGObject *pycontact;
+    PyObject *pyret;
+    EBook *book;
+    EContact *contact;
+    gboolean ret;
 
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:EBook.commit_contact",
+                                     kwlist, &PyEContact_Type,
+                                     (PyObject **)&pycontact)){
+        return NULL;
+    }
+
+    contact = (EContact *)pycontact->obj;
+    book = (EBook *)self->obj;
+
+    ret = e_book_commit_contact(book, contact, NULL);
+
+    if (ret) {
+        pyret = Py_True;
+    } else {
+        pyret = Py_False;
+    }
+
+    Py_XINCREF(pyret);
+    return pyret;
+}
+%%
+override e_book_get_book_view kwargs
+static PyObject *
+_wrap_e_book_get_book_view(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"query", "fields", "max", NULL};
+    int results = 0;
+    PyObject *pyfields = NULL;
+    GList *fields = NULL;
+    PyObject *query = NULL;
+    PyObject *ret = NULL;
+    int cret;
+    EBookView *view = NULL;
+    EBookQuery *equery = NULL;
+    GError *err = NULL;
+
+    if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O!i:EBook.get_book_view",
+                                    kwlist, &PyEBookQuery_Type, &query, &PyList_Type, &pyfields,
+                                    &results))
+        return NULL;
+
+    if (pyfields != NULL) {
+        /* Translating to glist */
+        int len;
+        int i;
+
+        len = PyList_Size(pyfields);
+
+        for(i = 0; i < len; i++){
+            PyObject *item;
+            EContactField field;
+            char *name;
+            int size;
+
+            item = PyList_GetItem(pyfields, i);
+
+            pyg_enum_get_value(E_TYPE_CONTACT_FIELD, item, (gint *)&field);
+            name = e_contact_field_name(field);
+            fields = g_list_append(fields, name);
+        }
+    }
+
+    equery = ((PyEBookQuery *)query)->query;
+    cret = e_book_get_book_view(E_BOOK(self->obj), equery, fields, results, &view, &err);
+
+    /* Create the bookview object */
+    ret = pygobject_new(G_OBJECT(view));
+
+    /* e_book_query_unref(equery); The book view gets the ownership of the ref */
+    if (fields != NULL)
+        g_list_free(fields);
+
+    Py_XINCREF(ret);
+    return ret;
+}
+%%
+override e_book_view_set_contacts_added_cb kwargs
+static PyObject *
+_wrap_e_book_view_set_contacts_added_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    PyObject *callback;
+    PyObject *extra_args;
+    struct bookview_cb_t *data;
+    int len;
+    guint result;
+
+    len = PyTuple_Size(args);
+    if (len < 1){
+        PyErr_SetString(PyExc_TypeError,
+                        "EBookView.set_contacts_added_cb requires at least one argument");
+        return NULL;
+    }
+
+    data = g_new(struct bookview_cb_t, 1);
+
+    callback = PyTuple_GetItem(args, 0);
+
+    if(!PyCallable_Check(callback)){
+        PyErr_SetString(PyExc_TypeError, "callback must be callable");
+        return NULL;
+    }
+
+    Py_XINCREF(callback);
+    data->callback = callback;
+
+    if (len > 1){
+        extra_args = PySequence_GetSlice(args, 1, len);
+    } else {
+        extra_args = NULL;
+    }
+
+    data->extra_data = extra_args;
+    data->converter = econtact_to_pycontact;
+
+    result = g_signal_connect(self->obj, "contacts-added", contacts_list_cb, data);
+
+    return PyInt_FromLong(result);
+}
+%%
+override e_book_view_remove_contacts_added_cb kwargs
+static PyObject *
+_wrap_e_book_view_remove_contacts_added_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] ={"handler_id", NULL};
+    int handler;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &handler)) {
+        return NULL;
+    }
+
+    g_signal_handler_disconnect(self->obj, handler);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+override e_book_view_set_contacts_changed_cb kwargs
+static PyObject *
+_wrap_e_book_view_set_contacts_changed_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    PyObject *callback;
+    PyObject *extra_args;
+    struct bookview_cb_t *data;
+    int len;
+    guint result;
+
+    len = PyTuple_Size(args);
+    if (len < 1){
+        PyErr_SetString(PyExc_TypeError,
+                        "EBookView.set_contacts_added_cb requires at least one argument");
+        return NULL;
+    }
+
+    data = g_new(struct bookview_cb_t, 1);
+
+    callback = PyTuple_GetItem(args, 0);
+
+    if(!PyCallable_Check(callback)){
+        PyErr_SetString(PyExc_TypeError, "callback must be callable");
+        return NULL;
+    }
+
+    Py_XINCREF(callback);
+    data->callback = callback;
+
+    if (len > 1){
+        extra_args = PySequence_GetSlice(args, 1, len);
+    } else {
+        extra_args = NULL;
+    }
+
+    data->extra_data = extra_args;
+    data->converter = econtact_to_pycontact;
+
+    result = g_signal_connect(self->obj, "contacts-changed", contacts_list_cb, data);
+
+    return PyInt_FromLong(result);
+}
+%%
+override e_book_view_remove_contacts_changed_cb kwargs
+static PyObject *
+_wrap_e_book_view_remove_contacts_changed_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] ={"handler_id", NULL};
+    int handler;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &handler)) {
+        return NULL;
+    }
+
+    g_signal_handler_disconnect(self->obj, handler);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+override e_book_view_set_contacts_removed_cb kwargs
+static PyObject *
+_wrap_e_book_view_set_contacts_removed_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    PyObject *callback;
+    PyObject *extra_args;
+    struct bookview_cb_t *data;
+    int len;
+    guint result;
+
+    len = PyTuple_Size(args);
+    if (len < 1){
+        PyErr_SetString(PyExc_TypeError,
+                        "EBookView.set_contacts_removed_cb requires at least one argument");
+        return NULL;
+    }
+
+    data = g_new(struct bookview_cb_t, 1);
+
+    callback = PyTuple_GetItem(args, 0);
+
+    if(!PyCallable_Check(callback)){
+        PyErr_SetString(PyExc_TypeError, "callback must be callable");
+        return NULL;
+    }
+
+    Py_XINCREF(callback);
+    data->callback = callback;
+
+    if (len > 1){
+        extra_args = PySequence_GetSlice(args, 1, len);
+    } else {
+        extra_args = NULL;
+    }
+
+    data->extra_data = extra_args;
+    data->converter = PyString_FromString;
+
+    result = g_signal_connect(self->obj, "contacts-removed", contacts_list_cb, data);
+
+    return PyInt_FromLong(result);
+}
+%%
+override e_book_view_remove_contacts_removed_cb kwargs
+static PyObject *
+_wrap_e_book_view_remove_contacts_removed_cb(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] ={"handler_id", NULL};
+    int handler;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &handler)) {
+        return NULL;
+    }
+
+    g_signal_handler_disconnect(self->obj, handler);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]