soylent r280 - in branches/libsoylent-v0.4.0: . docs docs/reference docs/reference/libsoylent libsoylent libsoylent/example libsoylent/test m4



Author: svenp
Date: Tue Aug 12 12:53:27 2008
New Revision: 280
URL: http://svn.gnome.org/viewvc/soylent?rev=280&view=rev

Log:
merged libsoylent v0.4.0 branch with newest version of libsoylent

Added:
   branches/libsoylent-v0.4.0/docs/   (props changed)
      - copied from r279, /trunk/docs/
   branches/libsoylent-v0.4.0/libsoylent/example/   (props changed)
      - copied from r279, /trunk/libsoylent/example/
   branches/libsoylent-v0.4.0/libsoylent/generate_marshallers
      - copied unchanged from r279, /trunk/libsoylent/generate_marshallers
   branches/libsoylent-v0.4.0/libsoylent/marshal.list
      - copied unchanged from r279, /trunk/libsoylent/marshal.list
   branches/libsoylent-v0.4.0/libsoylent/sl-attribute-eds.c
      - copied unchanged from r279, /trunk/libsoylent/sl-attribute-eds.c
   branches/libsoylent-v0.4.0/libsoylent/sl-attribute-eds.h
      - copied unchanged from r279, /trunk/libsoylent/sl-attribute-eds.h
   branches/libsoylent-v0.4.0/libsoylent/sl-attribute.c
      - copied unchanged from r279, /trunk/libsoylent/sl-attribute.c
   branches/libsoylent-v0.4.0/libsoylent/sl-attribute.h
      - copied unchanged from r279, /trunk/libsoylent/sl-attribute.h
   branches/libsoylent-v0.4.0/libsoylent/sl-attributes.c
      - copied unchanged from r279, /trunk/libsoylent/sl-attributes.c
   branches/libsoylent-v0.4.0/libsoylent/sl-attributes.h
      - copied unchanged from r279, /trunk/libsoylent/sl-attributes.h
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-eds.c
      - copied unchanged from r279, /trunk/libsoylent/sl-entity-eds.c
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-eds.h
      - copied unchanged from r279, /trunk/libsoylent/sl-entity-eds.h
   branches/libsoylent-v0.4.0/libsoylent/sl-entity.c
      - copied unchanged from r279, /trunk/libsoylent/sl-entity.c
   branches/libsoylent-v0.4.0/libsoylent/sl-entity.h
      - copied unchanged from r279, /trunk/libsoylent/sl-entity.h
   branches/libsoylent-v0.4.0/libsoylent/sl-marshal.c
      - copied unchanged from r279, /trunk/libsoylent/sl-marshal.c
   branches/libsoylent-v0.4.0/libsoylent/sl-marshal.h
      - copied unchanged from r279, /trunk/libsoylent/sl-marshal.h
   branches/libsoylent-v0.4.0/libsoylent/sl-mutual-inclusion.h
      - copied unchanged from r279, /trunk/libsoylent/sl-mutual-inclusion.h
Removed:
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler-eds.c
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler-eds.h
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler-file.c
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler-file.h
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler.c
   branches/libsoylent-v0.4.0/libsoylent/sl-entity-handler.h
Modified:
   branches/libsoylent-v0.4.0/   (props changed)
   branches/libsoylent-v0.4.0/Makefile.am
   branches/libsoylent-v0.4.0/configure.ac
   branches/libsoylent-v0.4.0/docs/reference/   (props changed)
   branches/libsoylent-v0.4.0/docs/reference/libsoylent/   (props changed)
   branches/libsoylent-v0.4.0/libsoylent/Makefile.am
   branches/libsoylent-v0.4.0/libsoylent/NEWS
   branches/libsoylent-v0.4.0/libsoylent/README
   branches/libsoylent-v0.4.0/libsoylent/sl-book.c
   branches/libsoylent-v0.4.0/libsoylent/sl-book.h
   branches/libsoylent-v0.4.0/libsoylent/sl-group.c
   branches/libsoylent-v0.4.0/libsoylent/sl-group.h
   branches/libsoylent-v0.4.0/libsoylent/sl-person.c
   branches/libsoylent-v0.4.0/libsoylent/sl-person.h
   branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.c
   branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.h
   branches/libsoylent-v0.4.0/libsoylent/soylent.c
   branches/libsoylent-v0.4.0/libsoylent/soylent.h
   branches/libsoylent-v0.4.0/libsoylent/test/test-book.c
   branches/libsoylent-v0.4.0/libsoylent/test/test-playground.c
   branches/libsoylent-v0.4.0/libsoylent/test/test.c
   branches/libsoylent-v0.4.0/libsoylent/test/test.h
   branches/libsoylent-v0.4.0/m4/   (props changed)

Modified: branches/libsoylent-v0.4.0/Makefile.am
==============================================================================
--- branches/libsoylent-v0.4.0/Makefile.am	(original)
+++ branches/libsoylent-v0.4.0/Makefile.am	Tue Aug 12 12:53:27 2008
@@ -4,7 +4,7 @@
 SUBDIRS = src data
 
 if ENABLE_LIBSOYLENT
-SUBDIRS += libsoylent
+SUBDIRS += libsoylent docs
 endif
 
 EXTRA_DIST =
@@ -30,3 +30,6 @@
 	fi
 
 FORCE:
+
+# add generation of documentation to distcheck
+DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc

Modified: branches/libsoylent-v0.4.0/configure.ac
==============================================================================
--- branches/libsoylent-v0.4.0/configure.ac	(original)
+++ branches/libsoylent-v0.4.0/configure.ac	Tue Aug 12 12:53:27 2008
@@ -7,7 +7,7 @@
 m4_define(soylent_major_minor, soylent_major_version.soylent_minor_version)
 
 m4_define(libsoylent_major_version, 0)
-m4_define(libsoylent_minor_version, 2)
+m4_define(libsoylent_minor_version, 4)
 m4_define(libsoylent_micro_version, 0)
 m4_define(libsoylent_version, libsoylent_major_version.libsoylent_minor_version.libsoylent_micro_version)
 
@@ -27,6 +27,8 @@
 
 AM_PROG_CC_C_O
 
+GTK_DOC_CHECK(1.9)
+
 dnl Soylent-specific macros
 
 AC_DEFUN([SOYLENT_RELEASE_CHECK],
@@ -116,6 +118,12 @@
 		glib-2.0
 		libebook-1.2
 	])
+
+  PKG_CHECK_MODULES(EXAMPLE,
+  [
+    glib-2.0
+    libebook-1.2
+  ])
 	
 	AC_DEFINE(ENABLE_LIBSOYLENT, 1, [Build libsoylent])
 fi
@@ -126,6 +134,8 @@
 AC_SUBST(LIBSOYLENT_LIBS)
 AC_SUBST(TEST_CFLAGS)
 AC_SUBST(TEST_LIBS)
+AC_SUBST(EXAMPLE_CFLAGS)
+AC_SUBST(EXAMPLE_LIBS)
 
 AC_DEFINE(LIBSOYLENT_VERSION, libsoylent_version, [libsoylent version])
 
@@ -174,6 +184,10 @@
   src/Makefile
   libsoylent/Makefile
   libsoylent/test/Makefile
+  libsoylent/example/Makefile
+  docs/Makefile
+  docs/reference/Makefile
+  docs/reference/libsoylent/Makefile
 ])
 
 AC_OUTPUT

Modified: branches/libsoylent-v0.4.0/libsoylent/Makefile.am
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/Makefile.am	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/Makefile.am	Tue Aug 12 12:53:27 2008
@@ -1,6 +1,6 @@
 #
 
-SUBDIRS = . test
+SUBDIRS = . test example
 
 lib_LTLIBRARIES = libsoylent.la
 
@@ -8,23 +8,28 @@
 
 libsoylent_la_SOURCES = \
 	soylent.h \
+  sl-mutual-inclusion.h \
 	sl-entity.h \
-	sl-entity-handler.h \
-	sl-entity-handler-eds.h \
-	sl-entity-handler-file.h \
-	sl-book.h \
-	sl-group.h \
-	sl-person.h \
-	sl-priv-util.h \
-	soylent.c \
-	sl-entity.c \
-	sl-entity-handler.c \
-	sl-entity-handler-eds.c \
-	sl-entity-handler-file.c \
-	sl-book.c \
-	sl-group.c \
-	sl-person.c \
-	sl-priv-util.c
+  sl-entity-eds.h \
+  sl-attribute.h \
+  sl-attribute-eds.h \
+  sl-attributes.h \
+  sl-book.h \
+  sl-group.h \
+  sl-person.h \
+  sl-priv-util.h \
+  sl-marshal.h \
+  soylent.c \
+  sl-entity.c \
+  sl-entity-eds.c \
+  sl-attribute.c \
+  sl-attribute-eds.c \
+  sl-attributes.c \
+  sl-book.c \
+  sl-group.c \
+  sl-person.c \
+  sl-priv-util.c \
+  sl-marshal.c
 
 libsoylent_la_CFLAGS = $(LIBSOYLENT_CFLAGS) $(WARN_CFLAGS)
 libsoylent_la_LIBADD = $(LIBSOYLENT_LIBS)

