[folks] Added new properties to the Telepathy backends.



commit a5ef0adc0c5accb2b90640b8c57fb8febdf0571c
Author: Seif Lotfy <seif lotfy collabora co uk>
Date:   Wed May 23 14:47:25 2012 +0200

    Added new properties to the Telepathy backends.
    
    The Telepathy backend requires Zeitgeist to pull its info.
    
    Signed-off-by: Seif Lotfy <seif lotfy collabora co uk>

 backends/telepathy/lib/Makefile.am            |    7 ++
 backends/telepathy/lib/tpf-persona-store.vala |  130 ++++++++++++++++++++++++-
 backends/telepathy/lib/tpf-persona.vala       |  103 +++++++++++++++++++
 configure.ac                                  |   29 ++++++
 4 files changed, 268 insertions(+), 1 deletions(-)
---
diff --git a/backends/telepathy/lib/Makefile.am b/backends/telepathy/lib/Makefile.am
index 77c75f3..ac30174 100644
--- a/backends/telepathy/lib/Makefile.am
+++ b/backends/telepathy/lib/Makefile.am
@@ -146,6 +146,13 @@ libfolks_telepathy_la_LIBADD = \
 	$(top_builddir)/folks/libfolks-internal.la \
 	$(NULL)
 
+if ENABLE_ZEITGEIST
+libfolks_telepathy_la_VALAFLAGS += --pkg zeitgeist-1.0
+libfolks_telepathy_la_VALAFLAGS += --define=HAVE_ZEITGEIST
+libfolks_telepathy_la_CFLAGS += $(ZEITGEIST_CFLAGS)
+libfolks_telepathy_la_LIBADD += $(ZEITGEIST_LIBS)
+endif
+
 # The quoting here is unnecessary but harmless, and has the useful side-effect
 # that vim quickfix mode (:make) doesn't interpret the libtool --mode=link
 # command as an error message in a bizarrely named file
diff --git a/backends/telepathy/lib/tpf-persona-store.vala b/backends/telepathy/lib/tpf-persona-store.vala
index cb04c0d..61189c2 100644
--- a/backends/telepathy/lib/tpf-persona-store.vala
+++ b/backends/telepathy/lib/tpf-persona-store.vala
@@ -24,7 +24,9 @@ using GLib;
 using Gee;
 using TelepathyGLib;
 using Folks;
-
+#if HAVE_ZEITGEIST
+using Zeitgeist;
+#endif
 extern const string G_LOG_DOMAIN;
 extern const string BACKEND_NAME;
 
@@ -85,6 +87,11 @@ public class Tpf.PersonaStore : Folks.PersonaStore
 
   private Account _account;
 
+#if HAVE_ZEITGEIST
+  private Zeitgeist.Log? _log= null;
+  private Zeitgeist.Monitor? _monitor = null;
+#endif
+
   /**
    * The Telepathy account this store is based upon.
    */
@@ -1022,6 +1029,12 @@ public class Tpf.PersonaStore : Folks.PersonaStore
           new GLib.GenericArray<TelepathyGLib.Contact> ());
 
       this._got_initial_members = true;
+#if HAVE_ZEITGEIST
+          if (this._monitor == null)
+            {
+              this._populate_counters ();
+            }
+#endif
       this._notify_if_is_quiescent ();
     }
 
@@ -1529,4 +1542,119 @@ public class Tpf.PersonaStore : Folks.PersonaStore
 
       return store;
     }
