No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Federico Mena-Quintero <federico@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <camel/camel.h>
29
30 #include "alarm.h"
31 #include "alarm-notify.h"
32 #include "alarm-queue.h"
33 #include "config-data.h"
34
35 #define ALARM_NOTIFY_GET_PRIVATE(obj) \
36 (G_TYPE_INSTANCE_GET_PRIVATE \
37 ((obj), TYPE_ALARM_NOTIFY, AlarmNotifyPrivate))
38
39 #define APPLICATION_ID "org.gnome.EvolutionAlarmNotify"
40
41 struct _AlarmNotifyPrivate {
42 ESourceRegistry *registry;
43 GHashTable *clients;
44 GMutex mutex;
45 };
46
47 /* Forward Declarations */
48 static void alarm_notify_initable_init (GInitableIface *interface);
49
50 G_DEFINE_TYPE_WITH_CODE (
51 AlarmNotify, alarm_notify, GTK_TYPE_APPLICATION,
52 G_IMPLEMENT_INTERFACE (
53 G_TYPE_INITABLE, alarm_notify_initable_init))
54
55 static void
56 alarm_notify_load_calendars (AlarmNotify *an)
57 {
58 GList *list, *iter;
59
60 /* Add all available ESources. alarm_notify_add_calendar() will
61 * discard the ones we're not interested in (mail accounts, etc.). */
62
63 list = e_source_registry_list_sources (an->priv->registry, NULL);
64
65 for (iter = list; iter != NULL; iter = g_list_next (iter))
66 alarm_notify_add_calendar (an, E_SOURCE (iter->data));
67
68 g_list_free_full (list, (GDestroyNotify) g_object_unref);
69 }
70
71 static void
72 alarm_notify_dispose (GObject *object)
73 {
74 AlarmNotifyPrivate *priv;
75 GHashTableIter iter;
76 gpointer client;
77
78 priv = ALARM_NOTIFY_GET_PRIVATE (object);
79
80 if (priv->registry != NULL) {
81 g_object_unref (priv->registry);
82 priv->registry = NULL;
83 }
84
85 g_hash_table_iter_init (&iter, priv->clients);
86 while (g_hash_table_iter_next (&iter, NULL, &client))
87 alarm_queue_remove_client (client, TRUE);
88
89 /* Chain up to parent's dispose() method. */
90 G_OBJECT_CLASS (alarm_notify_parent_class)->dispose (object);
91 }
92
93 static void
94 alarm_notify_finalize (GObject *object)
95 {
96 AlarmNotifyPrivate *priv;
97
98 priv = ALARM_NOTIFY_GET_PRIVATE (object);
99
100 g_hash_table_destroy (priv->clients);
101
102 alarm_queue_done ();
103 alarm_done ();
104
105 g_mutex_clear (&priv->mutex);
106
107 /* Chain up to parent's finalize() method. */
108 G_OBJECT_CLASS (alarm_notify_parent_class)->finalize (object);
109 }
110
111 static void
112 alarm_notify_startup (GApplication *application)
113 {
114 GtkIconTheme *icon_theme;
115
116 /* Chain up to parent's startup() method. */
117 G_APPLICATION_CLASS (alarm_notify_parent_class)->startup (application);
118
119 /* Keep the application running. */
120 g_application_hold (application);
121
122 config_data_init_debugging ();
123
124 /* FIXME Ideally we should not use Camel libraries in calendar,
125 * though it is the case currently for attachments. Remove
126 * this once that is fixed. */
127
128 /* Initialize Camel's type system. */
129 camel_object_get_type ();
130
131 icon_theme = gtk_icon_theme_get_default ();
132 gtk_icon_theme_append_search_path (icon_theme, EVOLUTION_ICONDIR);
133 }
134
135 static void
136 alarm_notify_activate (GApplication *application)
137 {
138 AlarmNotify *an = ALARM_NOTIFY (application);
139
140 if (g_application_get_is_remote (application)) {
141 g_application_quit (application);
142 return;
143 }
144
145 if (an->priv->registry != NULL) {
146 alarm_notify_load_calendars (an);
147
148 g_signal_connect_swapped (
149 an->priv->registry, "source-added",
150 G_CALLBACK (alarm_notify_add_calendar), an);
151
152 g_signal_connect_swapped (
153 an->priv->registry, "source-removed",
154 G_CALLBACK (alarm_notify_remove_calendar), an);
155 }
156 }
157
158 static gboolean
159 alarm_notify_initable (GInitable *initable,
160 GCancellable *cancellable,
161 GError **error)
162 {
163 AlarmNotify *an = ALARM_NOTIFY (initable);
164
165 an->priv->registry = e_source_registry_new_sync (cancellable, error);
166
167 return (an->priv->registry != NULL);
168 }
169
170 static void
171 alarm_notify_class_init (AlarmNotifyClass *class)
172 {
173 GObjectClass *object_class;
174 GApplicationClass *application_class;
175
176 g_type_class_add_private (class, sizeof (AlarmNotifyPrivate));
177
178 object_class = G_OBJECT_CLASS (class);
179 object_class->dispose = alarm_notify_dispose;
180 object_class->finalize = alarm_notify_finalize;
181
182 application_class = G_APPLICATION_CLASS (class);
183 application_class->startup = alarm_notify_startup;
184 application_class->activate = alarm_notify_activate;
185 }
186
187 static void
188 alarm_notify_initable_init (GInitableIface *interface)
189 {
190 /* XXX Awkward name since we're missing an 'E' prefix. */
191 interface->init = alarm_notify_initable;
192 }
193
194 static void
195 alarm_notify_init (AlarmNotify *an)
196 {
197 an->priv = ALARM_NOTIFY_GET_PRIVATE (an);
198 g_mutex_init (&an->priv->mutex);
199
200 an->priv->clients = g_hash_table_new_full (
201 (GHashFunc) e_source_hash,
202 (GEqualFunc) e_source_equal,
203 (GDestroyNotify) g_object_unref,
204 (GDestroyNotify) g_object_unref);
205
206 alarm_queue_init (an);
207 }
208
209 /**
210 * alarm_notify_new:
211 *
212 * Creates a new #AlarmNotify object.
213 *
214 * Returns: a newly-created #AlarmNotify
215 **/
216 AlarmNotify *
217 alarm_notify_new (GCancellable *cancellable,
218 GError **error)
219 {
220 return g_initable_new (
221 TYPE_ALARM_NOTIFY, cancellable, error,
222 "application-id", APPLICATION_ID, NULL);
223 }
224
225 static void
226 client_opened_cb (GObject *source_object,
227 GAsyncResult *result,
228 gpointer user_data)
229 {
230 ESource *source = E_SOURCE (source_object);
231 AlarmNotify *an = ALARM_NOTIFY (user_data);
232 EClient *client = NULL;
233 ECalClient *cal_client;
234 GError *error = NULL;
235
236 e_client_utils_open_new_finish (source, result, &client, &error);
237
238 /* Sanity check. */
239 g_return_if_fail (
240 ((client != NULL) && (error == NULL)) ||
241 ((client == NULL) && (error != NULL)));
242
243 if (error != NULL) {
244 debug (
245 ("Failed to open '%s' (%s): %s",
246 e_source_get_display_name (source),
247 e_source_get_uid (source), error->message));
248 g_error_free (error);
249 return;
250 }
251
252 g_hash_table_insert (
253 an->priv->clients,
254 g_object_ref (source), client);
255
256 cal_client = E_CAL_CLIENT (client);
257
258 /* to resolve floating DATE-TIME properly */
259 e_cal_client_set_default_timezone (
260 cal_client, config_data_get_timezone ());
261
262 alarm_queue_add_client (cal_client);
263 }
264
265 /**
266 * alarm_notify_add_calendar:
267 * @an: an #AlarmNotify
268 * @source: the #ESource to create an #ECal from
269 *
270 * Tells the alarm notification service to load a calendar and start
271 * monitoring its alarms.
272 **/
273 void
274 alarm_notify_add_calendar (AlarmNotify *an,
275 ESource *source)
276 {
277 EClientSourceType client_source_type;
278 const gchar *extension_name;
279
280 g_return_if_fail (IS_ALARM_NOTIFY (an));
281
282 g_mutex_lock (&an->priv->mutex);
283
284 /* Check if we already know about this ESource. */
285 if (g_hash_table_lookup (an->priv->clients, source) != NULL) {
286 g_mutex_unlock (&an->priv->mutex);
287 return;
288 }
289
290 /* Check if this is an ESource we're interested in. */
291 if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
292 client_source_type = E_CLIENT_SOURCE_TYPE_EVENTS;
293 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST))
294 client_source_type = E_CLIENT_SOURCE_TYPE_MEMOS;
295 else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
296 client_source_type = E_CLIENT_SOURCE_TYPE_TASKS;
297 else {
298 g_mutex_unlock (&an->priv->mutex);
299 return;
300 }
301
302 /* Check if alarms are even wanted on this ESource. */
303 extension_name = E_SOURCE_EXTENSION_ALARMS;
304 if (e_source_has_extension (source, extension_name)) {
305 ESourceAlarms *extension;
306 extension = e_source_get_extension (source, extension_name);
307 if (!e_source_alarms_get_include_me (extension)) {
308 g_mutex_unlock (&an->priv->mutex);
309 return;
310 }
311 }
312
313 debug (("Opening '%s' (%s)", e_source_get_display_name (source), e_source_get_uid (source)));
314
315 e_client_utils_open_new (
316 source, client_source_type, TRUE, NULL,
317 client_opened_cb, an);
318
319 g_mutex_unlock (&an->priv->mutex);
320 }
321
322 void
323 alarm_notify_remove_calendar (AlarmNotify *an,
324 ESource *source)
325 {
326 ECalClient *cal_client;
327
328 cal_client = g_hash_table_lookup (an->priv->clients, source);
329 if (cal_client != NULL) {
330 alarm_queue_remove_client (cal_client, FALSE);
331 g_hash_table_remove (an->priv->clients, source);
332 }
333 }