Modified: branches/libsoylent-v0.4.0/libsoylent/NEWS
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/NEWS	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/NEWS	Tue Aug 12 12:53:27 2008
@@ -1,3 +1,57 @@
+=== 2008.08.12: libsoylent v0.4.0 "small step, giant leap" ===
+
+Let me present you the newest version of libsoylent: 0.4.0. Three weeks of hard
+work went into this release, and in fact so much was added and changed that we
+decided to skip a version-number. Sorry 0.3.0.
+
+So, what's in it? More or less a complete people-management-library. Our goal
+was to create a simple-yet-powerful API that "just works". Hopefully we managed
+that. If you have no clear picture of what libsoylent is or just want to know
+more about it, look at the examples we've put up on the libsoylent-page [1].
+
+What comes next? Because the library is that new and fresh, much testing will
+be needed. If you want to help, just play around with libsoylent and report
+bugs that you may encounter to our mailinglist. Thanks! Besides, next to the
+need of more documentation and polishing, here is a list of features that will
+follow in the next releases:
+ * live-attributes (e.g. online-status)
+ * communication (launch applications for chat / mail etc.)
+ * address-book searching (atm you can only get all people)
+ * people association / merging
+
+Please leave a comment on my blog [2] if you have thoughts, ideas, criticism,
+feature-requests or suggestions for changing something. Just let us hear your
+opinion.
+
+Anyway, if you're working on something that needs people-functionality, why not
+give libsoylent a try?
+
+[1] http://live.gnome.org/Soylent/libsoylent#head-350076c20ead379a4d797b273ff4db09e67c22ab
+[2] http://www.kalterregen.de/blog/
+
+--- Changes ---
+
+ * creating and modifying attributes works
+ * adding / removing attributes to / from people works
+ * attribute-mapping (for C runtime-types) implemented
+ * attribute-system (definition, cleanup and to-string functionality)
+   implemented
+ * changes to people can be commited
+ * loading people from the addressbook implemented
+ * signals for SlBook, SlPerson and SlAttribute implemented
+ * integrated gtk-doc
+ * added a bunch of documentation
+ * added more tests
+ * added example-code (three examples)
+ * revised architecture
+ * a lot of internal-code improvements
+ * fixed a bunch of bugs
+ * added debugging functions
+ * a lot of polishing was done (code-cleanup, convinience functions and macros
+   etc.)
+
+--------------------------------------------------------------------------------
+
 === 2008.07.23: libsoylent v0.2.0 "management qualities" ===
 
 The second release features the basic functionality one would expect from a

Modified: branches/libsoylent-v0.4.0/libsoylent/README
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/README	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/README	Tue Aug 12 12:53:27 2008
@@ -1,9 +1,9 @@
 === libsoylent ===
 
 libsoylent provides a convinient way to manage people and information associated
-with them. Features are a system-wide addressbook, arbitrary people and group
-attributes, static (e.g. name) and dynamic (e.g. online-status) information,
-etc. This comes in the form of a clean object-orientated API.
+with them. Features are a system-wide addressbook, arbitrary people attributes,
+static (e.g. name) and dynamic (e.g. online-status) information, etc. This comes
+in the form of a clean object-orientated API.
 
 More information is available at:
 
@@ -11,8 +11,8 @@
 
 --- State ---
 
-v0.2.*: libsoylent is work-in-progress. Addressbook and people management work
-at a very basic level. Modifying attributes of people is not implemented yet.
+v0.4.*: libsoylent is work-in-progress. Some minor features are missing, but
+the core-functionality is implemented. The library still needs some testing.
 Even if it's unlikely that libsoylent will cause any damage you are encouraged
 (as with any work-in-progress software) to backup your system (or at least
 your ~/.evolution directory) before using libsoylent.
@@ -25,6 +25,51 @@
  * Telepathy, Mission Control, libempathy
  * E-D-S
 
+--- Documentation ---
+
+The libsoylent API reference can be found online at:
+
+http://kalterregen.de/libsoylent
+
+It is also located in the source under the docs/references/libsoylent/html
+directory.
+
+--- Examples ---
+
+The examples in the libsoylent/example directory will give a good introduction
+to libsoylent.
+
+--- Building libsoylent ---
+
+libsoylent uses autotools for building. To build libsoylent (and Soylent)
+execute in the source directory:
+
+./autogen.sh --enable-libsoylent=yes
+make
+
+If you want to install libsoylent (and Soylent) just do:
+
+make install
+
+If you also want to build the libsoylent documentation add --enable-gtk-doc to
+the autogen.sh parameters.
+
+That's it!
+
+--- Debugging ---
+
+If you want to have detailed information about what's going on in libsoylent,
+define one or more of the following macros in `sl-priv-util.h`, depending on
+what you want to debug. Then rebuild libsoylent.
+
+Note that this may produce a lot of output.
+
+SL_ENABLE_DEBUG_ALL
+SL_ENABLE_DEBUG_BOOK
+SL_ENABLE_DEBUG_ENTITY
+SL_ENABLE_DEBUG_ATTRIBUTE
+SL_ENABLE_DEBUG_UTIL
+
 --- Contact ---
 
 Bugs, feature requests, questions and related discussion go to the Soylent
@@ -34,6 +79,9 @@
 
 --- Known Bugs ---
 
+Note: because of bug 1 to 3, addressbook functionality has been disabled in
+v0.4.0, i.e. you can only use the default addressbook.
+
  * [1] if you have never started Evolution before there will be no system-
    addressbook, so all addressbook-functions will fail [TODO; workaround:
    start Evolution once]
@@ -42,3 +90,5 @@
    to delete the addressbook again]
  * [3] adding people to any addressbook but the default addressbook kills E-D-S
    [TODO; no workaround atm]
+ * [4] addresses stored via libsoylent are not displayed in Evolution [TODO;
+   workaround: use Evolution to store addresses]

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-book.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-book.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-book.c	Tue Aug 12 12:53:27 2008
@@ -21,10 +21,22 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "sl-book.h"
+/**
+ * SECTION:sl-book
+ * @short_description: the addressbook
+ * @see_also: #SlEntity
+ * @stability: Unstable
+ * @include: sl-book.h
+ *
+ * SlBook is basically like a real-world addressbook, i.e. it is responsible
+ * for managing people (adding and removing them to / from the addressbook).
+ * Searching for people is also possible. Furthermore SlBook contains utility
+ * functions to create, open and delete addressbooks.
+ */
+
+#include "sl-mutual-inclusion.h"
 #include "sl-priv-util.h"
-#include "sl-entity.h"
-#include "sl-entity-handler-eds.h"
+#include "sl-marshal.h"
 
 /* private structs and fields */
 
@@ -32,6 +44,9 @@
 {
   GError *error;
   EBook *ebook;
+  EBookView *eview;
+  GMainLoop *view_wait_loop;
+  GList *people;
 };
 
 static GObjectClass *parent_class = NULL;
@@ -43,9 +58,18 @@
   const GValue *value, GParamSpec *pspec);
 static void sl_book_get_property (GObject *object, guint property_id,
   GValue *value, GParamSpec *pspec);
-static SlBook *sl_book_new (EBook *ebook);
+static SlBook *sl_book_new (EBook *ebook, GError **error);
 static SlBook *sl_book_new_from_source (ESource *source, GError **error);
 
+static void eview_contacts_added (EBookView *eview, GList *econtacts, 
+                                  SlBook *self);
+static void eview_contacts_changed (EBookView *eview, GList *econtacts, 
+                                    SlBook *self);
+static void eview_contacts_removed (EBookView *eview, GList *econtact_ids, 
+                                    SlBook *self);
+static void eview_sequence_complete (EBookView *eview, EBookViewStatus status, 
+                                     SlBook *self);
+
 GType
 sl_book_get_type (void)
 {
@@ -91,10 +115,32 @@
                               GParamSpec *)) sl_book_set_property;
   
   GParamSpec *pspec = NULL;
+  
+  /**
+   * SlBook:ebook:
+   *
+   * The underlying #EBook (private).
+   */
   pspec = g_param_spec_pointer ("ebook", "ebook", "EBook backend", 
             G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
-  
   g_object_class_install_property (obj_class, SL_BOOK_PROPERTY_EBOOK, pspec);
+  
+  /**
+   * SlBook::added:
+   * @book: the book that received the signal
+   * @foo: yeah, foo
+   *
+   * Emitted when a person is added to the addressbook.
+   */
+  
+  
+  g_signal_new ("modified", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+  g_signal_new ("person-added", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, SL_PERSON_TYPE, G_TYPE_BOOLEAN);
+  g_signal_new ("person-removed", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, SL_PERSON_TYPE, G_TYPE_BOOLEAN);
+  g_signal_new ("person-modified", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, SL_PERSON_TYPE, G_TYPE_BOOLEAN);
+  g_signal_new ("person-attribute-added", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_OBJECT_BOOLEAN, G_TYPE_NONE, 3, SL_PERSON_TYPE, SL_ATTRIBUTE_TYPE, G_TYPE_BOOLEAN);
+  g_signal_new ("person-attribute-removed", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_OBJECT_BOOLEAN, G_TYPE_NONE, 3, SL_PERSON_TYPE, SL_ATTRIBUTE_TYPE, G_TYPE_BOOLEAN);
+  g_signal_new ("person-attribute-modified", SL_BOOK_TYPE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, sl_marshal_VOID__OBJECT_OBJECT_POINTER_BOOLEAN, G_TYPE_NONE, 4, SL_PERSON_TYPE, SL_ATTRIBUTE_TYPE, G_TYPE_POINTER, G_TYPE_BOOLEAN);
 }
 
 static void
@@ -194,6 +240,13 @@
   return books;
 }
 
+/**
+ * sl_book_exists:
+ *
+ * Deprecated:
+ *
+ * Since: v0.2.0
+ */
 gboolean
 sl_book_exists (const gchar *name)
 {
@@ -210,9 +263,23 @@
   return (source != NULL);
 }
 
