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 }