2011-02-25 22:42:25 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2014-01-07 21:32:37 +00:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2011-02-25 22:42:25 +00:00
|
|
|
*
|
|
|
|
* Author: David Zeuthen <davidz@redhat.com>
|
|
|
|
*
|
|
|
|
* Based on code from gnome-panel's clock-applet, file calendar-client.c, with Authors:
|
|
|
|
*
|
|
|
|
* Mark McLoughlin <mark@skynet.ie>
|
|
|
|
* William Jon McCann <mccann@jhu.edu>
|
|
|
|
* Martin Grimme <martin@pycage.de>
|
|
|
|
* Christian Kellner <gicmo@xatom.net>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <gio/gio.h>
|
|
|
|
|
|
|
|
#define HANDLE_LIBICAL_MEMORY
|
2012-04-26 13:08:27 +00:00
|
|
|
#include <libecal/libecal.h>
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
#include "calendar-sources.h"
|
|
|
|
|
|
|
|
/* Set the environment variable CALENDAR_SERVER_DEBUG to show debug */
|
|
|
|
static void print_debug (const gchar *str, ...);
|
|
|
|
|
|
|
|
#define BUS_NAME "org.gnome.Shell.CalendarServer"
|
|
|
|
|
|
|
|
static const gchar introspection_xml[] =
|
|
|
|
"<node>"
|
|
|
|
" <interface name='org.gnome.Shell.CalendarServer'>"
|
|
|
|
" <method name='GetEvents'>"
|
|
|
|
" <arg type='x' name='since' direction='in'/>"
|
|
|
|
" <arg type='x' name='until' direction='in'/>"
|
|
|
|
" <arg type='b' name='force_reload' direction='in'/>"
|
|
|
|
" <arg type='a(sssbxxa{sv})' name='events' direction='out'/>"
|
|
|
|
" </method>"
|
|
|
|
" <signal name='Changed'/>"
|
|
|
|
" <property name='Since' type='x' access='read'/>"
|
|
|
|
" <property name='Until' type='x' access='read'/>"
|
2012-10-29 15:37:07 +00:00
|
|
|
" <property name='HasCalendars' type='b' access='read'/>"
|
2011-02-25 22:42:25 +00:00
|
|
|
" </interface>"
|
|
|
|
"</node>";
|
|
|
|
static GDBusNodeInfo *introspection_data = NULL;
|
|
|
|
|
|
|
|
struct _App;
|
|
|
|
typedef struct _App App;
|
|
|
|
|
|
|
|
static gboolean opt_replace = FALSE;
|
|
|
|
static GOptionEntry opt_entries[] = {
|
|
|
|
{"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
|
|
|
|
{NULL }
|
|
|
|
};
|
|
|
|
static App *_global_app = NULL;
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
time_t start_time;
|
|
|
|
time_t end_time;
|
|
|
|
} CalendarOccurrence;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2015-03-06 22:20:26 +00:00
|
|
|
char *id;
|
2011-02-25 22:42:25 +00:00
|
|
|
char *uid;
|
|
|
|
char *rid;
|
2012-04-26 13:08:27 +00:00
|
|
|
char *backend_name;
|
2011-02-25 22:42:25 +00:00
|
|
|
char *summary;
|
|
|
|
char *description;
|
|
|
|
char *color_string;
|
|
|
|
time_t start_time;
|
|
|
|
time_t end_time;
|
|
|
|
guint is_all_day : 1;
|
|
|
|
|
|
|
|
/* Only used internally */
|
|
|
|
GSList *occurrences;
|
|
|
|
} CalendarAppointment;
|
|
|
|
|
|
|
|
static time_t
|
|
|
|
get_time_from_property (icalcomponent *ical,
|
|
|
|
icalproperty_kind prop_kind,
|
|
|
|
struct icaltimetype (* get_prop_func) (const icalproperty *prop),
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
icalproperty *prop;
|
|
|
|
struct icaltimetype ical_time;
|
|
|
|
icalparameter *param;
|
|
|
|
icaltimezone *timezone = NULL;
|
|
|
|
|
|
|
|
prop = icalcomponent_get_first_property (ical, prop_kind);
|
|
|
|
if (!prop)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ical_time = get_prop_func (prop);
|
|
|
|
|
|
|
|
param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
|
|
|
|
if (param)
|
|
|
|
timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
|
|
|
|
else if (icaltime_is_utc (ical_time))
|
|
|
|
timezone = icaltimezone_get_utc_timezone ();
|
|
|
|
else
|
|
|
|
timezone = default_zone;
|
|
|
|
|
|
|
|
return icaltime_as_timet_with_zone (ical_time, timezone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_ical_uid (icalcomponent *ical)
|
|
|
|
{
|
|
|
|
return g_strdup (icalcomponent_get_uid (ical));
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_ical_rid (icalcomponent *ical)
|
|
|
|
{
|
|
|
|
icalproperty *prop;
|
|
|
|
struct icaltimetype ical_time;
|
|
|
|
|
|
|
|
prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
|
|
|
|
if (!prop)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ical_time = icalproperty_get_recurrenceid (prop);
|
|
|
|
|
|
|
|
return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ?
|
|
|
|
g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_ical_summary (icalcomponent *ical)
|
|
|
|
{
|
|
|
|
icalproperty *prop;
|
|
|
|
|
|
|
|
prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
|
|
|
|
if (!prop)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return g_strdup (icalproperty_get_summary (prop));
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_ical_description (icalcomponent *ical)
|
|
|
|
{
|
|
|
|
icalproperty *prop;
|
|
|
|
|
|
|
|
prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
|
|
|
|
if (!prop)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return g_strdup (icalproperty_get_description (prop));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline time_t
|
|
|
|
get_ical_start_time (icalcomponent *ical,
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
return get_time_from_property (ical,
|
|
|
|
ICAL_DTSTART_PROPERTY,
|
|
|
|
icalproperty_get_dtstart,
|
|
|
|
default_zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline time_t
|
|
|
|
get_ical_end_time (icalcomponent *ical,
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
return get_time_from_property (ical,
|
|
|
|
ICAL_DTEND_PROPERTY,
|
|
|
|
icalproperty_get_dtend,
|
|
|
|
default_zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
get_ical_is_all_day (icalcomponent *ical,
|
|
|
|
time_t start_time,
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
icalproperty *prop;
|
|
|
|
struct tm *start_tm;
|
|
|
|
time_t end_time;
|
|
|
|
struct icaldurationtype duration;
|
|
|
|
struct icaltimetype start_icaltime;
|
|
|
|
|
|
|
|
start_icaltime = icalcomponent_get_dtstart (ical);
|
|
|
|
if (start_icaltime.is_date)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
start_tm = gmtime (&start_time);
|
|
|
|
if (start_tm->tm_sec != 0 ||
|
|
|
|
start_tm->tm_min != 0 ||
|
|
|
|
start_tm->tm_hour != 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ((end_time = get_ical_end_time (ical, default_zone)))
|
|
|
|
return (end_time - start_time) % 86400 == 0;
|
|
|
|
|
|
|
|
prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
|
|
|
|
if (!prop)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
duration = icalproperty_get_duration (prop);
|
|
|
|
|
|
|
|
return icaldurationtype_as_int (duration) % 86400 == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline time_t
|
|
|
|
get_ical_due_time (icalcomponent *ical,
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
return get_time_from_property (ical,
|
|
|
|
ICAL_DUE_PROPERTY,
|
|
|
|
icalproperty_get_due,
|
|
|
|
default_zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline time_t
|
|
|
|
get_ical_completed_time (icalcomponent *ical,
|
|
|
|
icaltimezone *default_zone)
|
|
|
|
{
|
|
|
|
return get_time_from_property (ical,
|
|
|
|
ICAL_COMPLETED_PROPERTY,
|
|
|
|
icalproperty_get_completed,
|
|
|
|
default_zone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2012-03-02 00:22:46 +00:00
|
|
|
get_source_color (ECalClient *esource)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
ESource *source;
|
2012-04-26 13:08:27 +00:00
|
|
|
ECalClientSourceType source_type;
|
|
|
|
ESourceSelectable *extension;
|
|
|
|
const gchar *extension_name;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
2012-03-02 00:22:46 +00:00
|
|
|
g_return_val_if_fail (E_IS_CAL_CLIENT (esource), NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
2012-03-02 00:22:46 +00:00
|
|
|
source = e_client_get_source (E_CLIENT (esource));
|
2012-04-26 13:08:27 +00:00
|
|
|
source_type = e_cal_client_get_source_type (esource);
|
|
|
|
|
|
|
|
switch (source_type)
|
|
|
|
{
|
|
|
|
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
|
|
|
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
|
|
|
break;
|
|
|
|
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
|
|
|
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
extension = e_source_get_extension (source, extension_name);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
2012-04-26 13:08:27 +00:00
|
|
|
return e_source_selectable_dup_color (extension);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
2012-04-26 13:08:27 +00:00
|
|
|
get_source_backend_name (ECalClient *esource)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2012-04-26 13:08:27 +00:00
|
|
|
ESource *source;
|
|
|
|
ECalClientSourceType source_type;
|
|
|
|
ESourceBackend *extension;
|
|
|
|
const gchar *extension_name;
|
|
|
|
|
|
|
|
g_return_val_if_fail (E_IS_CAL_CLIENT (esource), NULL);
|
|
|
|
|
|
|
|
source = e_client_get_source (E_CLIENT (esource));
|
|
|
|
source_type = e_cal_client_get_source_type (esource);
|
|
|
|
|
|
|
|
switch (source_type)
|
|
|
|
{
|
|
|
|
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
|
|
|
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
|
|
|
break;
|
|
|
|
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
|
|
|
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_return_val_if_reached (NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
2012-04-26 13:08:27 +00:00
|
|
|
|
|
|
|
extension = e_source_get_extension (source, extension_name);
|
|
|
|
|
|
|
|
return e_source_backend_dup_backend_name (extension);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
null_safe_strcmp (const char *a,
|
|
|
|
const char *b)
|
|
|
|
{
|
|
|
|
return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
calendar_appointment_equal (CalendarAppointment *a,
|
|
|
|
CalendarAppointment *b)
|
|
|
|
{
|
|
|
|
GSList *la, *lb;
|
|
|
|
|
|
|
|
if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
|
|
|
|
{
|
|
|
|
CalendarOccurrence *oa = la->data;
|
|
|
|
CalendarOccurrence *ob = lb->data;
|
|
|
|
|
|
|
|
if (oa->start_time != ob->start_time ||
|
|
|
|
oa->end_time != ob->end_time)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
null_safe_strcmp (a->uid, b->uid) == 0 &&
|
2012-04-26 13:08:27 +00:00
|
|
|
null_safe_strcmp (a->backend_name, b->backend_name) == 0 &&
|
2011-02-25 22:42:25 +00:00
|
|
|
null_safe_strcmp (a->summary, b->summary) == 0 &&
|
|
|
|
null_safe_strcmp (a->description, b->description) == 0 &&
|
|
|
|
null_safe_strcmp (a->color_string, b->color_string) == 0 &&
|
|
|
|
a->start_time == b->start_time &&
|
|
|
|
a->end_time == b->end_time &&
|
|
|
|
a->is_all_day == b->is_all_day;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
calendar_appointment_free (CalendarAppointment *appointment)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = appointment->occurrences; l; l = l->next)
|
|
|
|
g_free (l->data);
|
|
|
|
g_slist_free (appointment->occurrences);
|
|
|
|
appointment->occurrences = NULL;
|
|
|
|
|
2015-03-06 22:20:26 +00:00
|
|
|
g_free (appointment->id);
|
|
|
|
appointment->id = NULL;
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
g_free (appointment->uid);
|
|
|
|
appointment->uid = NULL;
|
|
|
|
|
|
|
|
g_free (appointment->rid);
|
|
|
|
appointment->rid = NULL;
|
|
|
|
|
2012-04-26 13:08:27 +00:00
|
|
|
g_free (appointment->backend_name);
|
|
|
|
appointment->backend_name = NULL;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
g_free (appointment->summary);
|
|
|
|
appointment->summary = NULL;
|
|
|
|
|
|
|
|
g_free (appointment->description);
|
|
|
|
appointment->description = NULL;
|
|
|
|
|
|
|
|
g_free (appointment->color_string);
|
|
|
|
appointment->color_string = NULL;
|
|
|
|
|
|
|
|
appointment->start_time = 0;
|
|
|
|
appointment->is_all_day = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
calendar_appointment_init (CalendarAppointment *appointment,
|
|
|
|
icalcomponent *ical,
|
2016-07-07 21:24:59 +00:00
|
|
|
ECalClient *cal)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2016-07-07 21:24:59 +00:00
|
|
|
icaltimezone *default_zone;
|
|
|
|
|
|
|
|
default_zone = e_cal_client_get_default_timezone (cal);
|
2015-03-06 22:20:26 +00:00
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
appointment->uid = get_ical_uid (ical);
|
|
|
|
appointment->rid = get_ical_rid (ical);
|
2012-04-26 13:08:27 +00:00
|
|
|
appointment->backend_name = get_source_backend_name (cal);
|
2011-02-25 22:42:25 +00:00
|
|
|
appointment->summary = get_ical_summary (ical);
|
|
|
|
appointment->description = get_ical_description (ical);
|
|
|
|
appointment->color_string = get_source_color (cal);
|
|
|
|
appointment->start_time = get_ical_start_time (ical, default_zone);
|
|
|
|
appointment->end_time = get_ical_end_time (ical, default_zone);
|
|
|
|
appointment->is_all_day = get_ical_is_all_day (ical,
|
|
|
|
appointment->start_time,
|
|
|
|
default_zone);
|
2015-03-06 22:20:26 +00:00
|
|
|
|
|
|
|
/* While the UID is usually enough to identify an event, only the triple
|
|
|
|
* of (source,UID,RID) is fully unambiguous; neither may contain '\n',
|
|
|
|
* so we can safely use it to create a unique ID from the triple
|
|
|
|
*/
|
|
|
|
source_uid = e_source_get_uid (e_client_get_source (E_CLIENT (cal)));
|
|
|
|
appointment->id = g_strdup_printf ("%s\n%s\n%s",
|
|
|
|
source_uid,
|
|
|
|
appointment->uid,
|
|
|
|
appointment->rid ? appointment->rid : "");
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static icaltimezone *
|
|
|
|
resolve_timezone_id (const char *tzid,
|
2012-03-02 00:22:46 +00:00
|
|
|
ECalClient *source)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
icaltimezone *retval;
|
|
|
|
|
|
|
|
retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
|
|
|
|
if (!retval)
|
|
|
|
{
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_get_timezone_sync (source, tzid, &retval, NULL, NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
calendar_appointment_collect_occurrence (ECalComponent *component,
|
|
|
|
time_t occurrence_start,
|
|
|
|
time_t occurrence_end,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
CalendarOccurrence *occurrence;
|
|
|
|
GSList **collect_loc = data;
|
|
|
|
|
|
|
|
occurrence = g_new0 (CalendarOccurrence, 1);
|
|
|
|
occurrence->start_time = occurrence_start;
|
|
|
|
occurrence->end_time = occurrence_end;
|
|
|
|
|
|
|
|
*collect_loc = g_slist_prepend (*collect_loc, occurrence);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
calendar_appointment_generate_occurrences (CalendarAppointment *appointment,
|
|
|
|
icalcomponent *ical,
|
2012-03-02 00:22:46 +00:00
|
|
|
ECalClient *cal,
|
2011-02-25 22:42:25 +00:00
|
|
|
time_t start,
|
2016-07-07 21:24:59 +00:00
|
|
|
time_t end)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
ECalComponent *ecal;
|
2016-07-07 21:24:59 +00:00
|
|
|
icaltimezone *default_zone;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
g_assert (appointment->occurrences == NULL);
|
|
|
|
|
2016-07-07 21:24:59 +00:00
|
|
|
default_zone = e_cal_client_get_default_timezone (cal);
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
ecal = e_cal_component_new ();
|
|
|
|
e_cal_component_set_icalcomponent (ecal,
|
|
|
|
icalcomponent_new_clone (ical));
|
|
|
|
|
|
|
|
e_cal_recur_generate_instances (ecal,
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
calendar_appointment_collect_occurrence,
|
|
|
|
&appointment->occurrences,
|
|
|
|
(ECalRecurResolveTimezoneFn) resolve_timezone_id,
|
|
|
|
cal,
|
|
|
|
default_zone);
|
|
|
|
|
|
|
|
g_object_unref (ecal);
|
|
|
|
|
|
|
|
appointment->occurrences = g_slist_reverse (appointment->occurrences);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CalendarAppointment *
|
|
|
|
calendar_appointment_new (icalcomponent *ical,
|
2016-07-07 21:24:59 +00:00
|
|
|
ECalClient *cal)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
CalendarAppointment *appointment;
|
|
|
|
|
|
|
|
appointment = g_new0 (CalendarAppointment, 1);
|
|
|
|
|
2016-07-07 21:24:59 +00:00
|
|
|
calendar_appointment_init (appointment, ical, cal);
|
2011-02-25 22:42:25 +00:00
|
|
|
return appointment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct _App
|
|
|
|
{
|
|
|
|
GDBusConnection *connection;
|
|
|
|
|
|
|
|
time_t since;
|
|
|
|
time_t until;
|
|
|
|
|
|
|
|
icaltimezone *zone;
|
|
|
|
|
|
|
|
CalendarSources *sources;
|
|
|
|
gulong sources_signal_id;
|
|
|
|
|
|
|
|
/* hash from uid to CalendarAppointment objects */
|
|
|
|
GHashTable *appointments;
|
|
|
|
|
|
|
|
gchar *timezone_location;
|
|
|
|
|
|
|
|
guint changed_timeout_id;
|
|
|
|
|
|
|
|
gboolean cache_invalid;
|
|
|
|
|
|
|
|
GList *live_views;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
app_update_timezone (App *app)
|
|
|
|
{
|
|
|
|
gchar *location;
|
|
|
|
|
|
|
|
location = e_cal_system_timezone_get_location ();
|
|
|
|
if (g_strcmp0 (location, app->timezone_location) != 0)
|
|
|
|
{
|
|
|
|
if (location == NULL)
|
|
|
|
app->zone = icaltimezone_get_utc_timezone ();
|
|
|
|
else
|
|
|
|
app->zone = icaltimezone_get_builtin_timezone (location);
|
|
|
|
g_free (app->timezone_location);
|
|
|
|
app->timezone_location = location;
|
|
|
|
print_debug ("Using timezone %s", app->timezone_location);
|
|
|
|
}
|
2016-07-08 15:50:35 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g_free (location);
|
|
|
|
}
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
on_app_schedule_changed_cb (gpointer user_data)
|
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
print_debug ("Emitting changed");
|
|
|
|
g_dbus_connection_emit_signal (app->connection,
|
|
|
|
NULL, /* destination_bus_name */
|
|
|
|
"/org/gnome/Shell/CalendarServer",
|
|
|
|
"org.gnome.Shell.CalendarServer",
|
|
|
|
"Changed",
|
|
|
|
NULL, /* no params */
|
|
|
|
NULL);
|
|
|
|
app->changed_timeout_id = 0;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
app_schedule_changed (App *app)
|
|
|
|
{
|
|
|
|
print_debug ("Scheduling changed");
|
|
|
|
if (app->changed_timeout_id == 0)
|
|
|
|
{
|
|
|
|
app->changed_timeout_id = g_timeout_add (2000,
|
|
|
|
on_app_schedule_changed_cb,
|
|
|
|
app);
|
2014-04-10 17:27:23 +00:00
|
|
|
g_source_set_name_by_id (app->changed_timeout_id, "[gnome-shell] on_app_schedule_changed_cb");
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
invalidate_cache (App *app)
|
|
|
|
{
|
|
|
|
app->cache_invalid = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-03-02 00:22:46 +00:00
|
|
|
on_objects_added (ECalClientView *view,
|
|
|
|
GSList *objects,
|
|
|
|
gpointer user_data)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
App *app = user_data;
|
2012-03-02 00:22:46 +00:00
|
|
|
GSList *l;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
print_debug ("%s for calendar", G_STRFUNC);
|
|
|
|
|
|
|
|
for (l = objects; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
icalcomponent *ical = l->data;
|
|
|
|
const char *uid;
|
|
|
|
|
|
|
|
uid = icalcomponent_get_uid (ical);
|
|
|
|
|
|
|
|
if (g_hash_table_lookup (app->appointments, uid) == NULL)
|
|
|
|
{
|
|
|
|
/* new appointment we don't know about => changed signal */
|
|
|
|
invalidate_cache (app);
|
|
|
|
app_schedule_changed (app);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-03-02 00:22:46 +00:00
|
|
|
on_objects_modified (ECalClientView *view,
|
|
|
|
GSList *objects,
|
|
|
|
gpointer user_data)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
print_debug ("%s for calendar", G_STRFUNC);
|
|
|
|
invalidate_cache (app);
|
|
|
|
app_schedule_changed (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-03-02 00:22:46 +00:00
|
|
|
on_objects_removed (ECalClientView *view,
|
|
|
|
GSList *uids,
|
|
|
|
gpointer user_data)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
print_debug ("%s for calendar", G_STRFUNC);
|
|
|
|
invalidate_cache (app);
|
|
|
|
app_schedule_changed (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
app_load_events (App *app)
|
|
|
|
{
|
2012-04-26 13:08:27 +00:00
|
|
|
GList *clients;
|
|
|
|
GList *l;
|
2011-02-25 22:42:25 +00:00
|
|
|
GList *ll;
|
|
|
|
gchar *since_iso8601;
|
|
|
|
gchar *until_iso8601;
|
2016-07-07 14:53:47 +00:00
|
|
|
gchar *query;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
/* out with the old */
|
|
|
|
g_hash_table_remove_all (app->appointments);
|
|
|
|
/* nuke existing views */
|
|
|
|
for (ll = app->live_views; ll != NULL; ll = ll->next)
|
|
|
|
{
|
2012-03-02 00:22:46 +00:00
|
|
|
ECalClientView *view = E_CAL_CLIENT_VIEW (ll->data);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
|
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
|
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_view_stop (view, NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_object_unref (view);
|
|
|
|
}
|
|
|
|
g_list_free (app->live_views);
|
|
|
|
app->live_views = NULL;
|
|
|
|
|
|
|
|
/* timezone could have changed */
|
|
|
|
app_update_timezone (app);
|
|
|
|
|
|
|
|
since_iso8601 = isodate_from_time_t (app->since);
|
|
|
|
until_iso8601 = isodate_from_time_t (app->until);
|
|
|
|
|
|
|
|
print_debug ("Loading events since %s until %s",
|
|
|
|
since_iso8601,
|
|
|
|
until_iso8601);
|
|
|
|
|
2016-07-07 14:53:47 +00:00
|
|
|
query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
|
|
|
|
"(make-time \"%s\")",
|
|
|
|
since_iso8601,
|
|
|
|
until_iso8601);
|
|
|
|
|
2012-04-26 13:08:27 +00:00
|
|
|
clients = calendar_sources_get_appointment_clients (app->sources);
|
|
|
|
for (l = clients; l != NULL; l = l->next)
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2012-03-02 00:22:46 +00:00
|
|
|
ECalClient *cal = E_CAL_CLIENT (l->data);
|
2011-02-25 22:42:25 +00:00
|
|
|
GError *error;
|
2012-03-02 00:22:46 +00:00
|
|
|
GSList *objects, *j;
|
|
|
|
ECalClientView *view;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_set_default_timezone (cal, app->zone);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
error = NULL;
|
2012-03-02 00:22:46 +00:00
|
|
|
if (!e_client_open_sync (E_CLIENT (cal), TRUE, NULL, &error))
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2012-04-26 13:08:27 +00:00
|
|
|
ESource *source = e_client_get_source (E_CLIENT (cal));
|
2012-03-05 20:33:15 +00:00
|
|
|
g_warning ("Error opening calendar %s: %s\n",
|
2012-04-26 13:08:27 +00:00
|
|
|
e_source_get_uid (source), error->message);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_error_free (error);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = NULL;
|
|
|
|
objects = NULL;
|
2012-03-02 00:22:46 +00:00
|
|
|
if (!e_cal_client_get_object_list_sync (cal,
|
|
|
|
query,
|
|
|
|
&objects,
|
|
|
|
NULL, /* cancellable */
|
|
|
|
&error))
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2012-04-26 13:08:27 +00:00
|
|
|
ESource *source = e_client_get_source (E_CLIENT (cal));
|
2012-03-05 20:33:15 +00:00
|
|
|
g_warning ("Error querying calendar %s: %s\n",
|
2012-04-26 13:08:27 +00:00
|
|
|
e_source_get_uid (source), error->message);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_error_free (error);
|
|
|
|
g_free (query);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = objects; j != NULL; j = j->next)
|
|
|
|
{
|
|
|
|
icalcomponent *ical = j->data;
|
|
|
|
CalendarAppointment *appointment;
|
|
|
|
|
2016-07-07 21:24:59 +00:00
|
|
|
appointment = calendar_appointment_new (ical, cal);
|
2011-02-25 22:42:25 +00:00
|
|
|
calendar_appointment_generate_occurrences (appointment,
|
|
|
|
ical,
|
|
|
|
cal,
|
|
|
|
app->since,
|
2016-07-07 21:24:59 +00:00
|
|
|
app->until);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_hash_table_insert (app->appointments, g_strdup (appointment->uid), appointment);
|
|
|
|
}
|
|
|
|
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_free_icalcomp_slist (objects);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
error = NULL;
|
2012-03-02 00:22:46 +00:00
|
|
|
if (!e_cal_client_get_view_sync (cal,
|
|
|
|
query,
|
|
|
|
&view,
|
|
|
|
NULL, /* cancellable */
|
|
|
|
&error))
|
2011-02-25 22:42:25 +00:00
|
|
|
{
|
2012-03-05 20:33:15 +00:00
|
|
|
g_warning ("Error setting up live-query on calendar: %s\n", error->message);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_signal_connect (view,
|
|
|
|
"objects-added",
|
|
|
|
G_CALLBACK (on_objects_added),
|
|
|
|
app);
|
|
|
|
g_signal_connect (view,
|
|
|
|
"objects-modified",
|
|
|
|
G_CALLBACK (on_objects_modified),
|
|
|
|
app);
|
|
|
|
g_signal_connect (view,
|
|
|
|
"objects-removed",
|
|
|
|
G_CALLBACK (on_objects_removed),
|
|
|
|
app);
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_view_start (view, NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
app->live_views = g_list_prepend (app->live_views, view);
|
|
|
|
}
|
|
|
|
}
|
2012-04-26 13:08:27 +00:00
|
|
|
g_list_free (clients);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_free (since_iso8601);
|
|
|
|
g_free (until_iso8601);
|
2016-07-07 14:53:47 +00:00
|
|
|
g_free (query);
|
2011-02-25 22:42:25 +00:00
|
|
|
app->cache_invalid = FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-29 15:37:07 +00:00
|
|
|
static gboolean
|
|
|
|
app_has_calendars (App *app)
|
|
|
|
{
|
|
|
|
return calendar_sources_has_sources (app->sources);
|
|
|
|
}
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
static void
|
|
|
|
on_appointment_sources_changed (CalendarSources *sources,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
|
|
|
|
print_debug ("Sources changed\n");
|
|
|
|
app_load_events (app);
|
2012-10-29 15:37:07 +00:00
|
|
|
|
|
|
|
/* Notify the HasCalendars property */
|
|
|
|
{
|
|
|
|
GVariantBuilder dict_builder;
|
|
|
|
|
|
|
|
g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
g_variant_builder_add (&dict_builder, "{sv}", "HasCalendars",
|
|
|
|
g_variant_new_boolean (app_has_calendars (app)));
|
|
|
|
|
|
|
|
g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
|
|
|
|
NULL,
|
|
|
|
"/org/gnome/Shell/CalendarServer",
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
"PropertiesChanged",
|
|
|
|
g_variant_new ("(sa{sv}as)",
|
|
|
|
"org.gnome.Shell.CalendarServer",
|
|
|
|
&dict_builder,
|
|
|
|
NULL),
|
|
|
|
NULL);
|
|
|
|
}
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static App *
|
|
|
|
app_new (GDBusConnection *connection)
|
|
|
|
{
|
|
|
|
App *app;
|
|
|
|
|
|
|
|
app = g_new0 (App, 1);
|
|
|
|
app->connection = g_object_ref (connection);
|
|
|
|
app->sources = calendar_sources_get ();
|
|
|
|
app->sources_signal_id = g_signal_connect (app->sources,
|
|
|
|
"appointment-sources-changed",
|
|
|
|
G_CALLBACK (on_appointment_sources_changed),
|
|
|
|
app);
|
|
|
|
|
|
|
|
app->appointments = g_hash_table_new_full (g_str_hash,
|
|
|
|
g_str_equal,
|
|
|
|
g_free,
|
|
|
|
(GDestroyNotify) calendar_appointment_free);
|
|
|
|
|
|
|
|
app_update_timezone (app);
|
|
|
|
|
|
|
|
return app;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
app_free (App *app)
|
|
|
|
{
|
|
|
|
GList *ll;
|
|
|
|
for (ll = app->live_views; ll != NULL; ll = ll->next)
|
|
|
|
{
|
2012-03-02 00:22:46 +00:00
|
|
|
ECalClientView *view = E_CAL_CLIENT_VIEW (ll->data);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
|
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
|
|
|
|
g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
|
2012-03-02 00:22:46 +00:00
|
|
|
e_cal_client_view_stop (view, NULL);
|
2011-02-25 22:42:25 +00:00
|
|
|
g_object_unref (view);
|
|
|
|
}
|
|
|
|
g_list_free (app->live_views);
|
|
|
|
|
|
|
|
g_free (app->timezone_location);
|
|
|
|
|
|
|
|
g_hash_table_unref (app->appointments);
|
|
|
|
|
|
|
|
g_object_unref (app->connection);
|
|
|
|
g_signal_handler_disconnect (app->sources,
|
|
|
|
app->sources_signal_id);
|
|
|
|
g_object_unref (app->sources);
|
|
|
|
|
|
|
|
if (app->changed_timeout_id != 0)
|
|
|
|
g_source_remove (app->changed_timeout_id);
|
|
|
|
|
|
|
|
g_free (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_method_call (GDBusConnection *connection,
|
|
|
|
const gchar *sender,
|
|
|
|
const gchar *object_path,
|
|
|
|
const gchar *interface_name,
|
|
|
|
const gchar *method_name,
|
|
|
|
GVariant *parameters,
|
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
|
|
|
|
if (g_strcmp0 (method_name, "GetEvents") == 0)
|
|
|
|
{
|
|
|
|
GVariantBuilder builder;
|
|
|
|
GHashTableIter hash_iter;
|
|
|
|
CalendarAppointment *a;
|
|
|
|
gint64 since;
|
|
|
|
gint64 until;
|
|
|
|
gboolean force_reload;
|
|
|
|
gboolean window_changed;
|
|
|
|
|
|
|
|
g_variant_get (parameters,
|
|
|
|
"(xxb)",
|
|
|
|
&since,
|
|
|
|
&until,
|
|
|
|
&force_reload);
|
|
|
|
|
|
|
|
if (until < since)
|
|
|
|
{
|
|
|
|
g_dbus_method_invocation_return_dbus_error (invocation,
|
|
|
|
"org.gnome.Shell.CalendarServer.Error.Failed",
|
|
|
|
"until cannot be before since");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
print_debug ("Handling GetEvents (since=%" G_GINT64_FORMAT ", until=%" G_GINT64_FORMAT ", force_reload=%s)",
|
|
|
|
since,
|
|
|
|
until,
|
|
|
|
force_reload ? "true" : "false");
|
|
|
|
|
|
|
|
window_changed = FALSE;
|
|
|
|
if (!(app->until == until && app->since == since))
|
|
|
|
{
|
|
|
|
GVariantBuilder *builder;
|
|
|
|
GVariantBuilder *invalidated_builder;
|
|
|
|
|
|
|
|
app->until = until;
|
|
|
|
app->since = since;
|
|
|
|
window_changed = TRUE;
|
|
|
|
|
|
|
|
builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
|
|
|
g_variant_builder_add (builder, "{sv}",
|
|
|
|
"Until", g_variant_new_int64 (app->until));
|
|
|
|
g_variant_builder_add (builder, "{sv}",
|
|
|
|
"Since", g_variant_new_int64 (app->since));
|
|
|
|
g_dbus_connection_emit_signal (app->connection,
|
|
|
|
NULL, /* destination_bus_name */
|
|
|
|
"/org/gnome/Shell/CalendarServer",
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
"PropertiesChanged",
|
|
|
|
g_variant_new ("(sa{sv}as)",
|
|
|
|
"org.gnome.Shell.CalendarServer",
|
|
|
|
builder,
|
|
|
|
invalidated_builder),
|
|
|
|
NULL); /* GError** */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reload events if necessary */
|
|
|
|
if (window_changed || force_reload || app->cache_invalid)
|
|
|
|
{
|
|
|
|
app_load_events (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The a{sv} is used as an escape hatch in case we want to provide more
|
|
|
|
* information in the future without breaking ABI
|
|
|
|
*/
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssbxxa{sv})"));
|
|
|
|
g_hash_table_iter_init (&hash_iter, app->appointments);
|
|
|
|
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &a))
|
|
|
|
{
|
|
|
|
GVariantBuilder extras_builder;
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = a->occurrences; l; l = l->next)
|
|
|
|
{
|
|
|
|
CalendarOccurrence *o = l->data;
|
|
|
|
time_t start_time = o->start_time;
|
|
|
|
time_t end_time = o->end_time;
|
|
|
|
|
|
|
|
if ((start_time >= app->since &&
|
|
|
|
start_time < app->until) ||
|
|
|
|
(start_time <= app->since &&
|
|
|
|
(end_time - 1) > app->since))
|
|
|
|
{
|
|
|
|
g_variant_builder_init (&extras_builder, G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
g_variant_builder_add (&builder,
|
|
|
|
"(sssbxxa{sv})",
|
2015-03-06 22:20:26 +00:00
|
|
|
a->id,
|
2011-02-25 22:42:25 +00:00
|
|
|
a->summary != NULL ? a->summary : "",
|
|
|
|
a->description != NULL ? a->description : "",
|
|
|
|
(gboolean) a->is_all_day,
|
|
|
|
(gint64) start_time,
|
|
|
|
(gint64) end_time,
|
|
|
|
extras_builder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_dbus_method_invocation_return_value (invocation,
|
|
|
|
g_variant_new ("(a(sssbxxa{sv}))", &builder));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GVariant *
|
|
|
|
handle_get_property (GDBusConnection *connection,
|
|
|
|
const gchar *sender,
|
|
|
|
const gchar *object_path,
|
|
|
|
const gchar *interface_name,
|
|
|
|
const gchar *property_name,
|
|
|
|
GError **error,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
App *app = user_data;
|
|
|
|
GVariant *ret;
|
|
|
|
|
|
|
|
ret = NULL;
|
|
|
|
if (g_strcmp0 (property_name, "Since") == 0)
|
|
|
|
{
|
|
|
|
ret = g_variant_new_int64 (app->since);
|
|
|
|
}
|
|
|
|
else if (g_strcmp0 (property_name, "Until") == 0)
|
|
|
|
{
|
|
|
|
ret = g_variant_new_int64 (app->until);
|
|
|
|
}
|
2012-10-29 15:37:07 +00:00
|
|
|
else if (g_strcmp0 (property_name, "HasCalendars") == 0)
|
|
|
|
{
|
|
|
|
ret = g_variant_new_boolean (app_has_calendars (app));
|
|
|
|
}
|
2011-02-25 22:42:25 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const GDBusInterfaceVTable interface_vtable =
|
|
|
|
{
|
|
|
|
handle_method_call,
|
|
|
|
handle_get_property,
|
|
|
|
NULL /* handle_set_property */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_bus_acquired (GDBusConnection *connection,
|
|
|
|
const gchar *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GError *error;
|
|
|
|
guint registration_id;
|
|
|
|
|
|
|
|
_global_app = app_new (connection);
|
|
|
|
|
|
|
|
error = NULL;
|
|
|
|
registration_id = g_dbus_connection_register_object (connection,
|
|
|
|
"/org/gnome/Shell/CalendarServer",
|
|
|
|
introspection_data->interfaces[0],
|
|
|
|
&interface_vtable,
|
|
|
|
_global_app,
|
|
|
|
NULL, /* user_data_free_func */
|
|
|
|
&error);
|
|
|
|
if (registration_id == 0)
|
|
|
|
{
|
|
|
|
g_printerr ("Error exporting object: %s (%s %d)",
|
|
|
|
error->message,
|
|
|
|
g_quark_to_string (error->domain),
|
|
|
|
error->code);
|
|
|
|
g_error_free (error);
|
|
|
|
_exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
print_debug ("Connected to the session bus");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_name_lost (GDBusConnection *connection,
|
|
|
|
const gchar *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2012-10-30 17:42:43 +00:00
|
|
|
GMainLoop *main_loop = user_data;
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
g_print ("gnome-shell-calendar-server[%d]: Lost (or failed to acquire) the name " BUS_NAME " - exiting\n",
|
|
|
|
(gint) getpid ());
|
2012-10-30 17:42:43 +00:00
|
|
|
g_main_loop_quit (main_loop);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_name_acquired (GDBusConnection *connection,
|
|
|
|
const gchar *name,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
print_debug ("Acquired the name " BUS_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
stdin_channel_io_func (GIOChannel *source,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2012-10-30 17:42:43 +00:00
|
|
|
GMainLoop *main_loop = data;
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
if (condition & G_IO_HUP)
|
|
|
|
{
|
2012-02-27 20:32:24 +00:00
|
|
|
g_debug ("gnome-shell-calendar-server[%d]: Got HUP on stdin - exiting\n",
|
2011-02-25 22:42:25 +00:00
|
|
|
(gint) getpid ());
|
2012-10-30 17:42:43 +00:00
|
|
|
g_main_loop_quit (main_loop);
|
2011-02-25 22:42:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Unhandled condition %d on GIOChannel for stdin", condition);
|
|
|
|
}
|
|
|
|
return FALSE; /* remove source */
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc,
|
|
|
|
char **argv)
|
|
|
|
{
|
|
|
|
GError *error;
|
|
|
|
GOptionContext *opt_context;
|
2012-10-30 17:42:43 +00:00
|
|
|
GMainLoop *main_loop;
|
2011-02-25 22:42:25 +00:00
|
|
|
gint ret;
|
|
|
|
guint name_owner_id;
|
|
|
|
GIOChannel *stdin_channel;
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
opt_context = NULL;
|
|
|
|
name_owner_id = 0;
|
2011-02-28 21:51:54 +00:00
|
|
|
stdin_channel = NULL;
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
|
|
|
g_assert (introspection_data != NULL);
|
|
|
|
|
|
|
|
opt_context = g_option_context_new ("gnome-shell calendar server");
|
|
|
|
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
|
|
|
error = NULL;
|
|
|
|
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
|
|
|
{
|
|
|
|
g_printerr ("Error parsing options: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-10-30 17:42:43 +00:00
|
|
|
main_loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
|
2011-02-25 22:42:25 +00:00
|
|
|
stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
|
2012-10-30 17:42:43 +00:00
|
|
|
g_io_add_watch_full (stdin_channel,
|
|
|
|
G_PRIORITY_DEFAULT,
|
|
|
|
G_IO_HUP,
|
|
|
|
stdin_channel_io_func,
|
|
|
|
g_main_loop_ref (main_loop),
|
|
|
|
(GDestroyNotify) g_main_loop_unref);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
|
|
BUS_NAME,
|
|
|
|
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
|
|
|
(opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
|
|
|
on_bus_acquired,
|
|
|
|
on_name_acquired,
|
|
|
|
on_name_lost,
|
2012-10-30 17:42:43 +00:00
|
|
|
g_main_loop_ref (main_loop),
|
|
|
|
(GDestroyNotify) g_main_loop_unref);
|
|
|
|
|
|
|
|
g_main_loop_run (main_loop);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
2012-10-30 17:42:43 +00:00
|
|
|
g_main_loop_unref (main_loop);
|
2011-02-25 22:42:25 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (stdin_channel != NULL)
|
|
|
|
g_io_channel_unref (stdin_channel);
|
|
|
|
if (_global_app != NULL)
|
|
|
|
app_free (_global_app);
|
|
|
|
if (name_owner_id != 0)
|
|
|
|
g_bus_unown_name (name_owner_id);
|
|
|
|
if (opt_context != NULL)
|
|
|
|
g_option_context_free (opt_context);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_debug (const gchar *format, ...)
|
|
|
|
{
|
|
|
|
gchar *s;
|
|
|
|
va_list ap;
|
|
|
|
gchar timebuf[64];
|
|
|
|
GTimeVal now;
|
|
|
|
time_t now_t;
|
|
|
|
struct tm broken_down;
|
|
|
|
static volatile gsize once_init_value = 0;
|
|
|
|
static gboolean show_debug = FALSE;
|
|
|
|
static guint pid = 0;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&once_init_value))
|
|
|
|
{
|
|
|
|
show_debug = (g_getenv ("CALENDAR_SERVER_DEBUG") != NULL);
|
|
|
|
pid = getpid ();
|
|
|
|
g_once_init_leave (&once_init_value, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!show_debug)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
g_get_current_time (&now);
|
|
|
|
now_t = now.tv_sec;
|
|
|
|
localtime_r (&now_t, &broken_down);
|
|
|
|
strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
|
|
|
|
|
|
|
|
va_start (ap, format);
|
|
|
|
s = g_strdup_vprintf (format, ap);
|
|
|
|
va_end (ap);
|
|
|
|
|
|
|
|
g_print ("gnome-shell-calendar-server[%d]: %s.%03d: %s\n", pid, timebuf, (gint) (now.tv_usec / 1000), s);
|
|
|
|
g_free (s);
|
|
|
|
out:
|
|
|
|
;
|
|
|
|
}
|