+/**
+ * sl_book_create:
+ * @name: name of the new addressbook
+ * @error: return location for a GError or NULL
+ *
+ * Creates a new addressbook with the given @name.
+ * There is also a sl_book_open() function. And have you seen our
+ * #SlAttributeHandlerType? Or our %foobar?
+ *
+ * Returns: the created addressbook, or NULL on error. The created addressbook
+ * is immediatly ready for use.
+ */
 SlBook *
 sl_book_create (const gchar *name, GError **error)
 {
+  g_error ("%s disabled because of addressbook-bug", __FUNCTION__);
+  
   g_return_val_if_fail (name != NULL, NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
   
@@ -252,6 +319,8 @@
 
 SlBook *sl_book_open (const gchar *name, GError **error)
 {
+  g_error ("%s disabled because of addressbook-bug", __FUNCTION__);
+  
   ESourceList *source_tree = NULL;
   if (!e_book_get_addressbooks (&source_tree, error))
     {
@@ -280,12 +349,14 @@
       return NULL;
     }
   
-  return sl_book_new (ebook);
+  return sl_book_new (ebook, error);
 }
 
 gboolean
 sl_book_delete (const gchar *name, GError **error)
 {
+  g_error ("%s disabled because of addressbook-bug", __FUNCTION__);
+  
   /* TODO: forbid to delete default addressbook */
   
   g_return_val_if_fail (name != NULL, FALSE);
@@ -330,11 +401,49 @@
   return TRUE;
 }
 
+gboolean
+sl_book_constr (SlBook *self, GError **error)
+{
+  self->priv->people = NULL;
+  self->priv->eview = NULL;
+  self->priv->view_wait_loop = g_main_loop_new (NULL, FALSE);
+  
+  sl_debug_book ("starting to load people from book%s", "");
+  
+  /* this will query all contacts */
+  EBookQuery *query = e_book_query_any_field_contains ("");
+  
+  /* TODO: Here you can query only certain fields, this would be a great
+   * performance improvement. But we definitely want a list of all people and
+   * for every person a list of all attributes. Is this possible without
+   * querying all fields? */
+  /* TODO: this would also need some refactoring for SlAttribute to support
+   * lazy loading */
+  if (!e_book_get_book_view (self->priv->ebook, query, NULL, 0, 
+                             &self->priv->eview, error))
+    {
+      return FALSE;
+    }
+  
+  g_object_connect (self->priv->eview,
+    "signal::contacts-added", G_CALLBACK (eview_contacts_added), self,
+    "signal::contacts-changed", G_CALLBACK (eview_contacts_changed), self,
+    "signal::contacts-removed", G_CALLBACK (eview_contacts_removed), self,
+    "signal::sequence-complete", G_CALLBACK (eview_sequence_complete), self,
+    NULL);
+  
+  e_book_view_start (self->priv->eview);
+  g_main_loop_run (self->priv->view_wait_loop);
+  
+  return TRUE;
+}
+
 static SlBook *
-sl_book_new (EBook *ebook)
+sl_book_new (EBook *ebook, GError **error)
 {
   g_return_val_if_fail (ebook != NULL && E_IS_BOOK (ebook), NULL);
   SlBook *self = g_object_new (SL_BOOK_TYPE, "ebook", ebook, NULL);
+  sl_book_constr (self, error);
   return self;
 }
 
@@ -354,7 +463,7 @@
       return NULL;
     }
   
-  SlBook *self = sl_book_new (ebook);
+  SlBook *self = sl_book_new (ebook, error);
   g_object_unref (ebook);
   return self;
 }
@@ -367,11 +476,15 @@
   
   SlEntity *entity = SL_ENTITY (person);
   if (!e_book_add_contact (self->priv->ebook, sl_entity_get_econtact (entity),
-    error))
+                           error))
     {
       return FALSE;
     }
   
+  sl_entity_set_ebook (entity, self->priv->ebook);
+  
+  self->priv->people = g_list_append (self->priv->people, person);
+  
   return TRUE;
 }
 
@@ -384,19 +497,320 @@
     {
       return FALSE;
     }
+  
+  self->priv->people = g_list_remove (self->priv->people, person);
+  
   return TRUE;
 }
 
 GList *
 sl_book_get_people (SlBook *self)
 {
-  g_warning("%s not implemented", __FUNCTION__);
-  return NULL;
+  /* TODO: make this with a libsoylent-query? */
+  return self->priv->people;
 }
 
 SlPerson *
-sl_book_get_person(SlBook *self, gchar *attrname, gpointer value)
+sl_book_get_person (SlBook *self, const gchar *attrname, gpointer value)
 {
-  g_warning("%s not implemented", __FUNCTION__);
+  /* TODO: this works only for strings atm */
+  GList *people = self->priv->people;
+  for (; people != NULL; people = people->next)
+    {
+      SlPerson *person = people->data;
+      if (g_str_equal ((gchar *) value, (gchar *) sl_person_get (person, attrname)))
+        {
+          return person;
+        }
+    }
+  
+  return NULL;
+}
+
+/*static SlPerson *
+sl_book_get_person_from_econtact (SlBook *self, EContact *econtact)
+{
+  GList *people = self->priv->people;
+  for (; people != NULL; people = people->next)
+    {
+      SlPerson *person = people->data;
+      if (sl_entity_get_econtact (SL_ENTITY (person)) == econtact)
+        {
+          return person;
+        }
+    }
+  
   return NULL;
+}*/
+
+void
+sl_book_emit_person_added (SlBook *self, SlPerson *person, gboolean on_purpose)
+{
+  g_signal_emit_by_name (self, "person-added", person, on_purpose);
+  g_signal_emit_by_name (self, "modified", on_purpose);
+}
+
+void
+sl_book_emit_person_removed (SlBook *self, SlPerson *person, gboolean on_purpose)
+{
+  g_signal_emit_by_name (self, "person-removed", person, on_purpose);
+  g_signal_emit_by_name (self, "modified", on_purpose);
+}
+
+void
+sl_book_emit_person_attribute_added (SlBook *self, SlPerson *person, SlAttribute *attr, gboolean on_purpose)
+{
+  g_signal_emit_by_name (self, "person-attribute-added", person, attr, on_purpose);
+  g_signal_emit_by_name (self, "person-modified", person, on_purpose);
+  g_signal_emit_by_name (self, "modified", on_purpose);
+}
+
+void
+sl_book_emit_person_attribute_removed (SlBook *self, SlPerson *person, SlAttribute *attr, gboolean on_purpose)
+{
+  g_signal_emit_by_name (self, "person-attribute-removed", person, attr, on_purpose);
+  g_signal_emit_by_name (self, "person-modified", person, on_purpose);
+  g_signal_emit_by_name (self, "modified", on_purpose);
+}
+
+void
+sl_book_emit_person_attribute_modified (SlBook *self, SlPerson *person, SlAttribute *attr, GList *old_values, gboolean on_purpose)
+{
+  g_signal_emit_by_name (self, "person-attribute-modified", person, attr, old_values, on_purpose);
+  g_signal_emit_by_name (self, "person-modified", person, on_purpose);
+  g_signal_emit_by_name (self, "modified", on_purpose);
+}
+
+static void
+eview_contacts_added (EBookView *eview, GList *econtacts, SlBook *self)
+{
+  /* TODO: consider to forget econtact here again */
+  if (self->priv->view_wait_loop != NULL)
+    {
+      sl_debug_book ("loading %d person / people", g_list_length (econtacts));
+    }
+  
+  sl_debug_book ("%d econtact(s) added", g_list_length (econtacts));
+  
+  for (; econtacts != NULL; econtacts = econtacts->next)
+    {
+      EContact *econtact = econtacts->data;
+      SlPerson *person = sl_person_new_with_econtact (econtact);
+      self->priv->people = g_list_append (self->priv->people, person);
+      
+      if (self->priv->view_wait_loop == NULL)
+        {
+          sl_book_emit_person_added (self, person, FALSE);
+        }
+    }
+}
+
+static void
+eview_contacts_changed (EBookView *eview, GList *econtacts, SlBook *self)
+{
+  g_assert (econtacts != NULL);
+  sl_debug_book ("examining %d econtact(s) for modifications", g_list_length (econtacts));
+  
+  for (; econtacts != NULL; econtacts = econtacts->next)
+    {
+      
+      EContact *econtact = econtacts->data;
+      SlPerson *person = sl_book_get_person (self, SL_ATTR_ID, e_contact_get (econtact, E_CONTACT_UID));
+      g_assert (person != NULL);
+      SlEntity *entity = SL_ENTITY (person);
+      EContact *econtact_old = sl_entity_get_econtact (entity);
+
+      sl_entity_set_econtact (entity, econtact);
+      
+      GList *eattributes = sl_priv_util_eattribute_flat_to_deep_list (e_vcard_get_attributes (E_VCARD (econtact)));
+      GList *eattributes_old = sl_priv_util_eattribute_flat_to_deep_list (e_vcard_get_attributes (E_VCARD (econtact_old)));
+      
+      GList *added = NULL;
+      GList *removed = NULL;
+      GList *modified = NULL;
+      GList *rest = NULL;
+      sl_priv_util_list_set_diff_full (eattributes, eattributes_old,
+                                      (GEqualFunc) sl_priv_util_eattrlist_name_equal,
+                                      (GEqualFunc) sl_priv_util_eattrlist_modified,
+                                      &added, &removed, &modified, &rest);
+      
+      sl_debug_book ("processing added eattributes%s", "");
+      for (; added != NULL; added = added->next)
+        {
+          GList *eattrlist = added->data;
+          EVCardAttribute *eattr = eattrlist->data;
+          const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+          if (sl_is_ignored_eattr (eattrname))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname);
+              continue;
+            }
+          
+          sl_debug_book ("found new eattribute \"%s\"", eattrname);
+          SlAttribute *attr = sl_attribute_new_with_eattributes (eattrlist);
+          sl_entity_add_attribute_shallow (entity, attr);
+          sl_book_emit_person_attribute_added (self, person, attr, FALSE);
+          g_object_unref (attr);
+        }
+      
+      sl_debug_book ("processing removed eattributes%s", "");
+      for (; removed != NULL; removed = removed->next)
+        {
+          GList *eattrlist = removed->data;
+          EVCardAttribute *eattr = eattrlist->data;
+          const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+          if (sl_is_ignored_eattr (eattrname))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname);
+              continue;
+            }
+          
+          sl_debug_book ("eattribute \"%s\" doesn't exist anymore", eattrname);
+          SlAttribute *attr = g_object_ref (sl_entity_get_attribute_from_eattr (entity, eattr));
+          g_assert (attr != NULL);
+          sl_entity_remove_attribute_shallow (entity, attr);
+          sl_book_emit_person_attribute_removed (self, person, attr, FALSE);
+          g_object_unref (attr);
+        }
+      
+      sl_debug_book ("processing modified eattributes%s", "");
+      for (; modified != NULL; modified = modified->next)
+        {
+          GList *eattrlist = modified->data;
+          EVCardAttribute *eattr = eattrlist->data;
+          const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+          if (sl_is_ignored_eattr (eattrname))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname);
+              continue;
+            }
+
+          sl_debug_book ("found modified eattribute \"%s\"", eattrname);
+          SlAttribute *attr = sl_entity_get_attribute_from_eattr (entity, eattr);
+          g_assert (attr != NULL);
+          GList *old_values = sl_attribute_get_all (attr);
+          sl_attribute_set_all_from_eattributes (attr, eattrlist);
+          sl_book_emit_person_attribute_modified (self, person, attr, old_values, FALSE);
+        }
+      
+      sl_debug_book ("processing rest of eattributes%s", "");
+      for (; rest != NULL; rest = rest->next)
+        {
+          GList *eattrlist = rest->data;
+          EVCardAttribute *eattr = eattrlist->data;
+          const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+          if (sl_is_ignored_eattr (eattrname))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname);
+              continue;
+            }
+          
+          SlAttribute *attr = sl_entity_get_attribute_from_eattr (entity, eattr);
+          g_assert (attr != NULL);
+          sl_attribute_update_eattributes (attr, eattrlist);
+        }
+      
+      g_list_free (g_list_first (added));
+      g_list_free (g_list_first (removed));
+      g_list_free (g_list_first (modified));
+      sl_priv_util_eattribute_deep_list_free (eattributes);
+      sl_priv_util_eattribute_deep_list_free (eattributes_old);
+      
+      /*
+      sl_priv_util_eattribute_list_print (eattributes, "eattributes");
+      
+      sl_debug_book ("examining %d eattribute(s)", g_list_length (eattributes));
+      for (; eattributes != NULL; eattributes = eattributes->next)
+        {
+          
+          
+          EVCardAttribute *eattr = eattributes->data;
+          const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+          if (sl_is_ignored_eattr (eattrname))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname);
+              continue;
+            }
+
+          EVCardAttribute *eattr_old = e_vcard_get_attribute (E_VCARD (econtact_old), eattrname);
+          
+          if (eattr_old == NULL)
+            {
+              sl_debug_book ("found new eattribute \"%s\"", eattrname);
+              SlAttribute *attr = sl_attribute_new_with_eattr (eattr);
+              sl_person_add_attribute (person, attr);
+              sl_book_emit_person_attribute_added (self, person, attr, FALSE);
+              g_object_unref (attr);
+            }
+          else
+            {
+              GList *evalues = e_vcard_attribute_get_values (eattr);
+              GList *evalues_old = e_vcard_attribute_get_values (eattr_old);
+              if (!sl_priv_util_lists_equal (evalues, evalues_old, g_str_equal))
+                {
+                  sl_debug_book ("found modified eattribute \"%s\"", eattrname);
+                  SlAttribute *attr = sl_entity_get_attribute_from_eattr (entity, eattr_old);
+                  g_assert (attr != NULL);
+                  GList *old_values = sl_attribute_get_all (attr);
+                  sl_attribute_set_all_from_eattr (attr, eattr);
+                  sl_book_emit_person_attribute_modified (self, person, attr, old_values, FALSE);
+                }
+              eattributes_old = g_list_remove (eattributes_old, eattr_old);
+            }
+        }
+      
+      for (; eattributes_old != NULL; eattributes_old = eattributes_old->next)
+        {
+          EVCardAttribute *eattr_old = eattributes_old->data;
+          const gchar *eattrname_old = e_vcard_attribute_get_name (eattr_old);
+          if (sl_is_ignored_eattr (eattrname_old))
+            {
+              sl_debug_book ("ignoring eattribute \"%s\"", eattrname_old);
+              continue;
+            }
+          sl_debug_book ("eattribute \"%s\" doesn't exist anymore", e_vcard_attribute_get_name (eattr_old));
+          SlAttribute *attr = sl_entity_get_attribute_from_eattr (entity, eattr_old);
+          g_assert (attr != NULL);
+          sl_book_emit_person_attribute_removed (self, person, attr, FALSE);
+        }
+      */
+      
+      
+      //g_object_unref (econtact_old);
+    }
+}
+
+static void
+eview_contacts_removed (EBookView *eview, GList *ids, SlBook *self)
+{
+  sl_debug_book ("%d econtacts removed", g_list_length (ids));
+  
+  for (; ids != NULL; ids = ids->next)
+    {
+      SlPerson *person = sl_book_get_person (self, SL_ATTR_ID, ids->data);
+      g_assert (person != NULL);
+      
+      self->priv->people = g_list_remove (self->priv->people, person);
+      
+      sl_book_emit_person_removed (self, person, FALSE);
+      
+      g_object_unref (person);
+    }
+}
+
+static void
+eview_sequence_complete (EBookView *eview, EBookViewStatus status, SlBook *self) {
+  if (status != E_BOOK_VIEW_STATUS_OK)
+    {
+      g_critical ("eview status is: %d", status);
+    }
+  
+  if (self->priv->view_wait_loop != NULL)
+    {
+      sl_debug_book ("loading people from book done%s", "");
+
+      g_main_loop_quit (self->priv->view_wait_loop);
+      g_main_loop_unref (self->priv->view_wait_loop);
+      self->priv->view_wait_loop = NULL;
+    }
 }

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-book.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-book.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-book.h	Tue Aug 12 12:53:27 2008
@@ -28,11 +28,10 @@
 #ifndef SL_BOOK_H
 #define SL_BOOK_H
 
