"Fossies" - the Fresh Open Source Software Archive 
Member "evolution-mapi-3.46.1/src/configuration/e-mapi-subscribe-foreign-folder.c" (2 Dec 2022, 27023 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "e-mapi-subscribe-foreign-folder.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
3.44.2_vs_3.45.1.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 *
17 * Authors:
18 * Milan Crha <mcrha@redhat.com>
19 *
20 * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
21 *
22 */
23
24 #include "evolution-mapi-config.h"
25
26 #include <glib/gi18n-lib.h>
27 #include <gtk/gtk.h>
28
29 #include <libemail-engine/libemail-engine.h>
30
31 #include "camel/camel-mapi-store.h"
32 #include "camel/camel-mapi-store-summary.h"
33
34 #include "e-mapi-config-utils.h"
35 #include "e-mapi-search-gal-user.h"
36 #include "e-mapi-subscribe-foreign-folder.h"
37 #include "e-mapi-utils.h"
38
39 #ifndef PidTagMailboxOwnerName
40 #define PidTagMailboxOwnerName PR_USER_NAME_UNICODE
41 #endif
42
43 #define STR_ACCOUNTS_COMBO "e-mapi-accounts-combo"
44 #define STR_USER_NAME_SELECTOR_ENTRY "e-mapi-name-selector-entry"
45 #define STR_FOLDER_NAME_COMBO "e-mapi-folder-name-combo"
46 #define STR_SUBFOLDERS_CHECK "e-mapi-subfolders-check"
47 #define STR_MAPI_CAMEL_SESSION "e-mapi-camel-session"
48 #define STR_MAPI_DIRECT_USER_NAME "e-mapi-direct-user-name"
49
50 enum {
51 COLUMN_UID = 0,
52 COLUMN_DISPLAY_NAME,
53 COLUMN_STORE
54 };
55
56 static gboolean
57 add_foreign_folder_to_camel (CamelMapiStore *mapi_store,
58 const gchar *foreign_username,
59 mapi_id_t folder_id,
60 mapi_id_t parent_fid,
61 gboolean include_subfolders,
62 const gchar *display_username,
63 const gchar *display_foldername,
64 GError **perror)
65 {
66 gboolean res = TRUE;
67 gchar *parent_path = NULL;
68 CamelStoreInfo *parent_si = NULL;
69 GPtrArray *array;
70 guint ii;
71
72 g_return_val_if_fail (mapi_store != NULL, FALSE);
73 g_return_val_if_fail (mapi_store->summary != NULL, FALSE);
74 g_return_val_if_fail (foreign_username != NULL, FALSE);
75 g_return_val_if_fail (folder_id != 0, FALSE);
76 g_return_val_if_fail (folder_id != parent_fid, FALSE);
77 g_return_val_if_fail (display_username != NULL, FALSE);
78 g_return_val_if_fail (display_foldername != NULL, FALSE);
79
80 array = camel_store_summary_array (mapi_store->summary);
81
82 for (ii = 0; res && ii < array->len; ii++) {
83 CamelStoreInfo *si;
84 CamelMapiStoreInfo *msi;
85
86 si = g_ptr_array_index (array, ii);
87
88 msi = (CamelMapiStoreInfo *) si;
89
90 /* folder_id is unique even between users, thus can just check for it */
91 if (msi->folder_id == folder_id) {
92 res = FALSE;
93 g_propagate_error (perror,
94 g_error_new (E_MAPI_ERROR, MAPI_E_INVALID_PARAMETER,
95 _("Cannot add folder, folder already exists as “%s”"), camel_store_info_get_path (si)));
96 } else if (parent_fid != 0 && msi->folder_id == parent_fid) {
97 if (g_strcmp0 (foreign_username, msi->foreign_username) == 0) {
98 g_free (parent_path);
99 if (parent_si)
100 camel_store_info_unref (parent_si);
101 parent_si = camel_store_info_ref (si);
102 parent_path = g_strdup (camel_store_info_get_path (parent_si));
103 } else {
104 g_debug ("%s: parent folder '%s' with other user '%s' than expected '%s', skipping chain",
105 G_STRFUNC, camel_store_info_get_path (si), msi->foreign_username, foreign_username);
106 }
107 }
108 }
109
110 camel_store_summary_array_free (mapi_store->summary, array);
111
112 if (res) {
113 gchar *path;
114
115 if (!parent_path) {
116 gchar *mailbox;
117
118 /* Translators: The '%s' is replaced with user name, to whom the foreign mailbox belongs.
119 Example result: "Mailbox — John Smith"
120 */
121 mailbox = g_strdup_printf (C_("ForeignFolder", "Mailbox — %s"), display_username);
122 parent_path = g_strdup_printf ("%s/%s", DISPLAY_NAME_FOREIGN_FOLDERS, mailbox);
123
124 g_free (mailbox);
125 }
126
127 path = g_strconcat (parent_path, "/", display_foldername, NULL);
128
129 /* make sure the path is unique */
130 camel_mapi_store_ensure_unique_path (mapi_store, &path);
131
132 if (camel_mapi_store_summary_add_from_full (mapi_store->summary, path, folder_id, parent_fid,
133 CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_SUBSCRIBED,
134 CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN | CAMEL_MAPI_STORE_FOLDER_FLAG_MAIL |
135 (include_subfolders ? CAMEL_MAPI_STORE_FOLDER_FLAG_FOREIGN_WITH_SUBFOLDERS : 0),
136 foreign_username)) {
137 if (parent_si) {
138 CamelMapiStoreInfo *msi = (CamelMapiStoreInfo *) parent_si;
139
140 msi->camel_folder_flags = msi->camel_folder_flags & (~CAMEL_FOLDER_NOCHILDREN);
141 }
142
143 camel_store_summary_touch (mapi_store->summary);
144 camel_store_summary_save (mapi_store->summary);
145
146 camel_mapi_store_announce_subscribed_folder (mapi_store, path);
147 } else {
148 res = FALSE;
149 g_propagate_error (perror,
150 g_error_new (E_MAPI_ERROR, MAPI_E_INVALID_PARAMETER,
151 _("Cannot add folder, failed to add to store’s summary")));
152 }
153
154 g_free (path);
155 }
156
157 if (parent_si)
158 camel_store_info_unref (parent_si);
159 g_free (parent_path);
160
161 return res;
162 }
163
164 static void
165 enable_ok_button_by_data (GObject *dialog)
166 {
167 GtkEntry *entry;
168 GtkComboBoxText *combo;
169 const gchar *entry_text;
170 gchar *combo_text;
171
172 g_return_if_fail (dialog != NULL);
173
174 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
175 g_return_if_fail (entry != NULL);
176
177 combo = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
178 g_return_if_fail (combo != NULL);
179
180 entry_text = gtk_entry_get_text (entry);
181 combo_text = gtk_combo_box_text_get_active_text (combo);
182
183 gtk_dialog_set_response_sensitive (
184 GTK_DIALOG (dialog), GTK_RESPONSE_OK,
185 entry_text && *entry_text && *entry_text != ' ' && *entry_text != ',' &&
186 combo_text && *combo_text);
187
188 g_free (combo_text);
189 }
190
191 static void
192 name_entry_changed_cb (GObject *dialog)
193 {
194 GtkEntry *entry;
195
196 g_return_if_fail (dialog != NULL);
197
198 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
199 g_return_if_fail (entry != NULL);
200
201 g_object_set_data (G_OBJECT (entry), STR_MAPI_DIRECT_USER_NAME, NULL);
202
203 enable_ok_button_by_data (dialog);
204 }
205
206 static void
207 folder_name_combo_changed_cb (GObject *dialog,
208 GtkComboBox *combo)
209 {
210 enable_ok_button_by_data (dialog);
211 }
212
213 struct EMapiCheckForeignFolderData
214 {
215 GtkWidget *dialog;
216 gboolean include_subfolders;
217 gchar *username;
218 gchar *direct_username;
219 gchar *user_displayname;
220 gchar *orig_foldername;
221 gchar *use_foldername;
222 gchar *folder_displayname;
223 gchar *folder_container_class;
224 mapi_id_t folder_id;
225 mapi_id_t parent_folder_id;
226 };
227
228 static void
229 e_mapi_check_foreign_folder_data_free (gpointer ptr)
230 {
231 struct EMapiCheckForeignFolderData *cffd = ptr;
232
233 if (!cffd)
234 return;
235
236 g_free (cffd->username);
237 g_free (cffd->direct_username);
238 g_free (cffd->user_displayname);
239 g_free (cffd->orig_foldername);
240 g_free (cffd->use_foldername);
241 g_free (cffd->folder_displayname);
242 g_free (cffd->folder_container_class);
243
244 /* folder_id tells whether successfully finished,
245 then the dialog can be destroyed */
246 if (cffd->folder_id && cffd->dialog)
247 gtk_widget_destroy (cffd->dialog);
248
249 g_slice_free (struct EMapiCheckForeignFolderData, cffd);
250 }
251
252 static gboolean
253 check_foreign_username_resolved_cb (EMapiConnection *conn,
254 TALLOC_CTX *mem_ctx,
255 /* const */ struct mapi_SPropValue_array *properties,
256 gpointer user_data,
257 GCancellable *cancellable,
258 GError **perror)
259 {
260 struct EMapiCheckForeignFolderData *cffd = user_data;
261
262 g_return_val_if_fail (properties != NULL, FALSE);
263 g_return_val_if_fail (cffd != NULL, FALSE);
264 g_return_val_if_fail (cffd->user_displayname == NULL, FALSE);
265
266 cffd->user_displayname = g_strdup (e_mapi_util_find_array_propval (properties, PidTagDisplayName));
267
268 return TRUE;
269 }
270
271 static gboolean
272 foreign_folder_add_props_cb (EMapiConnection *conn,
273 TALLOC_CTX *mem_ctx,
274 struct SPropTagArray *props,
275 gpointer data,
276 GCancellable *cancellable,
277 GError **perror)
278 {
279 g_return_val_if_fail (mem_ctx != NULL, FALSE);
280 g_return_val_if_fail (props != NULL, FALSE);
281
282 SPropTagArray_add (mem_ctx, props, PidTagDisplayName);
283 SPropTagArray_add (mem_ctx, props, PidTagContainerClass);
284 SPropTagArray_add (mem_ctx, props, PidTagParentFolderId);
285
286 return TRUE;
287 }
288
289 static gboolean
290 foreign_folder_get_props_cb (EMapiConnection *conn,
291 TALLOC_CTX *mem_ctx,
292 /* const */ struct mapi_SPropValue_array *properties,
293 gpointer user_data,
294 GCancellable *cancellable,
295 GError **perror)
296 {
297 struct EMapiCheckForeignFolderData *cffd = user_data;
298 const mapi_id_t *pid;
299
300 g_return_val_if_fail (properties != NULL, FALSE);
301 g_return_val_if_fail (cffd != NULL, FALSE);
302 g_return_val_if_fail (cffd->folder_displayname == NULL, FALSE);
303 g_return_val_if_fail (cffd->folder_container_class == NULL, FALSE);
304
305 pid = e_mapi_util_find_array_propval (properties, PidTagParentFolderId);
306
307 cffd->folder_displayname = g_strdup (e_mapi_util_find_array_propval (properties, PidTagDisplayName));
308 cffd->folder_container_class = g_strdup (e_mapi_util_find_array_propval (properties, PidTagContainerClass));
309 cffd->parent_folder_id = pid ? *pid : 0;
310
311 if (!cffd->folder_container_class) {
312 /* Default to mail folder */
313 cffd->folder_container_class = g_strdup (IPF_NOTE);
314 }
315
316 return TRUE;
317 }
318
319 static void
320 check_foreign_folder_thread (GObject *with_object,
321 gpointer user_data,
322 GCancellable *cancellable,
323 GError **perror)
324 {
325 struct EMapiCheckForeignFolderData *cffd = user_data;
326 GError *local_error = NULL;
327 EMapiConnection *conn;
328 mapi_object_t obj_folder;
329 mapi_id_t fid = 0;
330
331 g_return_if_fail (with_object != NULL);
332 g_return_if_fail (CAMEL_IS_MAPI_STORE (with_object));
333 g_return_if_fail (user_data != NULL);
334 g_return_if_fail (cffd->username != NULL);
335
336 if (g_cancellable_set_error_if_cancelled (cancellable, perror))
337 return;
338
339 conn = camel_mapi_store_ref_connection (CAMEL_MAPI_STORE (with_object), cancellable, perror);
340 if (!conn || !e_mapi_connection_connected (conn)) {
341 if (conn)
342 g_object_unref (conn);
343 make_mapi_error (perror, "EMapiConnection", MAPI_E_NOT_INITIALIZED);
344 return;
345 }
346
347 if (cffd->direct_username && *cffd->direct_username) {
348 g_return_if_fail (cffd->user_displayname == NULL);
349
350 cffd->user_displayname = cffd->username;
351 cffd->username = g_strdup (cffd->direct_username);
352 } else {
353 if (!e_mapi_connection_resolve_username (conn, cffd->username,
354 NULL, NULL,
355 check_foreign_username_resolved_cb, cffd,
356 cancellable, perror)) {
357 g_object_unref (conn);
358 make_mapi_error (perror, "e_mapi_connection_resolve_username", MAPI_E_CALL_FAILED);
359 return;
360 }
361 }
362
363 if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
364 g_object_unref (conn);
365 return;
366 }
367
368 if (!e_mapi_connection_test_foreign_folder (conn, cffd->username,
369 cffd->use_foldername ? cffd->use_foldername : cffd->orig_foldername,
370 &fid, cancellable, &local_error)) {
371 if (g_error_matches (local_error, E_MAPI_ERROR, MAPI_E_NOT_FOUND)) {
372 g_clear_error (&local_error);
373 local_error = g_error_new (E_MAPI_ERROR, MAPI_E_NOT_FOUND,
374 _("Folder “%s” not found. Either it does not exist or you do not have permission to access it."),
375 cffd->orig_foldername);
376 }
377
378 g_object_unref (conn);
379 g_propagate_error (perror, local_error);
380 return;
381 }
382
383 if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
384 g_object_unref (conn);
385 return;
386 }
387
388 if (!e_mapi_connection_open_foreign_folder (conn, cffd->username, fid, &obj_folder, cancellable, perror)) {
389 g_object_unref (conn);
390 make_mapi_error (perror, "e_mapi_connection_open_foreign_folder", MAPI_E_CALL_FAILED);
391 return;
392 }
393
394 if (!e_mapi_connection_get_folder_properties (conn, &obj_folder,
395 foreign_folder_add_props_cb, NULL,
396 foreign_folder_get_props_cb, cffd,
397 cancellable, perror)) {
398 make_mapi_error (perror, "e_mapi_connection_get_folder_properties", MAPI_E_CALL_FAILED);
399
400 e_mapi_connection_close_folder (conn, &obj_folder, cancellable, perror);
401 g_object_unref (conn);
402 return;
403 }
404
405 e_mapi_connection_close_folder (conn, &obj_folder, cancellable, perror);
406 g_object_unref (conn);
407
408 if (!cffd->folder_container_class) {
409 g_propagate_error (perror, g_error_new_literal (E_MAPI_ERROR, MAPI_E_CALL_FAILED, _("Cannot add folder, cannot determine folder’s type")));
410 return;
411 }
412
413 cffd->folder_id = fid;
414 }
415
416 static void
417 check_foreign_folder_idle (GObject *with_object,
418 gpointer user_data,
419 GCancellable *cancellable,
420 GError **perror)
421 {
422 struct EMapiCheckForeignFolderData *cffd = user_data;
423 gchar *folder_name;
424 const gchar *base_username, *base_foldername;
425 CamelSettings *settings;
426 CamelMapiSettings *mapi_settings;
427 CamelMapiStore *mapi_store;
428 ESourceRegistry *registry = NULL;
429 CamelSession *session;
430 EMapiFolderType folder_type;
431 gchar *profile;
432
433 g_return_if_fail (with_object != NULL);
434 g_return_if_fail (CAMEL_IS_MAPI_STORE (with_object));
435 g_return_if_fail (user_data != NULL);
436 g_return_if_fail (cffd->username != NULL);
437 g_return_if_fail (cffd->folder_container_class != NULL);
438
439 if (!cffd->folder_id)
440 return;
441
442 base_username = cffd->user_displayname ? cffd->user_displayname : cffd->username;
443 base_foldername = cffd->folder_displayname ? cffd->folder_displayname : cffd->orig_foldername;
444
445 /* Translators: This is used to name foreign folder.
446 The first '%s' is replaced with user name to whom the folder belongs,
447 the second '%s' is replaced with folder name.
448 Example result: "John Smith — Calendar"
449 */
450 folder_name = g_strdup_printf (C_("ForeignFolder", "%s — %s"), base_username, base_foldername);
451
452 mapi_store = CAMEL_MAPI_STORE (with_object);
453
454 settings = camel_service_ref_settings (CAMEL_SERVICE (mapi_store));
455
456 mapi_settings = CAMEL_MAPI_SETTINGS (settings);
457 profile = camel_mapi_settings_dup_profile (mapi_settings);
458
459 g_object_unref (settings);
460
461 session = camel_service_ref_session (CAMEL_SERVICE (mapi_store));
462 if (E_IS_MAIL_SESSION (session))
463 registry = e_mail_session_get_registry (E_MAIL_SESSION (session));
464
465 folder_type = e_mapi_folder_type_from_string (cffd->folder_container_class);
466 if ((folder_type == E_MAPI_FOLDER_TYPE_MAIL &&
467 !add_foreign_folder_to_camel (mapi_store,
468 cffd->username,
469 cffd->folder_id,
470 cffd->parent_folder_id,
471 cffd->include_subfolders,
472 base_username,
473 base_foldername,
474 perror)) ||
475 (folder_type != E_MAPI_FOLDER_TYPE_MAIL && !e_mapi_folder_add_as_esource (registry, folder_type, profile,
476 TRUE /* camel_offline_settings_get_stay_synchronized (CAMEL_OFFLINE_SETTINGS (mapi_settings)) */,
477 E_MAPI_FOLDER_CATEGORY_FOREIGN,
478 cffd->username,
479 folder_name,
480 cffd->folder_id,
481 0,
482 cancellable,
483 perror))) {
484 /* to not destroy the dialog on error */
485 cffd->folder_id = 0;
486 }
487
488 g_object_unref (session);
489
490 g_free (folder_name);
491 g_free (profile);
492 }
493
494 static gpointer
495 ref_selected_store (GObject *dialog)
496 {
497 GtkComboBox *combo_box;
498 CamelStore *store = NULL;
499 GtkTreeIter iter;
500
501 combo_box = g_object_get_data (dialog, STR_ACCOUNTS_COMBO);
502 g_return_val_if_fail (combo_box != NULL, NULL);
503
504 if (gtk_combo_box_get_active_iter (combo_box, &iter)) {
505 gtk_tree_model_get (gtk_combo_box_get_model (combo_box), &iter,
506 COLUMN_STORE, &store, -1);
507 }
508
509 return store;
510 }
511
512 static void
513 subscribe_foreign_response_cb (GObject *dialog,
514 gint response_id)
515 {
516 struct EMapiCheckForeignFolderData *cffd;
517 ENameSelectorEntry *entry;
518 GtkComboBoxText *combo_text;
519 GtkToggleButton *subfolders_check;
520 EDestinationStore *dest_store;
521 CamelStore *cstore;
522 gchar *description;
523 const gchar *username;
524 gchar *orig_foldername, *use_foldername = NULL;
525
526 if (response_id != GTK_RESPONSE_OK) {
527 gtk_widget_destroy (GTK_WIDGET (dialog));
528 return;
529 }
530
531 g_return_if_fail (dialog != NULL);
532
533 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
534 combo_text = g_object_get_data (dialog, STR_FOLDER_NAME_COMBO);
535 subfolders_check = g_object_get_data (dialog, STR_SUBFOLDERS_CHECK);
536
537 g_return_if_fail (entry != NULL);
538
539 cstore = ref_selected_store (dialog);
540 g_return_if_fail (cstore != NULL);
541
542 username = NULL;
543 dest_store = e_name_selector_entry_peek_destination_store (entry);
544 if (dest_store && e_destination_store_get_destination_count (dest_store) > 0) {
545 EDestination *dest;
546 GList *dests = e_destination_store_list_destinations (dest_store);
547
548 g_return_if_fail (dests != NULL);
549
550 /* pick the first, there is no option to limit to only one destination */
551 dest = dests->data;
552 if (dest) {
553 username = e_destination_get_email (dest);
554 if (!username || !*username)
555 username = e_destination_get_name (dest);
556 }
557
558 g_list_free (dests);
559 }
560
561 if (!username || !*username)
562 username = gtk_entry_get_text (GTK_ENTRY (entry));
563
564 orig_foldername = gtk_combo_box_text_get_active_text (combo_text);
565 if (!orig_foldername)
566 orig_foldername = g_strdup ("");
567
568 /* convert well-known names to their non-localized form */
569 if (g_strcmp0 (orig_foldername, _("Inbox")) == 0) {
570 use_foldername = g_strdup ("Inbox");
571 } else if (g_strcmp0 (orig_foldername, _("Contacts")) == 0) {
572 use_foldername = g_strdup ("Contacts");
573 } else if (g_strcmp0 (orig_foldername, _("Calendar")) == 0) {
574 use_foldername = g_strdup ("Calendar");
575 } else if (g_strcmp0 (orig_foldername, _("Memos")) == 0) {
576 use_foldername = g_strdup ("Notes");
577 } else if (g_strcmp0 (orig_foldername, _("Tasks")) == 0) {
578 use_foldername = g_strdup ("Tasks");
579 }
580
581 cffd = g_slice_new0 (struct EMapiCheckForeignFolderData);
582 cffd->dialog = GTK_WIDGET (dialog);
583 cffd->username = g_strdup (username ? username : "");
584 cffd->direct_username = g_strdup (g_object_get_data (G_OBJECT (entry), STR_MAPI_DIRECT_USER_NAME));
585 cffd->orig_foldername = orig_foldername;
586 cffd->use_foldername = use_foldername;
587 cffd->folder_id = 0;
588 cffd->parent_folder_id = 0;
589 cffd->include_subfolders = gtk_toggle_button_get_active (subfolders_check);
590
591 description = g_strdup_printf (_("Testing availability of folder “%s” of user “%s”, please wait…"), cffd->orig_foldername, cffd->username);
592
593 e_mapi_config_utils_run_in_thread_with_feedback (
594 GTK_WINDOW (dialog),
595 G_OBJECT (cstore),
596 description,
597 check_foreign_folder_thread,
598 check_foreign_folder_idle,
599 cffd,
600 e_mapi_check_foreign_folder_data_free);
601
602 g_free (description);
603 g_object_unref (cstore);
604 }
605
606 static void
607 pick_gal_user_clicked_cb (GtkButton *button,
608 GObject *dialog)
609 {
610 GtkEntry *entry;
611 CamelMapiStore *mapi_store;
612 EMapiConnection *conn;
613 gchar *text, *display_name = NULL, *dn = NULL;
614 EMapiGalUserType searched_type = E_MAPI_GAL_USER_NONE;
615
616 g_return_if_fail (dialog != NULL);
617
618 entry = g_object_get_data (dialog, STR_USER_NAME_SELECTOR_ENTRY);
619
620 g_return_if_fail (entry != NULL);
621
622 mapi_store = ref_selected_store (dialog);
623 g_return_if_fail (mapi_store != NULL);
624
625 text = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
626
627 conn = camel_mapi_store_ref_connection (mapi_store, NULL, NULL);
628 if (!conn) {
629 e_notice (dialog, GTK_MESSAGE_ERROR, "%s", _("Cannot search for user when the account is offline"));
630 } else if (e_mapi_search_gal_user_modal (GTK_WINDOW (dialog),
631 conn,
632 text,
633 &searched_type,
634 &display_name,
635 NULL,
636 &dn,
637 NULL)) {
638 if (searched_type == E_MAPI_GAL_USER_REGULAR &&
639 display_name && dn && *dn && strchr (dn, '=')) {
640 gtk_entry_set_text (entry, display_name);
641 g_object_set_data_full (G_OBJECT (entry), STR_MAPI_DIRECT_USER_NAME, g_strdup (strrchr (dn, '=') + 1), g_free);
642 }
643 }
644
645 g_object_unref (mapi_store);
646 g_clear_object (&conn);
647 g_free (text);
648 g_free (display_name);
649 g_free (dn);
650 }
651
652 static gint
653 sort_accounts_by_display_name_cb (gconstpointer ptr1,
654 gconstpointer ptr2)
655 {
656 CamelService *service1 = (CamelService *) ptr1;
657 CamelService *service2 = (CamelService *) ptr2;
658
659 return g_utf8_collate (camel_service_get_display_name (service1), camel_service_get_display_name (service2));
660 }
661
662 static GtkWidget *
663 create_accounts_combo (CamelSession *session,
664 EClientCache *client_cache,
665 CamelStore *store)
666 {
667 GtkListStore *list_store;
668 GtkTreeIter iter;
669 GtkComboBox *combo_box;
670 ESourceRegistry *registry;
671 GList *services, *link, *accounts = NULL;
672 GtkCellRenderer *renderer;
673
674 list_store = gtk_list_store_new (3,
675 G_TYPE_STRING, /* COLUMN_UID - UID of the CamelMAPIStore */
676 G_TYPE_STRING, /* COLUMN_DISPLAY_NAME */
677 CAMEL_TYPE_MAPI_STORE); /* COLUMN_STORE */
678
679 registry = e_client_cache_ref_registry (client_cache);
680 services = camel_session_list_services (session);
681
682 for (link = services; link; link = g_list_next (link)) {
683 CamelService *service = link->data;
684
685 if (CAMEL_IS_MAPI_STORE (service)) {
686 ESource *source;
687
688 source = e_source_registry_ref_source (registry, camel_service_get_uid (service));
689 if (source && e_source_registry_check_enabled (registry, source)) {
690 accounts = g_list_prepend (accounts, service);
691 }
692
693 g_clear_object (&source);
694 }
695 }
696
697 accounts = g_list_sort (accounts, sort_accounts_by_display_name_cb);
698
699 for (link = accounts; link; link = g_list_next (link)) {
700 CamelService *service = link->data;
701
702 gtk_list_store_append (list_store, &iter);
703 gtk_list_store_set (list_store, &iter,
704 COLUMN_UID, camel_service_get_uid (service),
705 COLUMN_DISPLAY_NAME, camel_service_get_display_name (service),
706 COLUMN_STORE, service,
707 -1);
708 }
709
710 g_list_free_full (services, g_object_unref);
711 g_list_free (accounts);
712 g_clear_object (®istry);
713
714 combo_box = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store)));
715 g_object_unref (list_store);
716
717 renderer = gtk_cell_renderer_text_new ();
718 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
719 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "text", COLUMN_DISPLAY_NAME, NULL);
720
721 gtk_combo_box_set_id_column (combo_box, COLUMN_UID);
722 if (store)
723 gtk_combo_box_set_active_id (combo_box, camel_service_get_uid (CAMEL_SERVICE (store)));
724 else if (accounts)
725 gtk_combo_box_set_active (combo_box, 0);
726
727 return GTK_WIDGET (combo_box);
728 }
729
730 /* Opens dialog to subscribe to folders of other
731 users in the given store */
732 void
733 e_mapi_subscribe_foreign_folder (GtkWindow *parent,
734 CamelSession *session,
735 CamelStore *store,
736 EClientCache *client_cache)
737 {
738 ENameSelector *name_selector;
739 ENameSelectorModel *name_selector_model;
740 ENameSelectorDialog *name_selector_dialog;
741 GObject *dialog;
742 GtkWidget *content;
743 GtkWidget *label, *widget, *entry, *check, *accounts_combo;
744 GtkGrid *grid;
745 GtkComboBoxText *combo_text;
746 gint row;
747
748 g_return_if_fail (session != NULL);
749 if (store)
750 g_return_if_fail (CAMEL_IS_MAPI_STORE (store));
751
752 dialog = G_OBJECT (gtk_dialog_new_with_buttons (
753 _("Subscribe to folder of other MAPI user…"),
754 parent,
755 GTK_DIALOG_DESTROY_WITH_PARENT,
756 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
757 GTK_STOCK_OK, GTK_RESPONSE_OK,
758 NULL));
759
760 g_signal_connect (dialog, "response", G_CALLBACK (subscribe_foreign_response_cb), NULL);
761
762 content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
763
764 grid = GTK_GRID (gtk_grid_new ());
765 gtk_grid_set_row_homogeneous (grid, FALSE);
766 gtk_grid_set_row_spacing (grid, 6);
767 gtk_grid_set_column_homogeneous (grid, FALSE);
768 gtk_grid_set_column_spacing (grid, 6);
769 gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
770 gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
771
772 row = 0;
773
774 label = gtk_label_new (_("Account:"));
775 g_object_set (G_OBJECT (label),
776 "hexpand", FALSE,
777 "vexpand", FALSE,
778 "xalign", 0.0,
779 "halign", GTK_ALIGN_START,
780 NULL);
781
782 widget = create_accounts_combo (session, client_cache, store);
783 g_object_set (G_OBJECT (widget),
784 "hexpand", TRUE,
785 "vexpand", FALSE,
786 "halign", GTK_ALIGN_START,
787 NULL);
788 accounts_combo = widget;
789
790 gtk_grid_attach (grid, label, 0, row, 1, 1);
791 gtk_grid_attach (grid, widget, 1, row, 2, 1);
792
793 row++;
794
795 name_selector = e_name_selector_new (client_cache);
796 name_selector_model = e_name_selector_peek_model (name_selector);
797 e_name_selector_model_add_section (name_selector_model, "User", _("User"), NULL);
798 name_selector_dialog = e_name_selector_peek_dialog (name_selector);
799 g_signal_connect (name_selector_dialog, "response", G_CALLBACK (gtk_widget_hide), name_selector);
800 e_name_selector_load_books (name_selector);
801
802 g_object_set_data_full (dialog, "e-mapi-name-selector", name_selector, g_object_unref);
803
804 label = gtk_label_new_with_mnemonic (_("_User:"));
805 g_object_set (G_OBJECT (label),
806 "hexpand", FALSE,
807 "vexpand", FALSE,
808 "xalign", 0.0,
809 NULL);
810
811 entry = GTK_WIDGET (e_name_selector_peek_section_entry (name_selector, "User"));
812 g_object_set (G_OBJECT (entry),
813 "hexpand", TRUE,
814 "vexpand", FALSE,
815 NULL);
816
817 widget = gtk_button_new_with_mnemonic (_("C_hoose…"));
818 g_object_set (G_OBJECT (entry),
819 "hexpand", TRUE,
820 "vexpand", FALSE,
821 NULL);
822
823 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
824 g_signal_connect (widget, "clicked", G_CALLBACK (pick_gal_user_clicked_cb), dialog);
825
826 gtk_grid_attach (grid, label, 0, row, 1, 1);
827 gtk_grid_attach (grid, entry, 1, row, 1, 1);
828 gtk_grid_attach (grid, widget, 2, row, 1, 1);
829
830 row++;
831
832 label = gtk_label_new_with_mnemonic (_("_Folder name:"));
833 g_object_set (G_OBJECT (label),
834 "hexpand", FALSE,
835 "vexpand", FALSE,
836 "xalign", 0.0,
837 NULL);
838
839 widget = GTK_WIDGET (g_object_new (gtk_combo_box_text_get_type (),
840 "has-entry", TRUE,
841 "entry-text-column", 0,
842 "hexpand", TRUE,
843 "vexpand", FALSE,
844 NULL));
845
846 combo_text = GTK_COMBO_BOX_TEXT (widget);
847 gtk_combo_box_text_append_text (combo_text, _("Inbox"));
848 gtk_combo_box_text_append_text (combo_text, _("Contacts"));
849 gtk_combo_box_text_append_text (combo_text, _("Calendar"));
850 gtk_combo_box_text_append_text (combo_text, _("Memos"));
851 gtk_combo_box_text_append_text (combo_text, _("Tasks"));
852 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_text), 0);
853
854 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
855 gtk_grid_attach (grid, label, 0, row, 1, 1);
856 gtk_grid_attach (grid, widget, 1, row, 2, 1);
857
858 row++;
859
860 check = gtk_check_button_new_with_mnemonic (_("Include _subfolders"));
861 gtk_grid_attach (grid, check, 1, row, 2, 1);
862
863 /* remember widgets for later use */
864 g_object_set_data (dialog, STR_ACCOUNTS_COMBO, accounts_combo);
865 g_object_set_data (dialog, STR_USER_NAME_SELECTOR_ENTRY, entry);
866 g_object_set_data (dialog, STR_FOLDER_NAME_COMBO, widget);
867 g_object_set_data (dialog, STR_SUBFOLDERS_CHECK, check);
868
869 g_object_set_data_full (dialog, STR_MAPI_CAMEL_SESSION, g_object_ref (session), g_object_unref);
870
871 g_signal_connect_swapped (entry, "changed", G_CALLBACK (name_entry_changed_cb), dialog);
872 g_signal_connect_swapped (combo_text, "changed", G_CALLBACK (folder_name_combo_changed_cb), dialog);
873 g_signal_connect_swapped (accounts_combo, "changed", G_CALLBACK (name_entry_changed_cb), dialog);
874
875 name_entry_changed_cb (dialog);
876
877 gtk_widget_show_all (content);
878 gtk_widget_show (GTK_WIDGET (dialog));
879 }