The Telepathy backend requires Zeitgeist to pull its info.
Signed-off-by: Seif Lotfy <seif.lotfy@collabora.co.uk>
$(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
using Gee;
using TelepathyGLib;
using Folks;
-
+#if HAVE_ZEITGEIST
+using Zeitgeist;
+#endif
extern const string G_LOG_DOMAIN;
extern const string BACKEND_NAME;
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.
*/
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 ();
}
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
}
using GLib;
using TelepathyGLib;
using Folks;
+#if HAVE_ZEITGEIST
+using Zeitgeist;
+#endif
/**
* A persona subclass which represents a single instant messaging contact from
EmailDetails,
FavouriteDetails,
GroupDetails,
+ InteractionDetails,
ImDetails,
NameDetails,
PhoneDetails,
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;
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
}
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,
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])
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
#
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
Tracker backend.............: ${enable_tracker_backend}
Libsocialweb backend........: ${have_libsocialweb_backend}
E-D-S backend...............: ${enable_eds_backend}
+ Zeitgeist support...........: ${enable_zeitgeist}
"