-#include "sl-person.h"
+#include "sl-mutual-inclusion.h"
 
 #include <glib.h>
 #include <glib-object.h>
-//#include <libebook/e-book.h>
 
 #define SL_BOOK_TYPE            (sl_book_get_type ())
 #define SL_BOOK(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, \
@@ -47,13 +46,29 @@
 
 #define SL_BOOK_DEFAULT sl_book_default
 
-typedef struct _SlBook      SlBook;
 typedef struct _SlBookClass SlBookClass;
 typedef struct _SlBookPriv  SlBookPriv;
 
 typedef enum _SlBookProperty  SlBookProperty;
 typedef enum _SlBookError     SlBookError;
 
+/* TODO: how does evolution do this? implement book_manager */
+typedef void (*SlBookCBBookCreated)   (SlBook *book_manager, gchar *book_name, gpointer user_data);
+typedef void (*SlBookCBBookDeleted)   (SlBook *book_manager, gchar *book_name, gpointer user_data);
+
+typedef void (*SlBookCBModified)                (SlBook *book, gboolean on_purpose, gpointer user_data); /* means entity -added, -removed, -modified */
+typedef void (*SlBookCBPersonAdded)             (SlBook *book, SlPerson *person, gboolean on_purpose, gpointer user_data);
+typedef void (*SlBookCBPersonRemoved)           (SlBook *book, SlPerson *person, gboolean on_purpose, gpointer user_data);
+typedef void (*SlBookCBPersonModified)          (SlBook *book, SlPerson *person, gboolean on_purpose, gpointer user_data);
+typedef void (*SlBookCBPersonAttributeAdded)    (SlBook *book, SlPerson *person, SlAttribute *attr, gboolean on_purpose, gpointer user_data);
+typedef void (*SlBookCBPersonAttributeRemoved)  (SlBook *book, SlPerson *person, SlAttribute *attr, gboolean on_purpose, gpointer user_data);
+typedef void (*SlBookCBPersonAttributeModified) (SlBook *book, SlPerson *person, SlAttribute *attr, GList *old_values, gboolean on_purpose, gpointer user_data);
+
+typedef void (*SlEntityCBModified)          (SlEntity *entity, gboolean on_purpose, gpointer user_data);
+typedef void (*SlEntityCBAttributeAdded)    (SlEntity *entity, SlAttribute *attr, gboolean on_purpose, gpointer user_data);
+typedef void (*SlEntityCBAttributeRemoved)  (SlEntity *entity, SlAttribute *attr, gboolean on_purpose, gpointer user_data);
+typedef void (*SlEntityCBAttributeModified) (SlEntity *entity, SlAttribute *attr, gboolean on_purpose, GList *old_values, gpointer user_data);
+
 enum SlBookProperty
 {
   SL_BOOK_PROPERTY_EBOOK = 1
@@ -85,6 +100,8 @@
 
 gboolean sl_book_setup (GError **error);
 
+gboolean sl_book_constr (SlBook *self, GError **error);
+
 GList *sl_book_get_books (void);
 gboolean sl_book_exists (const gchar *name);
 SlBook *sl_book_create (const gchar *name, GError **error);
@@ -96,6 +113,12 @@
 gboolean sl_book_remove_person (SlBook *self, SlPerson *person, GError **error);
 /* TODO: more to come, like searching for attributes */
 GList *sl_book_get_people (SlBook *self);
-SlPerson *sl_book_get_person(SlBook *self, gchar *attrname, gpointer value);
+SlPerson *sl_book_get_person (SlBook *self, const gchar *attrname, gpointer value);
+
+void sl_book_emit_person_added (SlBook *self, SlPerson *person, gboolean on_purpose);
+void sl_book_emit_person_removed (SlBook *self, SlPerson *person, gboolean on_purpose);
+void sl_book_emit_person_attribute_added (SlBook *self, SlPerson *person, SlAttribute *attr, gboolean on_purpose);
+void sl_book_emit_person_attribute_removed (SlBook *self, SlPerson *person, SlAttribute *attr, gboolean on_purpose);
+void sl_book_emit_person_attribute_modified (SlBook *self, SlPerson *person, SlAttribute *attr, GList *old_values, gboolean on_purpose);
 
 #endif

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-group.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-group.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-group.c	Tue Aug 12 12:53:27 2008
@@ -62,7 +62,7 @@
   
   if (type == 0)
     {
-      type = g_type_register_static (SL_ENTITY_TYPE, "SlGroup", &info, 0);
+      type = g_type_register_static (G_TYPE_OBJECT, "SlGroup", &info, 0);
     }
   return type;
 }
@@ -85,14 +85,14 @@
   SlGroup *self = SL_GROUP (instance);
   SlGroupPriv *priv = g_new (SlGroupPriv, 1);
   self->priv = priv;
