aboutsummaryrefslogtreecommitdiff
path: root/src/datetime-service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/datetime-service.c')
-rw-r--r--src/datetime-service.c229
1 files changed, 175 insertions, 54 deletions
diff --git a/src/datetime-service.c b/src/datetime-service.c
index cc6c9d5..1f3eac6 100644
--- a/src/datetime-service.c
+++ b/src/datetime-service.c
@@ -42,6 +42,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libical/ical.h>
#include <libecal/e-cal-time-util.h>
#include <libedataserver/e-source.h>
+#include <libedataserverui/e-passwords.h>
// Other users of ecal seem to also include these, not sure why they should be included by the above
#include <libical/icaltime.h>
#include <cairo/cairo.h>
@@ -58,6 +59,8 @@ static void geo_create_client (GeoclueMaster * master, GeoclueMasterClient * cli
static gboolean update_appointment_menu_items (gpointer user_data);
static gboolean update_timezone_menu_items(gpointer user_data);
static void setup_timer (void);
+static void geo_client_invalid (GeoclueMasterClient * client, gpointer user_data);
+static void geo_address_change (GeoclueMasterClient * client, gchar * a, gchar * b, gchar * c, gchar * d, gpointer user_data);
static IndicatorService * service = NULL;
static GMainLoop * mainloop = NULL;
@@ -83,14 +86,10 @@ GSettings *conf;
static GeoclueMasterClient * geo_master = NULL;
static GeoclueAddress * geo_address = NULL;
-/* Our 3 important timezones */
-static const gchar * ecal_timezone = NULL;
+/* Our 2 important timezones */
static gchar * current_timezone = NULL;
static gchar * geo_timezone = NULL;
-static ECal * ecal = NULL;
-static icaltimezone * tzone;
-
/* Check to see if our timezones are the same */
static void
check_timezone_sync (void) {
@@ -143,9 +142,8 @@ check_timezone_sync (void) {
if (label != NULL) {
// TODO work out the current location name in a nice way
- dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_LABEL, label);
+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, label);
// TODO work out the current time at that location
- dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
} else {
@@ -153,22 +151,19 @@ check_timezone_sync (void) {
}
if (geo_timezone != NULL) {
// TODO work out the geo location name in a nice way
- dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_LABEL, geo_timezone);
+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, geo_timezone);
// TODO work out the current time at that location
- dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
}
} else {
// TODO work out the geo location name in a nice way
- dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_LABEL, geo_timezone);
+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, geo_timezone);
// TODO work out the current time at that location
- dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
dbusmenu_menuitem_property_set_bool(geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
// TODO work out the current location name in a nice way
- dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_LABEL, current_timezone);
+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, current_timezone);
// TODO work out the current time at that location
- dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
dbusmenu_menuitem_property_set_bool(current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
dbusmenu_menuitem_property_set_bool(locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
@@ -230,7 +225,7 @@ quick_set_tz_cb (OobsObject * obj, OobsResult result, gpointer user_data)
static void
quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data)
{
- const gchar * tz = dbusmenu_menuitem_property_get(menuitem, TIMEZONE_MENUITEM_PROP_LABEL);
+ const gchar * tz = dbusmenu_menuitem_property_get(menuitem, TIMEZONE_MENUITEM_PROP_ZONE);
g_debug("Quick setting timezone to: %s", tz);
@@ -303,7 +298,7 @@ check_for_calendar (gpointer user_data)
g_debug("Found the calendar application: %s", evo);
dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-
+/*
GError *gerror = NULL;
// TODO: In reality we should iterate sources of calendar, but getting the local one doens't lag for > a minute
g_debug("Setting up ecal.");
@@ -327,13 +322,13 @@ check_for_calendar (gpointer user_data)
ecal = NULL;
}
- /* This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
+ This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
* this means we'll have some geoclue interaction going on, and possibly the user will be involved in setting
* their location manually, case in point: trains have satellite links which often geoclue to sweden,
* this shouldn't automatically set the location and mess up all the appointments for the user.
- */
+
if (ecal) ecal_timezone = icaltimezone_get_tzid(tzone);
-
+ */
DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
dbusmenu_menuitem_child_add_position(root, separator, 3);
@@ -358,6 +353,7 @@ check_for_calendar (gpointer user_data)
return FALSE;
}
+
static gboolean
update_timezone_menu_items(gpointer user_data) {
g_debug("Updating timezone menu items");
@@ -402,8 +398,7 @@ update_timezone_menu_items(gpointer user_data) {
g_debug("Adding timezone in update_timezones %s", locations[i]);
item = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
- dbusmenu_menuitem_property_set (item, TIMEZONE_MENUITEM_PROP_LABEL, locations[i]);
- dbusmenu_menuitem_property_set (item, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+ dbusmenu_menuitem_property_set (item, TIMEZONE_MENUITEM_PROP_ZONE, locations[i]);
dbusmenu_menuitem_property_set_bool (item, TIMEZONE_MENUITEM_PROP_RADIO, FALSE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
@@ -417,6 +412,35 @@ update_timezone_menu_items(gpointer user_data) {
return FALSE;
}
+// Authentication function
+static gchar *
+auth_func (ECal *ecal, const gchar *prompt, const gchar *key, gpointer user_data) {
+ gboolean remember; // TODO: Is this useful? Should we be storing it somewhere?
+ ESource *source = e_cal_get_source (ecal);
+ gchar *auth_domain = e_source_get_duped_property (source, "auth-domain");
+
+ const gchar *component_name;
+ if (auth_domain) component_name = auth_domain;
+ else component_name = "Calendar";
+
+ gchar *password = e_passwords_get_password (component_name, key);
+
+ if (password == NULL) {
+ password = e_passwords_ask_password (
+ _("Enter password"),
+ component_name, key, prompt,
+ E_PASSWORDS_REMEMBER_FOREVER |
+ E_PASSWORDS_SECRET |
+ E_PASSWORDS_ONLINE,
+ &remember, NULL);
+ }
+
+ g_free (auth_domain);
+
+ return password;
+}
+
+
// Compare function for g_list_sort of ECalComponent objects
static gint
compare_appointment_items (ECalComponent *a,
@@ -426,8 +450,13 @@ compare_appointment_items (ECalComponent *a,
struct tm tm_a, tm_b;
time_t t_a, t_b;
gint retval = 0;
-
+
+ if (a == NULL || b == NULL) return retval;
+
ECalComponentVType vtype = e_cal_component_get_vtype (a);
+
+ if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return -1;
+
if (vtype == E_CAL_COMPONENT_EVENT)
e_cal_component_get_dtstart (a, &datetime_a);
else
@@ -436,6 +465,8 @@ compare_appointment_items (ECalComponent *a,
t_a = mktime(&tm_a);
vtype = e_cal_component_get_vtype (b);
+ if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return 1;
+
if (vtype == E_CAL_COMPONENT_EVENT)
e_cal_component_get_dtstart (b, &datetime_b);
else
@@ -459,15 +490,17 @@ compare_appointment_items (ECalComponent *a,
*/
static gboolean
update_appointment_menu_items (gpointer user_data) {
- if (!ecal) return FALSE;
// FFR: we should take into account short term timers, for instance
// tea timers, pomodoro timers etc... that people may add, this is hinted to in the spec.
time_t t1, t2;
gchar *query, *is, *ie, *ad;
GList *objects = NULL, *l;
+ GList *allobjects = NULL;
+ GSList *g;
GError *gerror = NULL;
gint i;
gint width, height;
+ ESourceList * sources = NULL;
time(&t1);
time(&t2);
@@ -476,19 +509,6 @@ update_appointment_menu_items (gpointer user_data) {
is = isodate_from_time_t(t1);
ie = isodate_from_time_t(t2);
- // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
- query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
-
-
- // FIXME iterate the query for all sources, kill global ecal
- g_debug("Getting objects with query: %s", query);
- if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
- g_debug("Failed to get objects\n");
- g_free(ecal);
- ecal = NULL;
- return FALSE;
- }
- g_debug("Number of objects returned: %d", g_list_length(objects));
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
/* Remove all of the previous appointments */
@@ -505,11 +525,56 @@ update_appointment_menu_items (gpointer user_data) {
}
// TODO Remove all highlights from the calendar widget
+
+ // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
+ query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
+
+ if (!e_cal_get_sources(&sources, E_CAL_SOURCE_TYPE_EVENT, &gerror)) {
+ g_debug("Failed to get ecal sources\n");
+ return FALSE;
+ }
+
+ // iterate the query for all sources
+ for (g = e_source_list_peek_groups (sources); g; g = g->next) {
+ ESourceGroup *group = E_SOURCE_GROUP (g->data);
+ GSList *s;
+
+ for (s = e_source_group_peek_sources (group); s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ g_signal_connect (G_OBJECT(source), "changed", G_CALLBACK (update_appointment_menu_items), NULL);
+ ECal *ecal = e_cal_new(source, E_CAL_SOURCE_TYPE_EVENT);
+ e_cal_set_auth_func (ecal, (ECalAuthFunc) auth_func, NULL);
+ //icaltimezone * tzone;
+
+ if (!e_cal_open(ecal, FALSE, &gerror)) {
+ g_debug("Failed to get ecal sources %s", gerror->message);
+ g_error_free(gerror);
+ gerror = NULL;
+ continue;
+ }
+
+ g_debug("Getting objects with query: %s", query);
+ if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
+ g_debug("Failed to get objects\n");
+ g_free(ecal);
+ return FALSE;
+ }
+ g_debug("Number of objects returned: %d", g_list_length(objects));
+
+ if (allobjects == NULL) {
+ allobjects = objects;
+ } else if (objects != NULL) {
+ allobjects = g_list_concat(allobjects, objects);
+ g_object_unref(objects);
+ }
+ }
+ }
// Sort the list see above FIXME regarding queries
- objects = g_list_sort(objects, (GCompareFunc) compare_appointment_items);
+ g_debug("Sorting objects list");
+ allobjects = g_list_sort(allobjects, (GCompareFunc) compare_appointment_items);
i = 0;
- for (l = objects; l; l = l->next) {
+ for (l = allobjects; l; l = l->next) {
ECalComponent *ecalcomp = l->data;
ECalComponentText valuetext;
ECalComponentDateTime datetime;
@@ -522,6 +587,7 @@ update_appointment_menu_items (gpointer user_data) {
struct tm tmp_tm;
DbusmenuMenuitem * item;
+ g_debug("Start Object");
ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
// See above FIXME regarding query result
@@ -540,7 +606,6 @@ update_appointment_menu_items (gpointer user_data) {
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- g_debug("Start Object");
// Label text
e_cal_component_get_summary (ecalcomp, &valuetext);
summary = g_strdup (valuetext.value);
@@ -586,7 +651,7 @@ update_appointment_menu_items (gpointer user_data) {
g_debug("Appointment time: %s", right);
g_debug("Appointment timezone: %s", datetime.tzid);
g_debug("Appointment timezone: %s", icaltimezone_get_tzid(appointment_zone)); // These two should be the same
- g_debug("Calendar timezone: %s", ecal_timezone);
+ //g_debug("Calendar timezone: %s", ecal_timezone);
dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
@@ -604,15 +669,18 @@ update_appointment_menu_items (gpointer user_data) {
g_debug("Command to Execute: %s", cmd);
- ESource *source = e_cal_get_source (ecal);
+ // FIXME This is now more difficult to get right with more sources, as we need to keep track
+ // of which ecal or source goes with each ECalComponent :/
+
+ //ESource *source = e_cal_get_source (ecal);
//e_source_get_color (source, &source_color); api has been changed
- const gchar *color_spec = e_source_peek_color_spec(source);
- GdkColor color;
+ const gchar *color_spec = NULL; //e_source_peek_color_spec(source);
g_debug("Colour to use: %s", color_spec);
// Draw the correct icon for the appointment type and then tint it using mask fill.
// For now we'll create a circle
if (color_spec != NULL) {
+ GdkColor color;
gdk_color_parse (color_spec, &color);
cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
@@ -634,7 +702,7 @@ update_appointment_menu_items (gpointer user_data) {
if (i == 4) break; // See above FIXME regarding query result limit
i++;
}
- g_list_free(objects);
+ g_object_unref(allobjects);
g_debug("End of objects");
return TRUE;
}
@@ -694,7 +762,7 @@ build_menus (DbusmenuMenuitem * root)
geo_location = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set (geo_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
- dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_LABEL, "Updating location information...");
+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, "");
dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
g_signal_connect(G_OBJECT(geo_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
@@ -702,14 +770,13 @@ build_menus (DbusmenuMenuitem * root)
current_location = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set (current_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
- dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_LABEL, "Current Timezone");
+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, "");
dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
g_signal_connect(G_OBJECT(current_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
dbusmenu_menuitem_child_append(root, current_location);
check_timezone_sync();
- //g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_timezone_menu_items), NULL);
DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
@@ -815,6 +882,41 @@ geo_address_cb (GeoclueAddress * address, int timestamp, GHashTable * addy_data,
return;
}
+/* Clean up the reference we kept to the address and make sure to
+ drop the signals incase someone else has one. */
+static void
+geo_address_clean (void)
+{
+ if (geo_address == NULL) {
+ return;
+ }
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(geo_address), geo_address_cb, NULL);
+ g_object_unref(G_OBJECT(geo_address));
+
+ geo_address = NULL;
+
+ return;
+}
+
+/* Clean up and remove all signal handlers from the client as we
+ unreference it as well. */
+static void
+geo_client_clean (void)
+{
+ if (geo_master == NULL) {
+ return;
+ }
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(geo_master), geo_client_invalid, NULL);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(geo_master), geo_address_change, NULL);
+ g_object_unref(G_OBJECT(geo_master));
+
+ geo_master = NULL;
+
+ return;
+}
+
/* Callback from creating the address */
static void
geo_create_address (GeoclueMasterClient * master, GeoclueAddress * address, GError * error, gpointer user_data)
@@ -824,6 +926,12 @@ geo_create_address (GeoclueMasterClient * master, GeoclueAddress * address, GErr
return;
}
+ /* We shouldn't have created a new address if we already had one
+ so this is a warning. But, it really is only a mem-leak so we
+ don't need to error out. */
+ g_warn_if_fail(geo_address == NULL);
+ geo_address_clean();
+
g_debug("Created Geoclue Address");
geo_address = address;
g_object_ref(G_OBJECT(geo_address));
@@ -851,10 +959,12 @@ geo_client_invalid (GeoclueMasterClient * client, gpointer user_data)
{
g_warning("Master client invalid, rebuilding.");
- if (geo_master != NULL) {
- g_object_unref(G_OBJECT(geo_master));
- }
- geo_master = NULL;
+ /* Client changes we can assume the address is now invalid so we
+ need to unreference the one we had. */
+ geo_address_clean();
+
+ /* And our master client is invalid */
+ geo_client_clean();
GeoclueMaster * master = geoclue_master_get_default();
geoclue_master_create_client_async(master, geo_create_client, NULL);
@@ -875,10 +985,9 @@ geo_address_change (GeoclueMasterClient * client, gchar * a, gchar * b, gchar *
{
g_warning("Address provider changed. Let's change");
- if (geo_address != NULL) {
- g_object_unref(G_OBJECT(geo_address));
- }
- geo_address = NULL;
+ /* If the address is supposed to have changed we need to drop the old
+ address before starting to get the new one. */
+ geo_address_clean();
geoclue_master_client_create_address_async(geo_master, geo_create_address, NULL);
@@ -899,8 +1008,17 @@ geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar *
g_debug("Created Geoclue client at: %s", path);
geo_master = client;
+
+ if (geo_master != NULL) {
+ g_warning(_("Unable to get a GeoClue client! Geolocation based timezone support will not be available."));
+ return;
+ }
+
g_object_ref(G_OBJECT(geo_master));
+ /* New client, make sure we don't have an address hanging on */
+ geo_address_clean();
+
geoclue_master_client_set_requirements_async(geo_master,
GEOCLUE_ACCURACY_LEVEL_REGION,
0,
@@ -980,5 +1098,8 @@ main (int argc, char ** argv)
g_object_unref(G_OBJECT(server));
g_object_unref(G_OBJECT(root));
+ geo_address_clean();
+ geo_client_clean();
+
return 0;
}