src/mn-evolution-server.gob (10752B) - raw
1 /*
2 * Mail Notification
3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 %headertop{
21 #include <dbus/dbus-glib.h>
22 %}
23
24 %{
25 #include <stdio.h>
26 #include <libintl.h>
27 #include <gobject/gvaluecollector.h>
28 #include <libedataserver/eds-version.h>
29 #include <camel/camel-folder.h>
30 #if EDS_CHECK_VERSION(2,29,0)
31 #include <shell/e-shell.h>
32 #include <mail/e-mail-browser.h>
33 #else
34 #include <mail/em-folder-view.h>
35 #include <mail/em-format.h>
36 #include <mail/em-message-browser.h>
37 #endif
38 #include <mail/em-utils.h>
39 #include <mail/mail-session.h>
40 #include <mail/mail-tools.h>
41 #include "mn-evolution.h"
42 #include "mn-evolution-folder-tree-server.h"
43 #include "mn-evolution-plugin.h"
44
45 /* see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=208774 */
46 static GHashTable *folders = NULL;
47
48 typedef struct
49 {
50 char *uri;
51 CamelFolder *folder;
52 } FolderInfo;
53
54 #define MN_EVOLUTION_SERVER_ERROR (mn_evolution_server_error_quark())
55
56 typedef enum
57 {
58 MN_EVOLUTION_SERVER_ERROR_FOLDER_NOT_FOUND,
59 MN_EVOLUTION_SERVER_ERROR_MESSAGE_NOT_FOUND,
60 MN_EVOLUTION_SERVER_ERROR_FOLDER_TREE_REGISTRATION_FAILED,
61 } MNEvolutionServerError;
62 %}
63
64 %afterdecls{
65 #include "mn-evolution-server-dbus.h"
66 %}
67
68 /*
69 * We hold the GDK lock because Evolution is multi-threaded and D-Bus
70 * interface methods are run from a main loop callback.
71 */
72
73 class MN:Evolution:Server from G:Object
74 {
75 signal NONE (STRING)
76 void folder_changed (self, const char *uri (check null));
77
78 signal NONE (STRING)
79 void message_reading (self, const char *uri (check null));
80
81 class_init (class)
82 {
83 dbus_g_object_type_install_info(TYPE_SELF, &dbus_glib_mn_evolution_server_object_info);
84 }
85
86 private GQuark
87 error_quark (void)
88 {
89 return g_quark_from_static_string("mn-evolution-server-error");
90 }
91
92 private void
93 cache_folder (const char *uri (check null),
94 CamelFolder *folder (check null))
95 {
96 FolderInfo *info;
97
98 info = g_new0(FolderInfo, 1);
99 info->uri = g_strdup(uri);
100 info->folder = folder;
101 #if EDS_CHECK_VERSION(2,31,0)
102 g_object_ref(folder);
103 #else
104 camel_object_ref(folder);
105 #endif
106
107 /* uncache the folder when it is deleted */
108 #if EDS_CHECK_VERSION(2,31,0)
109 g_signal_connect(folder, "deleted", G_CALLBACK(self_folder_deleted_cb), info);
110 #else
111 camel_object_hook_event(folder, "deleted", self_folder_deleted_cb, info);
112 #endif
113
114 g_hash_table_replace(folders, info->uri, info);
115 }
116
117 private void
118 folder_info_free (FolderInfo *info (check null))
119 {
120 #if EDS_CHECK_VERSION(2,31,0)
121 g_signal_handlers_disconnect_by_func(info->folder, self_folder_deleted_cb, info);
122 g_object_unref(info->folder);
123 #else
124 camel_object_unhook_event(info->folder, "deleted", self_folder_deleted_cb, info);
125 camel_object_unref(info->folder);
126 #endif
127 g_free(info->uri);
128 g_free(info);
129 }
130
131 private void
132 folder_deleted_cb (CamelObject *object,
133 gpointer event_data,
134 gpointer user_data)
135 {
136 FolderInfo *info = user_data;
137 gboolean status;
138
139 status = g_hash_table_remove(folders, info->uri);
140 g_assert(status == TRUE);
141 }
142
143 private CamelFolder *
144 lookup_folder (const char *uri (check null), GError **err)
145 {
146 CamelFolder *folder = NULL;
147
148 if (folders)
149 {
150 FolderInfo *info;
151
152 info = g_hash_table_lookup(folders, uri);
153 if (info)
154 {
155 folder = info->folder;
156 #if EDS_CHECK_VERSION(2,31,0)
157 g_object_ref(folder);
158 #else
159 camel_object_ref(folder);
160 #endif
161 }
162 }
163 else
164 folders = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) self_folder_info_free);
165
166 if (! folder)
167 {
168 folder = mail_tool_uri_to_folder(uri, 0,
169 #if EDS_CHECK_VERSION(2,91,0)
170 NULL,
171 #endif
172 NULL);
173 if (folder)
174 self_cache_folder(uri, folder);
175 else
176 g_set_error(err,
177 MN_EVOLUTION_SERVER_ERROR,
178 MN_EVOLUTION_SERVER_ERROR_FOLDER_NOT_FOUND,
179 dgettext(GETTEXT_PACKAGE, "folder not found"));
180 }
181
182 return folder;
183 }
184
185 private GValueArray *
186 value_array_new (GType type, ...)
187 {
188 GValueArray *value_array;
189 va_list args;
190
191 value_array = g_value_array_new(0);
192
193 va_start(args, type);
194
195 while (type)
196 {
197 GValue value = { 0, };
198 char *error = NULL;
199
200 g_value_init(&value, type);
201 G_VALUE_COLLECT(&value, args, 0, &error);
202 g_assert(error == NULL);
203
204 g_value_array_append(value_array, &value);
205 g_value_unset(&value);
206
207 type = va_arg(args, GType);
208 }
209
210 va_end(args);
211
212 return value_array;
213 }
214
215 private GValueArray *
216 camel_message_info_to_dbus_struct (CamelMessageInfo *info (check null))
217 {
218 const CamelSummaryMessageID *id;
219 char hexhash[sizeof(CamelSummaryMessageID) * 2 + 1];
220 int i;
221
222 id = camel_message_info_message_id(info);
223 for (i = 0; i < sizeof(id->id.hash); i++)
224 sprintf(hexhash + i * 2, "%.2x", id->id.hash[i]);
225
226 g_assert(camel_message_info_uid(info) != NULL);
227
228 return self_value_array_new(/* char *uid */
229 G_TYPE_STRING, camel_message_info_uid(info),
230 /* unsigned int sent_time */
231 G_TYPE_UINT, (unsigned int) camel_message_info_date_sent(info),
232 /* unsigned int received_time */
233 G_TYPE_UINT, (unsigned int) camel_message_info_date_received(info),
234 /* char *id */
235 G_TYPE_STRING, hexhash,
236 /* char *from */
237 G_TYPE_STRING, camel_message_info_from(info),
238 /* char *subject */
239 G_TYPE_STRING, camel_message_info_subject(info),
240 (GType) 0);
241 }
242
243 private gboolean
244 get_unseen_messages (self,
245 const char *folder_uri (check null),
246 GPtrArray **ret (check null),
247 GError **err)
248 {
249 CamelFolder *folder;
250
251 GDK_THREADS_ENTER();
252
253 folder = self_lookup_folder(folder_uri, err);
254 if (folder)
255 {
256 GPtrArray *summary;
257 int i;
258
259 *ret = g_ptr_array_new();
260
261 summary = camel_folder_get_summary(folder);
262
263 for (i = 0; i < summary->len; i++)
264 {
265 #if EDS_CHECK_VERSION(2,23,5)
266 char *uid = summary->pdata[i];
267 CamelMessageInfo *info = camel_folder_get_message_info(folder, uid);
268 #else
269 CamelMessageInfo *info = summary->pdata[i];
270 #endif
271
272 if ((camel_message_info_flags(info) & CAMEL_MESSAGE_SEEN) == 0)
273 g_ptr_array_add(*ret, self_camel_message_info_to_dbus_struct(info));
274 }
275
276 camel_folder_free_summary(folder, summary);
277 #if EDS_CHECK_VERSION(2,31,0)
278 g_object_unref(folder);
279 #else
280 camel_object_unref(folder);
281 #endif
282 }
283
284 GDK_THREADS_LEAVE();
285
286 return folder != NULL;
287 }
288
289 private gboolean
290 get_folder_name (self,
291 const char *folder_uri (check null),
292 char **ret (check null),
293 GError **err)
294 {
295 CamelFolder *folder;
296
297 GDK_THREADS_ENTER();
298
299 folder = self_lookup_folder(folder_uri, err);
300 if (folder)
301 {
302 *ret = g_strdup(camel_folder_get_name(folder));
303 #if EDS_CHECK_VERSION(2,31,0)
304 g_object_unref(folder);
305 #else
306 camel_object_unref(folder);
307 #endif
308 }
309
310 GDK_THREADS_LEAVE();
311
312 return folder != NULL;
313 }
314
315 private gboolean
316 open_message (self,
317 const char *folder_uri (check null),
318 const char *message_uid (check null),
319 GError **err)
320 {
321 CamelFolder *folder;
322
323 GDK_THREADS_ENTER();
324
325 folder = self_lookup_folder(folder_uri, err);
326 if (folder)
327 {
328 #if EDS_CHECK_VERSION(2,29,0)
329 EShell *shell;
330 EShellBackend *shell_backend;
331 GtkWidget *browser;
332
333 shell = e_shell_get_default ();
334 shell_backend = e_shell_get_backend_by_name (shell, "mail");
335
336 browser = e_mail_browser_new (shell_backend);
337 e_mail_reader_set_folder (E_MAIL_READER (browser), folder, folder_uri);
338 e_mail_reader_set_message (E_MAIL_READER (browser), message_uid);
339 gtk_widget_show (browser);
340 #else
341 GtkWidget *browser;
342
343 /* modelled after Evolution's handleuri_got_folder() */
344
345 browser = em_message_browser_window_new();
346
347 em_format_set_session((EMFormat *) ((EMFolderView *) browser)->preview, session);
348 em_folder_view_set_folder((EMFolderView *) browser, folder, folder_uri);
349 em_folder_view_set_message((EMFolderView *) browser, message_uid, FALSE);
350 gtk_widget_show(((EMMessageBrowser *) browser)->window);
351 #endif
352
353 #if EDS_CHECK_VERSION(2,31,0)
354 g_object_unref(folder);
355 #else
356 camel_object_unref(folder);
357 #endif
358 }
359
360 GDK_THREADS_LEAVE();
361
362 return folder != NULL;
363 }
364
365 private gboolean
366 set_message_flags (self,
367 const char *folder_uri (check null),
368 const char *message_uid (check null),
369 unsigned int flags,
370 GError **err)
371 {
372 CamelFolder *folder;
373 gboolean status = FALSE;
374
375 GDK_THREADS_ENTER();
376
377 folder = self_lookup_folder(folder_uri, err);
378 if (folder)
379 {
380 status = camel_folder_set_message_flags(folder, message_uid, flags, flags);
381 #if EDS_CHECK_VERSION(2,31,0)
382 g_object_unref(folder);
383 #else
384 camel_object_unref(folder);
385 #endif
386
387 if (! status)
388 g_set_error(err,
389 MN_EVOLUTION_SERVER_ERROR,
390 MN_EVOLUTION_SERVER_ERROR_MESSAGE_NOT_FOUND,
391 dgettext(GETTEXT_PACKAGE, "message not found"));
392 }
393
394 GDK_THREADS_LEAVE();
395
396 return status;
397 }
398
399 private gboolean
400 folder_tree_new (self, guint32 id, GError **err)
401 {
402 MNEvolutionFolderTreeServer *tree;
403 char *service;
404 char *path;
405 GError *tmp_err = NULL;
406 gboolean status;
407
408 GDK_THREADS_ENTER();
409
410 tree = mn_evolution_folder_tree_server_new(id);
411
412 service = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_SERVICE, id);
413 path = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_PATH, id);
414
415 status = mn_evolution_plugin_register_server(G_OBJECT(tree), service, path, &tmp_err);
416
417 g_free(service);
418 g_free(path);
419
420 if (! status)
421 {
422 /* unlikely to ever happen, not worth a translation */
423 g_set_error(err,
424 MN_EVOLUTION_SERVER_ERROR,
425 MN_EVOLUTION_SERVER_ERROR_FOLDER_TREE_REGISTRATION_FAILED,
426 "cannot register folder tree server: %s", tmp_err->message);
427 g_error_free(tmp_err);
428 g_object_unref(tree);
429 }
430
431 GDK_THREADS_LEAVE();
432
433 return status;
434 }
435
436 public MNEvolutionServer *
437 new (void)
438 {
439 return GET_NEW;
440 }
441 }