-  SL_ENTITY (self)->disposed = FALSE;
+  //SL_ENTITY (self)->disposed = FALSE;
 }
 
 static void
 sl_group_dispose (GObject *object)
 {
   SlGroup *self = SL_GROUP (object);
-  g_return_if_fail (!SL_ENTITY (self)->disposed);
+  //g_return_if_fail (!SL_ENTITY (self)->disposed);
   
   g_free (self->priv);
   

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-group.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-group.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-group.h	Tue Aug 12 12:53:27 2008
@@ -26,7 +26,7 @@
 #ifndef SL_GROUP_H
 #define SL_GROUP_H
 
-#include "sl-entity.h"
+#include "sl-group.h"
 
 #include <glib.h>
 #include <glib-object.h>
@@ -47,13 +47,13 @@
 
 struct _SlGroup
 {
-  SlEntity parent;
+  GObject parent;
   SlGroupPriv *priv;
 };
 
 struct _SlGroupClass
 {
-  SlEntityClass parent;
+  GObjectClass parent;
 };
 
 GType sl_group_get_type (void);

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-person.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-person.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-person.c	Tue Aug 12 12:53:27 2008
@@ -21,8 +21,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "sl-person.h"
-#include "sl-entity-handler-eds.h"
+#include "sl-mutual-inclusion.h"
 
 /* private structs and fields */
 
@@ -111,19 +110,121 @@
   g_warning("%s not implemented", __FUNCTION__);
 }
 
+SlName *sl_name_new (void)
+{
+  SlName *name = g_new (SlName, 1);
+  name->names = NULL;
+  name->family_name = "";
+  name->honoric_prefixes = NULL;
+  name->honoric_suffixes = NULL;
+  return name;
+}
+
+SlAddress *sl_address_new (void)
+{
+  SlAddress *address = g_new (SlAddress, 1);
+  address->country = "";
+  address->region = "";
+  address->city = "";
+  address->street = "";
+  address->postal_code = "";
+  address->addition = "";
+  address->po_box = "";
+  return address;
+}
+
+SlPerson *
+sl_person_new (const gchar *name, const gchar *family_name)
+{
+  SlPerson *self = g_object_new (SL_PERSON_TYPE, NULL);
+  sl_person_constr (self, name, family_name);
+  return self;
+}
+
 SlPerson *
-sl_person_new (const gchar *name)
+sl_person_new_with_econtact (EContact *econtact)
 {
   SlPerson *self = g_object_new (SL_PERSON_TYPE, NULL);
-  sl_person_constr (self, name);
+  sl_person_constr_with_econtact (self, econtact);
   return self;
 }
 
 void
-sl_person_constr (SlPerson *self, const gchar *name)
+sl_person_constr (SlPerson *self, const gchar *name, const gchar *family_name)
 {
   sl_entity_constr (SL_ENTITY (self));
-  /* temporary, this will be moved to SlAttributes */
-  EContact *econtact = sl_entity_get_econtact (SL_ENTITY (self));
-  e_contact_set (econtact, E_CONTACT_NICKNAME, (const gpointer) name);
+  SlName *n = sl_name_new ();
+  n->names = g_list_append (NULL, (gchar *) name);
+  n->family_name = (gchar *) family_name;
+  sl_person_set (self, SL_ATTR_NAME, n);
+}
+
+void
+sl_person_constr_with_econtact (SlPerson *self, EContact *econtact)
+{
+  sl_entity_constr_with_econtact (SL_ENTITY (self), econtact);
+}
+
+gchar *
+sl_person_get_name (SlPerson *self)
+{
+  SlName *name = sl_person_get (self, SL_ATTR_NAME);
+  return g_list_nth_data (name->names, 0);
+}
+
+void
+sl_person_set_name (SlPerson *self, gchar *name)
+{
+  SlAttribute *attr_name = sl_person_get_attribute (self, SL_ATTR_NAME);
+  SlName *n = sl_attribute_get (attr_name);
+  if (n->names == NULL)
+    {
+      n->names = g_list_append (n->names, name);
+    }
+  else
+    {
+      /* TODO: does this leak? */
+      n->names->data = name;
+    }
+  sl_attribute_modified (attr_name);
+}
+
+gchar *
+sl_person_get_family_name (SlPerson *self)
+{
+  SlName *name = sl_person_get (self, SL_ATTR_NAME);
+  return name->family_name;
+}
+
+void
+sl_person_set_family_name (SlPerson *self, gchar *family_name)
+{
+  SlAttribute *attr_name = sl_person_get_attribute (self, SL_ATTR_NAME);
+  SlName *n = sl_attribute_get (attr_name);
+  n->family_name = family_name;
+  sl_attribute_modified (attr_name);
+}
+
+gchar *
+sl_person_get_full_name (SlPerson *self)
+{
+  return sl_person_get (self, SL_ATTR_FULL_NAME);
+}
+
+void
+sl_person_set_full_name (SlPerson *self, gchar *fullname)
+{
+  sl_person_set (self, SL_ATTR_FULL_NAME, fullname);
+}
+
+gchar *
+sl_person_get_nick (SlPerson *self)
+{
+  return sl_person_get (self, SL_ATTR_NICK);
+}
+
+void
+sl_person_set_nick (SlPerson *self, gchar *nick)
+{
+  sl_person_set (self, SL_ATTR_NICK, nick);
 }

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-person.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-person.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-person.h	Tue Aug 12 12:53:27 2008
@@ -24,7 +24,7 @@
 #ifndef SL_PERSON_H
 #define SL_PERSON_H
 
-#include "sl-entity.h"
+#include "sl-mutual-inclusion.h"
 
 #include <glib.h>
 #include <glib-object.h>
@@ -41,9 +41,255 @@
 #define SL_PERSON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS (obj, \
   SL_PERSON_TYPE))
 
-typedef struct _SlPerson      SlPerson;
+/* well-known attributes */
+
+/**
+ * SL_ATTR_ID:
+ *
+ * Unique ID of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_ID "id"
+
+/**
+ * SL_ATTR_NAME:
+ *
+ * A structured name of a person (names, family-name etc.). For a
+ * more convinient way to handle a persons name see the sl_person_get/set_name*
+ * methods.
+ *
+ * type: #SlName
+ */
+#define SL_ATTR_NAME "name"
+
+/**
+ * SL_ATTR_FULL_NAME:
+ *
+ * A string representing the full, printable name of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_FULL_NAME "full-name"
+
+/**
+ * SL_ATTR_NICK:
+ *
+ * The nickname of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_NICK "nick"
+
+/**
+ * SL_ATTR_GROUP:
+ *
+ * A list of groups a person is in.
+ *
+ * type: #GList <type>(string)</type>
+ */
+#define SL_ATTR_GROUP "group"
+
+/**
+ * SL_ATTR_ADDRESS:
+ *
+ * An (postal) address of a person.
+ *
+ * type: #SlAddress
+ */
+#define SL_ATTR_ADDRESS "address"
+
+/**
+ * SL_ATTR_EMAIL:
+ *
+ * An email-address of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_EMAIL "email"
+
+/**
+ * SL_ATTR_TELEPHONE:
+ *
+ * A telephone-number of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_TELEPHONE "telephone"
+
+/**
+ * SL_ATTR_BIRTHDAY:
+ *
+ * The birthday of a person.
+ *
+ * type: #GDate
+ */
+#define SL_ATTR_BIRTHDAY "birthday"
+
+/**
+ * SL_ATTR_URL:
+ *
+ * An URL of a person. This typically represents something like a homepage.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_URL "url"
+
+/**
+ * SL_ATTR_BLOG:
+ *
+ * The blog-URL of a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_BLOG "blog"
+
+/**
+ * SL_ATTR_CALENDAR_URL:
+ *
+ * An URL pointing to where a calendar of a person is located.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_CALENDAR_URL "calendar-url"
+
+/**
+ * SL_ATTR_FREE_BUSY_URL:
+ *
+ * An URL pointing to where free-busy-information of a person is located.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_FREE_BUSY_URL "free-busy-url"
+
+/**
+ * SL_ATTR_NOTE:
+ *
+ * A note attached to a person.
+ *
+ * type: <type>string</type>
+ */
+#define SL_ATTR_NOTE "note"
+
+/**
+ * SL_ATTR_PHOTO:
+ *
+ * A photo of a person.
+ *
+ * type: #GByteArray
+ */
+#define SL_ATTR_PHOTO "photo"
+
+/**
+ * SL_ATTR_ICON:
+ *
+ * An icon of a person.
+ *
+ * type: #GByteArray
+ */
+#define SL_ATTR_ICON "icon"
+
+/* TODO: job struct? */
+#define SL_ATTR_JOB_ROLE      "job-role"
+#define SL_ATTR_JOB_TITLE     "job-title"
+
+/*#define EVC_X_AIM              "X-AIM"
+#define EVC_X_GADUGADU        "X-GADUGADU"
+#define EVC_X_ICQ              "X-ICQ"
+#define EVC_X_JABBER           "X-JABBER"
+#define EVC_X_MSN           	"X-MSN"
+#define EVC_X_YAHOO         	"X-YAHOO"
+#define EVC_X_GROUPWISE     	"X-GROUPWISE"*/
+
+/*#define EVC_GEO		    "GEO"*/
+/*#define EVC_ICSCALENDAR     "ICSCALENDAR"*/
+/*#define EVC_KEY             "KEY"*/
+/*#define EVC_LABEL           "LABEL"*/
+/*#define EVC_MAILER          "MAILER"*/
+/*#define EVC_ORG             "ORG"*/
+/*#define EVC_PRODID          "PRODID"*/
+/*#define EVC_QUOTEDPRINTABLE "QUOTED-PRINTABLE"*/
+/*#define EVC_REV             "REV"*/
+/*#define EVC_ROLE            "ROLE"*/
+/*#define EVC_TITLE           "TITLE"*/
+/*#define EVC_TYPE            "TYPE"*/
+/*#define EVC_VALUE           "VALUE"*/
+/*#define EVC_VERSION         "VERSION"*/
+/*#define EVC_X_ANNIVERSARY      "X-EVOLUTION-ANNIVERSARY"*/
+/*#define EVC_X_ASSISTANT        "X-EVOLUTION-ASSISTANT"*/
+/*#define EVC_X_BIRTHDAY         "X-EVOLUTION-BIRTHDAY"*/
+/*#define EVC_X_FILE_AS          "X-EVOLUTION-FILE-AS"*/
+/*#define EVC_X_LIST_SHOW_ADDRESSES "X-EVOLUTION-LIST-SHOW_ADDRESSES"*/
+/*#define EVC_X_LIST          	"X-EVOLUTION-LIST"*/
+/*#define EVC_X_MANAGER       	"X-EVOLUTION-MANAGER"*/
+/*#define EVC_X_SPOUSE        	"X-EVOLUTION-SPOUSE"*/
+/*#define EVC_X_WANTS_HTML    	"X-MOZILLA-HTML"*/
+/*#define EVC_X_BOOK_URI     	"X-EVOLUTION-BOOK-URI"*/
+/*#define EVC_X_CALLBACK         "X-EVOLUTION-CALLBACK"*/
+/*#define EVC_X_COMPANY          "X-EVOLUTION-COMPANY"*/
+/*#define EVC_X_DEST_CONTACT_UID "X-EVOLUTION-DEST-CONTACT-UID"
+#define EVC_X_DEST_EMAIL       "X-EVOLUTION-DEST-EMAIL"
+#define EVC_X_DEST_EMAIL_NUM   "X-EVOLUTION-DEST-EMAIL-NUM"
+#define EVC_X_DEST_HTML_MAIL   "X-EVOLUTION-DEST-HTML-MAIL"
+#define EVC_X_DEST_NAME        "X-EVOLUTION-DEST-NAME"
+#define EVC_X_DEST_SOURCE_UID  "X-EVOLUTION-DEST-SOURCE-UID"
+#define EVC_X_RADIO         	"X-EVOLUTION-RADIO"
+#define EVC_X_TELEX         	"X-EVOLUTION-TELEX"
+#define EVC_X_TTYTDD        	"X-EVOLUTION-TTYTDD"
+#define EVC_X_VIDEO_URL     	"X-EVOLUTION-VIDEO-URL"*/
+
+
+  
+void sl_entity_add_attribute (SlEntity *self, SlAttribute *attr);
+void sl_entity_remove_attribute (SlEntity *self, SlAttribute *attr);
+
+SlAttribute *sl_entity_get_attribute (SlEntity *self, const gchar *attrname);
+GList *sl_entity_get_attributes (SlEntity *self);
+  
+#define sl_person_get_book(self) \
+  (sl_entity_get_storage (SL_ENTITY (self)))
+#define sl_person_commit(self, error) \
+  (sl_entity_commit (SL_ENTITY (self), error))
+
+#define sl_person_add_attribute(self, attr) \
+  (sl_entity_add_attribute (SL_ENTITY (self), attr))
+#define sl_person_remove_attribute(self, attr)  \
+  (sl_entity_remove_attribute (SL_ENTITY (self), attr))
+#define sl_person_has_attribute(self, attrname) \
+  (sl_entity_has_attribute (SL_ENTITY (self), attrname))
+#define sl_person_get_attribute(self, attrname) \
+  (sl_entity_get_attribute (SL_ENTITY (self), attrname))
+#define sl_person_get_attributes(self) \
+  (sl_entity_get_attributes (SL_ENTITY (self)))
+  
+#define sl_person_add(self, attrname, value) \
+  (sl_entity_add (SL_ENTITY (self), attrname, value))
+#define sl_person_get(self, attrname) \
+  (sl_entity_get (SL_ENTITY (self), attrname))
+#define sl_person_set(self, attrname, value) \
+  (sl_entity_set (SL_ENTITY (self), attrname, value))
+#define sl_person_get_at(self, attrname, index) \
+  (gpointer sl_entity_get_at (SL_ENTITY (self) attrname, index))
+#define sl_person_set_at(self, attrname, index, value) \
+  (sl_entity_set_at (SL_ENTITY (self), attrname, index, value))
+#define sl_person_remove_at(self, attrname, index) \
+  (sl_entity_remove_at (SL_ENTITY (self), attrname, index))
+#define sl_person_set_all(self, attrname, values) \
+  (sl_entity_set_all (SL_ENTITY (self), attrname, values))
+#define sl_person_get_all(self, attrname) \
+  (sl_entity_get_all (SL_ENTITY (self), attrname))
+#define sl_person_remove_all(self, attrname) \
+  (sl_entity_remove_all (SL_ENTITY (self), attrname))
+#define sl_person_modified(self, attrname) \
+  (sl_entity_modified (SL_ENTITY (self), attrname))
+#define sl_person_modified_at(self, attrname, index) \
+  (sl_entity_modified_at (SL_ENTITY (self), attrname, index))
+
 typedef struct _SlPersonClass SlPersonClass;
 typedef struct _SlPersonPriv  SlPersonPriv;