+
+#if HAVE_ZEITGEIST
+  private string? _get_iid_from_event_metadata (string? uri) 
+    {
+      /* Format a proper id represting a persona in the store.
+       * Zeitgeist uses x-telepathy-identifier as a prefix for telepathy, which 
+       * is stored as the uri of a subject of an event. */
+      if (uri == null)
+        {
+          return null;
+        }
+      var new_uri = uri.replace ("x-telepathy-identifier:", "");
+      return this.account.protocol + ":" + new_uri;
+    }
+  
+  private void _increase_persona_counter (string? id, string? interaction_type, Event event)
+    {
+      /* Check if the persona id and interaction is valid. If so increase the
+       * appropriate interacton counter, to signify that an
+       * interaction was successfully counted. */
+      if (id != null && this._personas.has_key (id) && interaction_type != null)
+        {
+          var persona = this._personas.get (id);
+          persona._increase_counter (id, interaction_type, event);
+        }
+    }
+
+  private void _handle_new_interaction (TimeRange timerange, ResultSet events)
+    {
+      foreach (var e in events)
+        {
+          for (var i = 1; i < e.num_subjects (); i++)
+            {
+              var id = this._get_iid_from_event_metadata (e.get_subject (i).get_uri ());
+              var interaction_type = e.get_subject (0).get_interpretation ();
+              this._increase_persona_counter (id, interaction_type, e);
+            }
+        }
+    }
+
+  private PtrArray _get_zeitgeist_event_templates ()
+    {
+      /* To fetch events from Zeitgeist about the interaction with contacts we
+       * create templates reflecting how the telepathy-logger stores events in
+       * Zeitgeist */
+      var origin = this.id.replace (TelepathyGLib.ACCOUNT_OBJECT_PATH_BASE,
+                                    "x-telepathy-account-path:");
+
+      Event ev1 = new Event.full ("", "", "dbus://org.freedesktop.Telepathy.Logger.service");
+      ev1.add_subject (new Subject.full ("", Zeitgeist.NMO_IMMESSAGE, "", "", "", "", ""));
+      ev1.set_origin (origin);
+
+      Event ev2 = new Event.full ("", "", "dbus://org.freedesktop.Telepathy.Logger.service");
+      ev2.add_subject (new Subject.full ("", "", Zeitgeist.NFO_MEDIA_STREAM, "", "", "", ""));
+      ev2.set_origin (origin);
+
+      var templates = new PtrArray ();
+      templates.add (ev1.ref ());
+      templates.add (ev2.ref ());
+      return templates;
+    }
+
+  private async void _populate_counters ()
+    {
+      this._log = new Zeitgeist.Log ();
+
+      /* Prepare a monitor for this account to populate the counters upon
+       * interaction changes */
+      if (this._monitor == null)
+        {
+          PtrArray monitor_events = this._get_zeitgeist_event_templates ();
+          this._monitor = new Zeitgeist.Monitor (new Zeitgeist.TimeRange.from_now (),
+              (owned) monitor_events);
+          this._monitor.events_inserted.connect (this._handle_new_interaction);
+        }
+
+      /* Get all events for this account from Zeitgeist and increase the
+       * the counters of the personas */
+      try 
+        {
+          PtrArray events = this._get_zeitgeist_event_templates ();
+          var results = yield this._log.find_events (new TimeRange.anytime (),
+              (owned) events, StorageState.ANY, 0, ResultType.MOST_RECENT_EVENTS,
+              null);
+
+          foreach (var persona in this.personas.values)
+            {
+              persona.freeze_notify ();
+            }
+          foreach (var e in results)
+            {
+              var interaction_type = e.get_subject (0).get_interpretation ();
+              for (var i = 1; i < e.num_subjects (); i++)
+                {
+                  var id = this._get_iid_from_event_metadata (e.get_subject (i).get_uri ());
+                  this._increase_persona_counter (id, interaction_type, e);
+                }
+            }
+          foreach (var persona in this.personas.values)
+            {
+              persona.thaw_notify ();
+            }
+        }
+      catch
+        {
+          warning ("Failed to fetch events from Zeitgeist");
+        }
+
+      /* Install the monitor for this account to be notified when a persona has 
+       * been interacted with */
+      this._log.install_monitor (this._monitor);
+
+      this._notify_if_is_quiescent ();
+    }
+#endif
 }
