No issues found
1 /*
2 * e-book-shell-backend.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-book-shell-backend.h"
27
28 #include <string.h>
29 #include <glib/gi18n.h>
30 #include <libebook/libebook.h>
31 #include <libedataserverui/libedataserverui.h>
32
33 #include "e-util/e-import.h"
34 #include "shell/e-shell.h"
35 #include "shell/e-shell-window.h"
36 #include "widgets/misc/e-book-source-config.h"
37 #include "widgets/misc/e-preferences-window.h"
38 #include "widgets/misc/e-source-config-dialog.h"
39
40 #include "addressbook/gui/widgets/eab-gui-util.h"
41 #include "addressbook/gui/widgets/e-addressbook-view.h"
42 #include "addressbook/gui/contact-editor/e-contact-editor.h"
43 #include "addressbook/gui/contact-editor/e-contact-quick-add.h"
44 #include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
45 #include "addressbook/importers/evolution-addressbook-importers.h"
46
47 #include "autocompletion-config.h"
48
49 #include "e-book-shell-content.h"
50 #include "e-book-shell-migrate.h"
51 #include "e-book-shell-settings.h"
52 #include "e-book-shell-view.h"
53
54 #ifdef ENABLE_SMIME
55 #include "smime/gui/component.h"
56 #include "smime/gui/certificate-manager.h"
57 #endif
58
59 #define E_BOOK_SHELL_BACKEND_GET_PRIVATE(obj) \
60 (G_TYPE_INSTANCE_GET_PRIVATE \
61 ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendPrivate))
62
63 struct _EBookShellBackendPrivate {
64 gint placeholder;
65 };
66
67 G_DEFINE_DYNAMIC_TYPE (
68 EBookShellBackend,
69 e_book_shell_backend,
70 E_TYPE_SHELL_BACKEND)
71
72 static void
73 book_shell_backend_init_importers (void)
74 {
75 EImportClass *import_class;
76 EImportImporter *importer;
77
78 import_class = g_type_class_ref (e_import_get_type ());
79
80 importer = evolution_ldif_importer_peek ();
81 e_import_class_add_importer (import_class, importer, NULL, NULL);
82
83 importer = evolution_vcard_importer_peek ();
84 e_import_class_add_importer (import_class, importer, NULL, NULL);
85
86 importer = evolution_csv_outlook_importer_peek ();
87 e_import_class_add_importer (import_class, importer, NULL, NULL);
88
89 importer = evolution_csv_mozilla_importer_peek ();
90 e_import_class_add_importer (import_class, importer, NULL, NULL);
91
92 importer = evolution_csv_evolution_importer_peek ();
93 e_import_class_add_importer (import_class, importer, NULL, NULL);
94 }
95
96 static void
97 book_shell_backend_new_contact_cb (GObject *source_object,
98 GAsyncResult *result,
99 gpointer user_data)
100 {
101 ESource *source = E_SOURCE (source_object);
102 EShell *shell = user_data;
103 EClient *client = NULL;
104 EContact *contact;
105 EABEditor *editor;
106 GError *error = NULL;
107
108 e_client_utils_open_new_finish (source, result, &client, &error);
109
110 /* XXX Handle errors better. */
111 if (error != NULL) {
112 g_warn_if_fail (client == NULL);
113 g_warning (
114 "%s: Failed to open book: %s",
115 G_STRFUNC, error->message);
116 g_error_free (error);
117 goto exit;
118 }
119
120 g_return_if_fail (E_IS_CLIENT (client));
121
122 contact = e_contact_new ();
123
124 editor = e_contact_editor_new (
125 shell, E_BOOK_CLIENT (client), contact, TRUE, TRUE);
126
127 eab_editor_show (editor);
128
129 g_object_unref (contact);
130 g_object_unref (client);
131
132 exit:
133 g_object_unref (shell);
134 }
135
136 static void
137 book_shell_backend_new_contact_list_cb (GObject *source_object,
138 GAsyncResult *result,
139 gpointer user_data)
140 {
141 ESource *source = E_SOURCE (source_object);
142 EShell *shell = user_data;
143 EClient *client = NULL;
144 EContact *contact;
145 EABEditor *editor;
146 GError *error = NULL;
147
148 e_client_utils_open_new_finish (source, result, &client, &error);
149
150 /* XXX Handle errors better. */
151 if (error != NULL) {
152 g_warn_if_fail (client == NULL);
153 g_warning (
154 "%s: Failed to open book: %s",
155 G_STRFUNC, error->message);
156 g_error_free (error);
157 goto exit;
158 }
159
160 g_return_if_fail (E_IS_CLIENT (client));
161
162 contact = e_contact_new ();
163
164 editor = e_contact_list_editor_new (
165 shell, E_BOOK_CLIENT (client), contact, TRUE, TRUE);
166
167 eab_editor_show (editor);
168
169 g_object_unref (contact);
170 g_object_unref (client);
171
172 exit:
173 g_object_unref (shell);
174 }
175
176 static void
177 action_contact_new_cb (GtkAction *action,
178 EShellWindow *shell_window)
179 {
180 EShell *shell;
181 ESource *source = NULL;
182 ESourceRegistry *registry;
183 const gchar *action_name;
184
185 /* This callback is used for both contacts and contact lists. */
186
187 shell = e_shell_window_get_shell (shell_window);
188
189 if (g_strcmp0 (e_shell_window_get_active_view (shell_window), "addressbook") == 0) {
190 EShellView *shell_view = e_shell_window_get_shell_view (shell_window, "addressbook");
191
192 if (shell_view && E_IS_BOOK_SHELL_VIEW (shell_view)) {
193 EBookShellContent *book_shell_content;
194 EAddressbookView *view;
195 EAddressbookModel *model;
196 EBookClient *book_client;
197
198 book_shell_content = NULL;
199 g_object_get (G_OBJECT (shell_view), "shell-content", &book_shell_content, NULL);
200 g_return_if_fail (book_shell_content != NULL);
201
202 view = e_book_shell_content_get_current_view (book_shell_content);
203 g_return_if_fail (view != NULL);
204
205 model = e_addressbook_view_get_model (view);
206 book_client = e_addressbook_model_get_client (model);
207 g_return_if_fail (book_client != NULL);
208
209 source = g_object_ref (e_client_get_source (E_CLIENT (book_client)));
210
211 g_object_unref (book_shell_content);
212 }
213 }
214
215 if (!source) {
216 registry = e_shell_get_registry (shell);
217 source = e_source_registry_ref_default_address_book (registry);
218 }
219
220 /* Use a callback function appropriate for the action. */
221 action_name = gtk_action_get_name (action);
222 if (strcmp (action_name, "contact-new") == 0)
223 e_client_utils_open_new (
224 source, E_CLIENT_SOURCE_TYPE_CONTACTS, FALSE, NULL,
225 book_shell_backend_new_contact_cb,
226 g_object_ref (shell));
227 if (strcmp (action_name, "contact-new-list") == 0)
228 e_client_utils_open_new (
229 source, E_CLIENT_SOURCE_TYPE_CONTACTS, FALSE, NULL,
230 book_shell_backend_new_contact_list_cb,
231 g_object_ref (shell));
232
233 g_object_unref (source);
234 }
235
236 static void
237 action_address_book_new_cb (GtkAction *action,
238 EShellWindow *shell_window)
239 {
240 EShell *shell;
241 ESourceRegistry *registry;
242 GtkWidget *config;
243 GtkWidget *dialog;
244 const gchar *icon_name;
245
246 shell = e_shell_window_get_shell (shell_window);
247
248 registry = e_shell_get_registry (shell);
249 config = e_book_source_config_new (registry, NULL);
250
251 dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
252
253 gtk_window_set_transient_for (
254 GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
255
256 icon_name = gtk_action_get_icon_name (action);
257 gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
258
259 gtk_window_set_title (GTK_WINDOW (dialog), _("New Address Book"));
260
261 gtk_widget_show (dialog);
262 }
263
264 static GtkActionEntry item_entries[] = {
265
266 { "contact-new",
267 "contact-new",
268 NC_("New", "_Contact"),
269 "<Shift><Control>c",
270 N_("Create a new contact"),
271 G_CALLBACK (action_contact_new_cb) },
272
273 { "contact-new-list",
274 "stock_contact-list",
275 NC_("New", "Contact _List"),
276 "<Shift><Control>l",
277 N_("Create a new contact list"),
278 G_CALLBACK (action_contact_new_cb) }
279 };
280
281 static GtkActionEntry source_entries[] = {
282
283 { "address-book-new",
284 "address-book-new",
285 NC_("New", "Address _Book"),
286 NULL,
287 N_("Create a new address book"),
288 G_CALLBACK (action_address_book_new_cb) }
289 };
290
291 static gboolean
292 book_shell_backend_init_preferences (EShell *shell)
293 {
294 GtkWidget *preferences_window;
295
296 /* This is a main loop idle callback. */
297
298 preferences_window = e_shell_get_preferences_window (shell);
299
300 e_preferences_window_add_page (
301 E_PREFERENCES_WINDOW (preferences_window),
302 "contacts",
303 "preferences-autocompletion",
304 _("Contacts"),
305 "index#contacts",
306 autocompletion_config_new,
307 200);
308
309 #ifdef ENABLE_SMIME
310 preferences_window = e_shell_get_preferences_window (shell);
311 e_preferences_window_add_page (
312 E_PREFERENCES_WINDOW (preferences_window),
313 "certificates",
314 "preferences-certificates",
315 _("Certificates"),
316 "mail-encryption-s-mime-manage",
317 e_cert_manager_config_new,
318 700);
319 #endif
320
321 return FALSE;
322 }
323
324 static void
325 book_shell_backend_quick_add_email_cb (EShell *shell,
326 const gchar *email)
327 {
328 ESourceRegistry *registry;
329
330 /* XXX This is an ugly hack but it's the only way I could think
331 * of to integrate this feature with other shell modules. */
332
333 registry = e_shell_get_registry (shell);
334 e_contact_quick_add_email (registry, email, NULL, NULL);
335 }
336
337 static void
338 book_shell_backend_quick_add_vcard_cb (EShell *shell,
339 const gchar *vcard)
340 {
341 ESourceRegistry *registry;
342
343 /* XXX This is an ugly hack but it's the only way I could think
344 * of to integrate this feature with other shell modules. */
345
346 registry = e_shell_get_registry (shell);
347 e_contact_quick_add_vcard (registry, vcard, NULL, NULL);
348 }
349
350 static gboolean
351 book_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
352 const gchar *uri)
353 {
354 SoupURI *soup_uri;
355 const gchar *cp;
356 gchar *source_uid = NULL;
357 gchar *contact_uid = NULL;
358
359 if (!g_str_has_prefix (uri, "contacts:"))
360 return FALSE;
361
362 soup_uri = soup_uri_new (uri);
363
364 if (soup_uri == NULL)
365 return FALSE;
366
367 cp = soup_uri_get_query (soup_uri);
368
369 if (cp == NULL) {
370 soup_uri_free (soup_uri);
371 return FALSE;
372 }
373
374 while (*cp != '\0') {
375 gchar *header;
376 gchar *content;
377 gsize length;
378 gsize content_length;
379
380 length = strcspn (cp, "=&");
381
382 /* If it's malformed, give up. */
383 if (cp[length] != '=')
384 break;
385
386 header = (gchar *) cp;
387 header[length] = '\0';
388 cp += length + 1;
389
390 content_length = strcspn (cp, "&");
391 content = g_strndup (cp, content_length);
392
393 if (g_ascii_strcasecmp (header, "source-uid") == 0)
394 source_uid = g_strdup (content);
395
396 if (g_ascii_strcasecmp (header, "contact-uid") == 0)
397 contact_uid = g_strdup (content);
398
399 g_free (content);
400
401 cp += content_length;
402 if (*cp == '&') {
403 cp++;
404 if (strcmp (cp, "amp;"))
405 cp += 4;
406 }
407 }
408
409 /* FIXME */
410 /*addressbook_view_edit_contact (view, source_uid, contact_uid);*/
411
412 g_free (source_uid);
413 g_free (contact_uid);
414
415 soup_uri_free (soup_uri);
416
417 return TRUE;
418 }
419
420 static void
421 book_shell_backend_window_added_cb (EShellBackend *shell_backend,
422 GtkWindow *window)
423 {
424 const gchar *backend_name;
425
426 if (!E_IS_SHELL_WINDOW (window))
427 return;
428
429 backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
430
431 e_shell_window_register_new_item_actions (
432 E_SHELL_WINDOW (window), backend_name,
433 item_entries, G_N_ELEMENTS (item_entries));
434
435 e_shell_window_register_new_source_actions (
436 E_SHELL_WINDOW (window), backend_name,
437 source_entries, G_N_ELEMENTS (source_entries));
438 }
439
440 static void
441 book_shell_backend_constructed (GObject *object)
442 {
443 EShell *shell;
444 EShellBackend *shell_backend;
445
446 shell_backend = E_SHELL_BACKEND (object);
447 shell = e_shell_backend_get_shell (shell_backend);
448
449 /* XXX Why is this here? Address books aren't the only
450 * things that use S/MIME. Maybe put it in EShell? */
451 #ifdef ENABLE_SMIME
452 smime_component_init ();
453 #endif
454
455 book_shell_backend_init_importers ();
456
457 g_signal_connect (
458 shell, "event::contact-quick-add-email",
459 G_CALLBACK (book_shell_backend_quick_add_email_cb), NULL);
460
461 g_signal_connect_swapped (
462 shell, "event::contact-quick-add-vcard",
463 G_CALLBACK (book_shell_backend_quick_add_vcard_cb), NULL);
464
465 g_signal_connect_swapped (
466 shell, "handle-uri",
467 G_CALLBACK (book_shell_backend_handle_uri_cb),
468 shell_backend);
469
470 g_signal_connect_swapped (
471 shell, "window-added",
472 G_CALLBACK (book_shell_backend_window_added_cb),
473 shell_backend);
474
475 e_book_shell_backend_init_settings (shell);
476
477 /* Initialize preferences after the main loop starts so
478 * that all EPlugins and EPluginHooks are loaded first. */
479 g_idle_add ((GSourceFunc) book_shell_backend_init_preferences, shell);
480
481 /* Chain up to parent's constructed() method. */
482 G_OBJECT_CLASS (e_book_shell_backend_parent_class)->constructed (object);
483 }
484
485 static void
486 e_book_shell_backend_class_init (EBookShellBackendClass *class)
487 {
488 GObjectClass *object_class;
489 EShellBackendClass *shell_backend_class;
490
491 g_type_class_add_private (class, sizeof (EBookShellBackendPrivate));
492
493 object_class = G_OBJECT_CLASS (class);
494 object_class->constructed = book_shell_backend_constructed;
495
496 shell_backend_class = E_SHELL_BACKEND_CLASS (class);
497 shell_backend_class->shell_view_type = E_TYPE_BOOK_SHELL_VIEW;
498 shell_backend_class->name = "addressbook";
499 shell_backend_class->aliases = "contacts";
500 shell_backend_class->schemes = "";
501 shell_backend_class->sort_order = 300;
502 shell_backend_class->preferences_page = "contacts";
503 shell_backend_class->start = NULL;
504 shell_backend_class->migrate = e_book_shell_backend_migrate;
505 }
506
507 static void
508 e_book_shell_backend_class_finalize (EBookShellBackendClass *class)
509 {
510 }
511
512 static void
513 e_book_shell_backend_init (EBookShellBackend *book_shell_backend)
514 {
515 book_shell_backend->priv =
516 E_BOOK_SHELL_BACKEND_GET_PRIVATE (book_shell_backend);
517 }
518
519 void
520 e_book_shell_backend_type_register (GTypeModule *type_module)
521 {
522 /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
523 * function, so we have to wrap it with a public function in
524 * order to register types from a separate compilation unit. */
525 e_book_shell_backend_register_type (type_module);
526 }