+  
+typedef struct _SlAddress SlAddress;
+typedef struct _SlName    SlName;
 
 struct _SlPerson
 {
@@ -56,9 +302,52 @@
   SlEntityClass parent;
 };
 
+struct _SlAddress
+{
+  gchar *country;
+  gchar *region;
+  gchar *city;
+  gchar *street;
+  gchar *postal_code;
+  gchar *addition;
+  gchar *po_box;
+};
+
+/**
+ * SlName:
+ * @names: string-list of given names
+ * @family_name: the family name
+ * @honoric_prefixes: string-list of honoric prefixes (e.g. Dr.)
+ * @honoric_suffixes: string-list of honoric suffixes (e.g. Jr.)
+ *
+ * A structured representation of a name.
+ */
+struct _SlName
+{
+  GList *names;
+  gchar *family_name;
+  GList *honoric_prefixes;
+  GList *honoric_suffixes;
+};
+
 GType sl_person_get_type (void);
 
-SlPerson *sl_person_new (const gchar *name);
-void sl_person_constr (SlPerson *self, const gchar *name);
+SlAddress *sl_address_new (void);
+SlName *sl_name_new (void);
+
+SlPerson *sl_person_new (const gchar *name, const gchar *family_name);
+SlPerson *sl_person_new_with_econtact (EContact *econtact);
+void sl_person_constr (SlPerson *self, const gchar *name, const gchar *family_name);
+void sl_person_constr_with_econtact (SlPerson *self, EContact *econtact);
+
+gchar *sl_person_get_name (SlPerson *self);
+void sl_person_set_name (SlPerson *self, gchar *name);
+gchar *sl_person_get_family_name (SlPerson *self);
+void sl_person_set_family_name (SlPerson *self, gchar *family_name);
+gchar *sl_person_get_full_name (SlPerson *self);
+void sl_person_set_full_name (SlPerson *self, gchar *fullname);
+
+gchar *sl_person_get_nick (SlPerson *self);
+void sl_person_set_nick (SlPerson *self, gchar *nick);
 
 #endif

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.c	Tue Aug 12 12:53:27 2008
@@ -22,11 +22,16 @@
  */
 
 #include "sl-priv-util.h"