diff --git a/backends/telepathy/lib/tpf-persona.vala b/backends/telepathy/lib/tpf-persona.vala
index c5dffd8..d3c8ded 100644
--- a/backends/telepathy/lib/tpf-persona.vala
+++ b/backends/telepathy/lib/tpf-persona.vala
@@ -22,6 +22,9 @@ using Gee;
 using GLib;
 using TelepathyGLib;
 using Folks;
+#if HAVE_ZEITGEIST
+using Zeitgeist;
+#endif
 
 /**
  * A persona subclass which represents a single instant messaging contact from
@@ -34,6 +37,7 @@ public class Tpf.Persona : Folks.Persona,
     EmailDetails,
     FavouriteDetails,
     GroupDetails,
+    InteractionDetails,
     ImDetails,
     NameDetails,
     PhoneDetails,
@@ -388,6 +392,64 @@ public class Tpf.Persona : Folks.Persona,
       set { this.change_im_addresses.begin (value); }
     }
 
+  private uint _im_interaction_count = 0;
+
+  /**
+   * A counter for IM interactions (send/receive message) with the persona.
+   *
+   * See { link Folks.InteractionDetails.im_interaction_count}
+   *
+   * @since UNRELEASED
+   */
+  public uint im_interaction_count
+    {
+      get { return this._im_interaction_count; }
+    }
+
+  internal DateTime? _last_im_interaction_datetime = null;
+
+  /**
+   * The latest datetime for IM interactions (send/receive message) with the
+   * persona.
+   *
+   * See { link Folks.InteractionDetails.last_im_interaction_datetime}
+   *
+   * @since UNRELEASED
+   */
+  public DateTime? last_im_interaction_datetime
+    {
+      get { return this._last_im_interaction_datetime; }
+    }
+
+  private uint _call_interaction_count = 0;
+
+  /**
+   * A counter for call interactions (only successful calls) with the persona.
+   *
+   * See { link Folks.InteractionDetails.call_interaction_count}
+   *
+   * @since UNRELEASED
+   */
+  public uint call_interaction_count
+    {
+      get { return this._call_interaction_count; }
+    }
+
+  internal DateTime? _last_call_interaction_datetime = null;
+
+  /**
+   * The latest datetime for call interactions (only successful calls) with the
+   * persona.
+   *
+   * See { link Folks.InteractionDetails.last_call_interaction_datetime}
+   *
+   * @since UNRELEASED
+   */
+  public DateTime? last_call_interaction_datetime
+    {
+      get { return this._last_call_interaction_datetime; }
+    }
+
   private HashSet<string> _groups = new HashSet<string> ();
   private Set<string> _groups_ro;
 
@@ -1136,4 +1198,45 @@ public class Tpf.Persona : Folks.Persona,
       var store = PersonaStore.dup_for_account (account);
       return store._ensure_persona_for_contact (contact);
     }
+
+#if HAVE_ZEITGEIST
+  internal void _increase_counter (string id, string interaction_type, Event event)
+    {
+      var timestamp = (uint) (event.get_timestamp () / 1000);
+      var converted_datetime = new DateTime.from_unix_utc (timestamp);
+      var interpretation = event.get_interpretation ();
+
+      /* Only count send/receive for IM interactions */
+      if (interaction_type == Zeitgeist.NMO_IMMESSAGE &&
+          (interpretation == Zeitgeist.ZG_SEND_EVENT ||
+           interpretation == Zeitgeist.ZG_RECEIVE_EVENT))
+        {
+          this._im_interaction_count++;
+          this.notify_property ("im-interaction-count");
+          if (this._last_im_interaction_datetime == null ||
+              this._last_im_interaction_datetime.compare (converted_datetime) == -1)
+            {
+              this._last_im_interaction_datetime = converted_datetime;
+              this.notify_property ("last-im-interaction-datetime");
+            }
+          debug ("Persona %s IM interaction details changed:\n - count: %u \n - timestamp: %lld\n",
+              id, this._im_interaction_count, this._last_im_interaction_datetime.format ("%H %M %S - %d %m %y"));
+        }
+      /* Only count successful call for call interactions */
+      else if (interaction_type == Zeitgeist.NFO_AUDIO &&
+                interpretation == Zeitgeist.ZG_LEAVE_EVENT)
+        {
+          this._call_interaction_count++;
+          this.notify_property ("call-interaction-count");
+          if (this._last_call_interaction_datetime == null ||
+              this._last_call_interaction_datetime.compare (converted_datetime) == -1)
+            { 
+              this._last_call_interaction_datetime = converted_datetime;
+              this.notify_property ("last-call-interaction-datetime");
+            }
+          debug ("Persona %s Call interaction details changed:\n - count: %u \n - timestamp: %lld\n",
+             id, this._call_interaction_count, this._last_call_interaction_datetime.format ("%H %M %S - %d %m %y"));
+        }
+    }
+#endif
 }