+#include "sl-attribute-eds.h"
+
+#include <string.h>
+
+static GEqualFunc compare_equal;
 
 ESource *
 sl_priv_util_get_source (ESourceList *source_tree, const gchar *name)
 {
-  g_return_val_if_fail (name != NULL, FALSE);
+  g_return_val_if_fail (source_tree != NULL && name != NULL, NULL);
   
   GSList *groups = e_source_list_peek_groups (source_tree);
   for (; groups != NULL; groups = groups->next)
@@ -50,7 +55,371 @@
 ESourceGroup *
 sl_priv_util_source_tree_get_default_group (ESourceList *source_tree)
 {
+  g_return_val_if_fail (source_tree != NULL, NULL);
+  
   GSList *groups = e_source_list_peek_groups (source_tree);
   g_assert (groups != NULL);
   return groups->data;
 }
+
+gboolean sl_priv_util_lists_equal (GList *a, GList *b, GEqualFunc equal)
+{
+  g_return_val_if_fail (equal != NULL, FALSE);
+  
+  while (a != NULL && b != NULL)
+    {
+      if (!equal (a->data, b->data))
+        {
+          return FALSE;
+        }
+      a = a->next;
+      b = b->next;
+    }
+  
+  return (a == b);
+}
+
+static gint
+sl_priv_util_compare_by_equal (gconstpointer a, gconstpointer b)
+{
+  return !compare_equal (a, b);
+}
+
+gboolean
+sl_priv_util_list_contains (GList *list, gpointer data, GEqualFunc equal)
+{
+  g_return_val_if_fail (data != NULL && equal != NULL, FALSE);
+  
+  compare_equal = equal;
+  return (g_list_find_custom (list, data, sl_priv_util_compare_by_equal) != NULL);
+}
+
+void
+sl_priv_util_list_print (GList *list, const gchar *title)
+{
+  g_return_if_fail (title != NULL);
+  
+  g_print ("%s (%d):\n", title, g_list_length (list));
+  for (; list != NULL; list = list->next)
+    {
+      g_print (" * %s\n", (gchar *) list->data);
+    }
+}
+
+void
+sl_priv_util_eattribute_list_print (GList *eattributes, const gchar *title)
+{
+  g_return_if_fail (title != NULL);
+  
+  g_print ("%s (%d):\n", title, g_list_length (eattributes));
+  for (; eattributes != NULL; eattributes = eattributes->next)
+    {
+      EVCardAttribute *eattr = eattributes->data;
+      g_return_if_fail (eattr != NULL);
+      
+      g_print (" * %s\n", e_vcard_attribute_get_name (eattr));
+    }
+}
+
+void
+sl_priv_util_attribute_list_print (GList *attributes, const gchar *title)
+{
+  g_return_if_fail (title != NULL);
+  
+  g_print ("%s (%d):\n", title, g_list_length (attributes));
+  for (; attributes != NULL; attributes = attributes->next)
+    {
+      SlAttribute *attr = attributes->data;
+      g_print (" * %s\n", sl_attribute_get_name (attr));
+    }
+}
+
+void
+sl_priv_util_hash_table_print (GHashTable *table, const gchar *title)
+{
+  g_return_if_fail (table != NULL && title != NULL);
+  
+  GHashTableIter iter;
+  gpointer key = NULL;
+  gpointer value = NULL;
+  g_hash_table_iter_init (&iter, table);
+  g_print ("%s:\n", title);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      g_print (" * %s : %.8x\n", (gchar *) key, (guint) value);
+    }
+}
+
+void
+sl_priv_util_hash_table_print_keys (GHashTable *table, const gchar *title)
+{
+  g_return_if_fail (table != NULL && title != NULL);
+  
+  GList *keys = g_hash_table_get_keys (table);
+  sl_priv_util_list_print (keys, title);
+  g_list_free (keys);
+}
+
+gint
+sl_priv_util_compare_eattributes (EVCardAttribute *a, EVCardAttribute *b)
+{
+  g_return_val_if_fail (a != NULL && b != NULL, 0);
+  
+  const gchar *name_a = e_vcard_attribute_get_name (a);
+  const gchar *name_b = e_vcard_attribute_get_name (b);
+  return strcmp (name_a, name_b);
+}
+
+gboolean
+sl_priv_util_eattrlist_name_equal (GList *a, GList *b)
+{
+  g_return_val_if_fail (a != NULL && b != NULL, FALSE);
+  
+  const gchar *eattrname_a = e_vcard_attribute_get_name (a->data);
+  const gchar *eattrname_b = e_vcard_attribute_get_name (b->data);
+  return g_str_equal (eattrname_a, eattrname_b);
+}
+
+gboolean
+sl_priv_util_eattribute_equal (EVCardAttribute *a, EVCardAttribute *b)
+{
+  g_return_val_if_fail (a != NULL && b != NULL, FALSE);
+  
+  /* two eattributes are equal if their values are equal */
+  GList *evalues_a = e_vcard_attribute_get_values (a);
+  GList *evalues_b = e_vcard_attribute_get_values (b);
+  
+  return sl_priv_util_lists_equal (evalues_a, evalues_b, g_str_equal);
+}
+
+gboolean
+sl_priv_util_eattrlist_modified (GList *a, GList *b)
+{
+  g_return_val_if_fail (a != NULL && b != NULL, FALSE);
+  
+  /* TODO: ordering is taken into account here */
+  /* two lists of eattributes are modified if they are not equal */
+  
+  /* TODO: REMOVE AGAIN */
+  //return (!sl_priv_util_lists_equal (a, b, (GEqualFunc) sl_priv_util_eattribute_equal));
+  gboolean result = (!sl_priv_util_lists_equal (a, b, (GEqualFunc) sl_priv_util_eattribute_equal));
+  return result;
+}
+
+void
+sl_priv_util_list_set_diff (GList *a, GList *b, GEqualFunc equal, GList **added, GList **removed)
+{
+  sl_priv_util_list_set_diff_full (a, b, equal, NULL, added, removed, NULL, NULL);
+}
+
+void
+sl_priv_util_list_set_diff_full (GList *a, GList *b, GEqualFunc is_equal, GEqualFunc is_modified, GList **added, GList **removed, GList **modified, GList **rest)
+{
+  g_return_if_fail (is_equal != NULL);
+  
+  b = g_list_copy (b);
+  
+  sl_debug_util ("generating diff from two lists%s", "");
+  
+  if (added != NULL)
+    {
+      *added = NULL;
+    }
+  if (removed != NULL)
+    {
+      *removed = NULL;
+    }
+  if (modified != NULL)
+    {
+      *modified = NULL;
+    }
+  if (rest != NULL)
+    {
+      *rest = NULL;
+    }
+  GList *b_iter = NULL;
+  gboolean match = FALSE;
+  
+  for (; a != NULL; a = a->next)
+    {
+      match = FALSE;
+      b_iter = b;
+      
+      for (; b_iter != NULL; b_iter = b_iter->next)
+        {
+          if (is_equal (a->data, b_iter->data))
+            {
+              if (is_modified != NULL && is_modified (a->data, b_iter->data))
+                {
+                  if (modified != NULL)
+                    {
+                      *modified = g_list_append (*modified, a->data);
+                    }
+                }
+              else
+                {
+                  if (rest != NULL)
+                    {
+                      *rest = g_list_append (*rest, a->data);
+                    }
+                }
+              match = TRUE;
+              b = g_list_remove (b, b_iter->data);
+              break;
+            }
+        }
+      
+      if (!match)
+        {
+          if (added != NULL)
+            {
+              *added = g_list_append (*added, a->data);
+            }
+        }
+    }
+  
+  b_iter = b;
+  for (; b_iter != NULL; b_iter = b_iter->next)
+    {
+      if (removed != NULL)
+        {
+          *removed = g_list_append (*removed, b_iter->data);
+        }
+    }
+  
+  g_list_free (b);
+}
+
+/*
+ * (d, d, b, a, c, d, a) -> ((a, a), (b), (c), (d, d, d))
+ */
+GList *
+sl_priv_util_eattribute_flat_to_deep_list (GList *flat)
+{ 
+  sl_debug_util ("generating deep eattribute list from flat eattribute list%s", "");
+  
+  GList *deep = NULL;
+  flat = g_list_copy (flat);
+  flat = g_list_sort (flat, (GCompareFunc) sl_priv_util_compare_eattributes);
+  
+  for (; flat != NULL; flat = flat->next)
+    {
+      EVCardAttribute *eattr = flat->data;
+      g_assert (eattr != NULL);
+      const gchar *eattrname = e_vcard_attribute_get_name (eattr);
+      GList *eattrlist = g_list_append (NULL, eattr);
+      
+      while (TRUE)
+        {
+          GList *next = flat->next;
+          if (next == NULL || !g_str_equal (e_vcard_attribute_get_name (next->data), eattrname))
+            {
+              break;
+            }
+          flat = flat->next;
+          eattr = flat->data;
+          eattrlist = g_list_append (eattrlist, eattr);
+        }
+      
+      deep = g_list_append (deep, eattrlist);
+    }
+  
+  g_list_free (g_list_first (flat));
+  return deep;
+}
+
+void
+sl_priv_util_eattribute_deep_list_free (GList *deep)
+{
+  for (; deep != NULL; deep = deep->next)
+    {
+      g_list_free (deep->data);
+    }
+  g_list_free (deep);
+}
+
+
+/**
+ * sl_priv_util_strsplit_list:
+ * @string: a string to split
+ * @delimiter: a delimiter for splitting
+ * @max_tokens: the maximum number of tokens to split the string into. If it is
+ * less than 1, the string is split completly.
+ *
+ * Splits a string into a list of tokens. See g_strsplit() for more information
+ * on splitting strings.
+ *
+ * Returns: a list of strings (i.e. the tokens of the splitted string). The list
+ * should be freed with g_list_free().
+ */
+GList *sl_priv_util_strsplit_list (gchar *string, gchar *delimiter, gint max_tokens)
+{
+  /* g_strsplit checks all arguments */
+  gchar **tokens = g_strsplit (string, delimiter, max_tokens);
+  GList *list = sl_priv_util_strv_to_list (tokens);
+  g_free (tokens);
+  return list;
+}
+
+/**
+ * sl_priv_util_strjoin_list:
+ * @seperator: a seperator that should be inserted between the strings
+ * @strings: a list of strings that should be joined together
+ *
+ * Joins a list of strings together to one string. See g_strjoinv() for more
+ * information on joining strings.
+ *
+ * Returns: the joined string. The string should be freed with g_free().
+ */
+gchar *sl_priv_util_strjoin_list (gchar *seperator, GList *strings)
+{
+  /* g_strjoinv checks seperator, sl_priv_util_list_to_strv checks strings */
+  gchar **tokens = sl_priv_util_list_to_strv (strings);
+  gchar *string = g_strjoinv (seperator, tokens);
+  g_free (tokens);
+  return string;
+}
+
+/**
+ * sl_priv_util_strv_to_list:
+ * @strv: a NULL-terminated array of strings
+ *
+ * Creates a list of strings from a NULL-terminated array of strings. The items
+ * in the list will point to the same locations as the items in the array.
+ *
+ * Returns: a list of strings. The list should be freed with g_list_free().
+ */
+GList *sl_priv_util_strv_to_list (gchar **strv)
+{
+  g_return_val_if_fail (strv != NULL, NULL);
+  
+  GList *list = NULL;
+  for (; *strv != NULL; strv++)
+    {
+      list = g_list_prepend (list, *strv);
+    }
+  return g_list_reverse (list);
+}
+
+/**
+ * sl_priv_util_list_to_strv:
+ * @strings: a list of strings
+ *
+ * Creates a NULL-terminated array of strings from a list of strings. The items
+ * in the array will point to the same locations as the items in the list.
+ *
+ * Returns: a NULL-terminated array of strings. The array should be freed with
+ * g_free().
+ */
+gchar **sl_priv_util_list_to_strv (GList *strings)
+{
+  gchar **strv = g_new (gchar *, g_list_length (strings) + 1);
+  gchar **strvp = strv;
+  for (; strings != NULL; strings = strings->next)
+    {
+      *strvp = strings->data;
+      strvp++;
+    }
+  *strvp = NULL;
+  return strv;
+}

Modified: branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/sl-priv-util.h	Tue Aug 12 12:53:27 2008
@@ -21,13 +21,72 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#ifndef SL_PRIVUTIL_H
-#define SL_PRIVUTIL_H
+#ifndef SL_PRIV_UTIL_H
+#define SL_PRIV_UTIL_H
 
 #include <libebook/e-book.h>
 
+/*#define SL_ENABLE_DEBUG_ALL*/
+
+#define sl_debug(unit, format, ...) g_printerr ("dbg[%s]: ", unit); \
+                                    g_printerr (format, __VA_ARGS__); \
+                                    g_printerr ("\n")
+
+#ifdef SL_ENABLE_DEBUG_ALL
+  #define SL_ENABLE_DEBUG_BOOK
+  #define SL_ENABLE_DEBUG_ENTITY
+  #define SL_ENABLE_DEBUG_ATTRIBUTE
+  #define SL_ENABLE_DEBUG_UTIL
+#endif
+
+#ifdef SL_ENABLE_DEBUG_BOOK
+  #define sl_debug_book(format, ...) sl_debug ("Book", format, __VA_ARGS__)
+#else
+  #define sl_debug_book(format, ...)
+#endif
+#ifdef SL_ENABLE_DEBUG_ENTITY
+  #define sl_debug_entity(format, ...) sl_debug ("Entity", format, __VA_ARGS__)
+#else
+  #define sl_debug_entity(format, ...)
+#endif
+#ifdef SL_ENABLE_DEBUG_ATTRIBUTE
+  #define sl_debug_attribute(format, ...) sl_debug ("Attribute", format, __VA_ARGS__)
+#else
+  #define sl_debug_attribute(format, ...)
+#endif
+#ifdef SL_ENABLE_DEBUG_UTIL
+  #define sl_debug_util(format, ...) sl_debug ("Util", format, __VA_ARGS__)
+#else
+  #define sl_debug_util(format, ...)
+#endif
+
 ESource *sl_priv_util_get_source (ESourceList *source_tree, const gchar *name);
 ESourceGroup *sl_priv_util_source_tree_get_default_group
   (ESourceList *source_tree);
 
+gboolean sl_priv_util_lists_equal (GList *a, GList *b, GEqualFunc equal);
+gboolean sl_priv_util_list_contains (GList *list, gpointer data, GEqualFunc equal);
+void sl_priv_util_hash_table_print (GHashTable *table, const gchar *title);
+void sl_priv_util_hash_table_print_keys (GHashTable *table, const gchar *title);
+void sl_priv_util_list_print (GList *list, const gchar *title);
+void sl_priv_util_eattribute_list_print (GList *eattributes, const gchar *title);
+void sl_priv_util_attribute_list_print (GList *attributes, const gchar *title);
+
+gint sl_priv_util_compare_eattributes (EVCardAttribute *a, EVCardAttribute *b);
+
+gboolean sl_priv_util_eattrlist_name_equal (GList *a, GList *b);
+gboolean sl_priv_util_eattribute_equal (EVCardAttribute *a, EVCardAttribute *b);
+gboolean sl_priv_util_eattrlist_modified (GList *a, GList *b);
+
+void sl_priv_util_list_set_diff (GList *a, GList *b, GEqualFunc equal, GList **added, GList **removed);
+void sl_priv_util_list_set_diff_full (GList *a, GList *b, GEqualFunc is_equal, GEqualFunc is_modified, GList **added, GList **removed, GList **modified, GList **rest);
+
+GList *sl_priv_util_eattribute_flat_to_deep_list (GList *flat);
+void sl_priv_util_eattribute_deep_list_free (GList *deep);
+
+GList *sl_priv_util_strsplit_list (gchar *string, gchar *delimiter, gint max_tokens);
+gchar *sl_priv_util_strjoin_list (gchar *seperator, GList *strings);
+GList *sl_priv_util_strv_to_list (gchar **strv);
+gchar **sl_priv_util_list_to_strv (GList *strings);
+
 #endif

Modified: branches/libsoylent-v0.4.0/libsoylent/soylent.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/soylent.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/soylent.c	Tue Aug 12 12:53:27 2008
@@ -21,7 +21,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "config.h"
 #include "soylent.h"
 
 #include <glib-object.h>
@@ -30,5 +29,12 @@
 sl_init (GError **error)
 {
 	g_type_init ();
+  sl_attributes_init ();
 	return sl_book_setup (error);
 }
+
+void
+sl_cleanup (void)
+{
+  sl_attributes_cleanup ();
+}

Modified: branches/libsoylent-v0.4.0/libsoylent/soylent.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/soylent.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/soylent.h	Tue Aug 12 12:53:27 2008
@@ -21,17 +21,31 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/*
+ * general things that have to be changed / added
+ * ---
+ * TODO: add an SlBookManager (responsible for receiving signals when a book is
+ * created / deleted)
+ * TODO: add an sl_book_open method (one should be able to connect signals
+ * before a book is used, so no events get lost)
+ * TODO: SlBook should be derived from SlStorage
+ * TODO: add on_purpose to signals (TRUE if the user made a change explicitly
+ * (e.g. by calling add_attribute), FALSE if not (i.e. the backend reports a
+ * a change))                                                  
+ */
+
 #ifndef SOYLENT_H
 #define SOYLENT_H
 
+#include "config.h"
+#include "sl-marshal.h"
+#include "sl-mutual-inclusion.h"
 #include "sl-entity.h"
-#include "sl-entity-handler.h"
-#include "sl-entity-handler-eds.h"
-#include "sl-entity-handler-file.h"
-#include "sl-person.h"
+#include "sl-attribute.h"
+#include "sl-attributes.h"
 #include "sl-group.h"
-#include "sl-book.h"
 
 gboolean sl_init (GError **error);
+void sl_cleanup (void);
 
 #endif

Modified: branches/libsoylent-v0.4.0/libsoylent/test/test-book.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/test/test-book.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/test/test-book.c	Tue Aug 12 12:53:27 2008
@@ -28,6 +28,9 @@
 int
 main (int argc, char **argv)
 {
+  /* disabled because of addressbook-bug */
+  test_success ();
+  
   GError *error = NULL;
   const gchar *testbookname = "testbook";
   const gchar *testbookname_wrong = "testbook23";

Modified: branches/libsoylent-v0.4.0/libsoylent/test/test-playground.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/test/test-playground.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/test/test-playground.c	Tue Aug 12 12:53:27 2008
@@ -21,25 +21,51 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/* TODO
+ * test1: add attributes and values to a predefined addressbrook and check if all
+ * changes are as expected
+ * test2: run test1 and check if all signals are emitted correctly; after that
+ * check like in test1 if all changes are as expected
+ *
+ * signal-tests:
+ * [x] add person
+ * [x] remove person
+ * [x] add attribute w/ 1 value
+ * [x] add attribute w/ x values
+ * [x] remove attribute w/ 1 value
+ * [x] remove attribute w/ x values
+ * [x] modify: modify value
+ * [x] modify: add and remove values to / from attribute
+ * [x] + some combinations of the above
+ */
+
 #include "test.h"
 
 int
 main (int argc, char **argv)
 {
+  /* disabled for release */
+  test_success ();
+  
   GError *error = NULL;
   
   test_init ("Playground");
   test_soylent_init ();
   
-  /* known bug 3 forces us to use the system-addressbook, but we don't want
-   to modify it, so just skip this test */
-  test_success ();
-  
   SlBook *testbook = test_setup_testbook ();
   
+  /* print all attributes from all people
+  GList *people = sl_book_get_people (testbook);
+  for (; people != NULL; people = people->next)
+    {
+      SlPerson *person = people->data;
+      test_print_attributes (person);
+    }
+  */
+
   test_print ("creating some people");
-  SlPerson *person_tim = sl_person_new ("Tim");
-  SlPerson *person_joe = sl_person_new ("Joe");
+  SlPerson *person_tim = sl_person_new ("Tim", "Smith");
+  SlPerson *person_joe = sl_person_new ("Joe", "Miller");
   
   test_print ("adding \"Tim\" and \"Joe\" to the addressbook");
   if (!sl_book_add_person (testbook, person_tim, &error) ||
@@ -54,6 +80,23 @@
       test_fail ("couldn't remove person from addressbook: %s", error->message);
     }
   
+  SlAttribute *attr = sl_attribute_new_empty ("url");
+  sl_attribute_add (attr, "http://www.kalterregen.de";);
+  sl_attribute_add (attr, "http://planet.gnome.org";);
+  
+  if (!sl_attribute_set_at (attr, 0, "http://www.firefox.com";))
+    {
+      test_fail ("couldn't set value at a given index");
+    }
+  
+  sl_entity_add_attribute (SL_ENTITY (person_joe), attr);
+  g_object_unref (attr);
+  
+  if (!sl_person_commit (person_joe, &error))
+    {
+      test_fail ("couldn't commit changes of \"Joe\": %s", error->message);
+    }
+  
   g_object_unref (person_tim);
   g_object_unref (person_joe);
   

Modified: branches/libsoylent-v0.4.0/libsoylent/test/test.c
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/test/test.c	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/test/test.c	Tue Aug 12 12:53:27 2008
@@ -38,11 +38,13 @@
 SlBook *
 test_setup_testbook (void)
 {
-  GError *error = NULL;
-  /*const gchar *testbookname = "testbook";
-  SlBook *testbook = sl_book_create (testbookname, &error);*/
   /* workaround for known bug 3 */
-  SlBook *testbook = sl_book_open_default (&error);
+  SlBook *t = SL_BOOK_DEFAULT;
+  return t;
+  
+  GError *error = NULL;
+  const gchar *testbookname = "testbook";
+  SlBook *testbook = sl_book_create (testbookname, &error);
   if (testbook == NULL)
     {
       /* TODO: quit test here...*/
@@ -64,3 +66,32 @@
     }
   g_object_unref (testbook);
 }
+
+void
+test_print_attributes (SlPerson *person)
+{
+  test_print ("--- %s ---", sl_person_get_nick (person));
+  GList *attributes = sl_entity_get_attributes (SL_ENTITY (person));
+  for (; attributes != NULL; attributes = attributes->next)
+    {
+      SlAttribute *attr = attributes->data;
+      test_print_attribute (attr);
+    }
+}
+
+void
+test_print_attribute (SlAttribute *attr)
+{
+  test_print (" * %s", sl_attribute_get_name (attr));
+  GList *values = sl_attribute_get_all (attr);
+  int i = 0;
+  int length = g_list_length (values);
+  for (i = 0; i < length; i++)
+    {
+      /* TODO: this is only possible because we know all attributes are
+       * strings. In future some to_string () functionality is needed?
+       */
+      test_print ("   * %s", (gchar *) values->data);
+      values = values->next;
+    }
+}

Modified: branches/libsoylent-v0.4.0/libsoylent/test/test.h
==============================================================================
--- branches/libsoylent-v0.4.0/libsoylent/test/test.h	(original)
+++ branches/libsoylent-v0.4.0/libsoylent/test/test.h	Tue Aug 12 12:53:27 2008
@@ -46,5 +46,7 @@
 void test_soylent_init (void);
 SlBook *test_setup_testbook (void);
 void test_clean_testbook (SlBook *testbook);
+void test_print_attributes (SlPerson *person);
+void test_print_attribute (SlAttribute *attr);
 
 #endif



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