diff --git a/configure.ac b/configure.ac
index 1fed8c8..15bd756 100644
--- a/configure.ac
+++ b/configure.ac
@@ -101,6 +101,24 @@ fi
 
 AM_CONDITIONAL([ENABLE_EDS], [test "x$enable_eds_backend" = "xyes"])
 
+
+AC_ARG_ENABLE(zeitgeist,
+        AC_HELP_STRING([--enable-zeitgeist],
+                       [ build the Zeitgeist]),
+        enable_zeitgeist=$enableval,
+        enable_zeitgeist=no )
+
+AM_CONDITIONAL([ENABLE_ZEITGEIST], [test "x$enable_zeitgeist" = "xyes"])
+
+if test "x$enable_zeitgeist" = "xyes"; then
+        AC_DEFINE(HAVE_ZEITGEIST, [1],
+                  [Define as 1 if you have the Zeitgeist support])
+else
+        AC_DEFINE(HAVE_ZEITGEIST, [0],
+                  [Define as 1 if you have the Zeitgeist support])
+fi
+
+
 # Automatically check the dependencies for the libsocialweb backend
 SW_CLIENT_REQUIRED=0.25.20
 AC_ARG_ENABLE(libsocialweb-backend,
@@ -152,6 +170,7 @@ TRACKER_SPARQL_MAJOR=0.14
 TRACKER_SPARQL_REQUIRED=0.13.1
 EBOOK_REQUIRED=3.1.5
 EDATASERVER_REQUIRED=3.1.5
+ZEITGEIST_REQUIRED=0.3.14
 
 AC_SUBST([TRACKER_SPARQL_MAJOR])
 
@@ -194,6 +213,10 @@ if test x$enable_eds_backend = xyes; then
         PKG_CHECK_MODULES([EDATASERVER], [libedataserver-1.2 >= $EDATASERVER_REQUIRED])
 fi
 
+if test x$enable_zeitgeist = xyes; then
+        PKG_CHECK_MODULES([ZEITGEIST], [zeitgeist-1.0 >= $ZEITGEIST_REQUIRED])
+fi
+
 #
 # Vala building options -- allows tarball builds without installing Vala
 #
@@ -276,6 +299,11 @@ if test "x$enable_vala" = "xyes" ; then
         if test x$enable_eds_backend = xyes; then
           VALA_CHECK_PACKAGES([libebook-1.2 libedataserver-1.2 libxml-2.0])
         fi
+
+        if test x$enable_zeitgeist = xyes; then
+          VALA_CHECK_PACKAGES([zeitgeist-1.0])
+        fi
+
 fi
 
 # this will set HAVE_INTROSPECTION
@@ -584,5 +612,6 @@ Configure summary:
         Tracker backend.............:  ${enable_tracker_backend}
         Libsocialweb backend........:  ${have_libsocialweb_backend}
         E-D-S backend...............:  ${enable_eds_backend}
+        Zeitgeist support...........:  ${enable_zeitgeist}
 
 "



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