1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
/* Copyright (C) 2002-2004 Novell, Inc.
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of version 2 of the GNU Lesser General Public
7
* License as published by the Free Software Foundation.
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
* General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this program; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
20
/* ExchangeHierarchyForeign: class for a hierarchy consisting of a
21
* selected subset of folders from another user's mailbox.
28
#include "exchange-hierarchy-foreign.h"
29
#include "exchange-account.h"
30
#include "e-folder-exchange.h"
31
#include "e2k-propnames.h"
33
#include "e2k-utils.h"
34
#include "exchange-esource.h"
35
#include "exchange-types.h"
36
#include "e2k-types.h"
38
#include <libedataserver/e-xml-hash-utils.h>
39
#include <libedataserver/e-source-list.h>
45
struct _ExchangeHierarchyForeignPrivate {
46
GMutex *hide_private_lock;
47
gboolean checked_hide_private;
50
extern const char *exchange_localfreebusy_path;
52
#define PARENT_TYPE EXCHANGE_TYPE_HIERARCHY_SOMEDAV
53
static ExchangeHierarchySomeDAVClass *parent_class = NULL;
55
static GPtrArray *get_hrefs (ExchangeHierarchySomeDAV *hsd);
56
static ExchangeAccountFolderResult create_folder (ExchangeHierarchy *hier,
60
static ExchangeAccountFolderResult remove_folder (ExchangeHierarchy *hier,
62
static ExchangeAccountFolderResult scan_subtree (ExchangeHierarchy *hier,
65
static void finalize (GObject *object);
68
class_init (GObjectClass *object_class)
70
ExchangeHierarchyClass *hierarchy_class =
71
EXCHANGE_HIERARCHY_CLASS (object_class);
72
ExchangeHierarchySomeDAVClass *somedav_class =
73
EXCHANGE_HIERARCHY_SOMEDAV_CLASS (object_class);
75
parent_class = g_type_class_ref (PARENT_TYPE);
77
/* virtual method override */
78
object_class->finalize = finalize;
80
hierarchy_class->create_folder = create_folder;
81
hierarchy_class->remove_folder = remove_folder;
82
hierarchy_class->scan_subtree = scan_subtree;
84
somedav_class->get_hrefs = get_hrefs;
88
init (GObject *object)
90
ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (object);
91
ExchangeHierarchy *hier = EXCHANGE_HIERARCHY (object);
93
hfor->priv = g_new0 (ExchangeHierarchyForeignPrivate, 1);
94
hfor->priv->hide_private_lock = g_mutex_new ();
95
hier->hide_private_items = TRUE;
99
finalize (GObject *object)
101
ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (object);
103
g_mutex_free (hfor->priv->hide_private_lock);
106
G_OBJECT_CLASS (parent_class)->finalize (object);
109
E2K_MAKE_TYPE (exchange_hierarchy_foreign, ExchangeHierarchyForeign, class_init, init, PARENT_TYPE)
111
static const char *privacy_props[] = {
112
PR_DELEGATES_ENTRYIDS,
113
PR_DELEGATES_SEE_PRIVATE,
115
static const int n_privacy_props = sizeof (privacy_props) / sizeof (privacy_props[0]);
118
check_hide_private (ExchangeHierarchy *hier)
120
ExchangeHierarchyForeign *hfor = EXCHANGE_HIERARCHY_FOREIGN (hier);
122
E2kHTTPStatus status;
125
GPtrArray *entryids, *privflags;
127
const char *my_dn, *delegate_dn;
130
g_mutex_lock (hfor->priv->hide_private_lock);
132
if (hfor->priv->checked_hide_private) {
133
g_mutex_unlock (hfor->priv->hide_private_lock);
137
uri = e2k_uri_concat (hier->account->home_uri,
138
"NON_IPM_SUBTREE/Freebusy%20Data/LocalFreebusy.EML");
139
ctx = exchange_account_get_context (hier->account);
141
status = e2k_context_propfind (ctx, NULL, uri,
142
privacy_props, n_privacy_props,
143
&results, &nresults);
146
hfor->priv->checked_hide_private = TRUE;
148
if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status) || nresults == 0) {
149
g_mutex_unlock (hfor->priv->hide_private_lock);
152
if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (results[0].status) ||
153
!results[0].props || nresults > 1) {
154
e2k_results_free (results, nresults);
155
g_mutex_unlock (hfor->priv->hide_private_lock);
159
entryids = e2k_properties_get_prop (results[0].props,
160
PR_DELEGATES_ENTRYIDS);
161
privflags = e2k_properties_get_prop (results[0].props,
162
PR_DELEGATES_SEE_PRIVATE);
163
if (entryids && privflags) {
164
my_dn = hier->account->legacy_exchange_dn;
165
for (i = 0; i < entryids->len && i < privflags->len; i++) {
166
entryid = entryids->pdata[i];
167
delegate_dn = e2k_entryid_to_dn (entryid);
170
!g_ascii_strcasecmp (delegate_dn, my_dn) &&
171
privflags->pdata[i] &&
172
atoi (privflags->pdata[i]))
173
hier->hide_private_items = FALSE;
178
e2k_results_free (results, nresults);
179
g_mutex_unlock (hfor->priv->hide_private_lock);
183
remove_all_cb (ExchangeHierarchy *hier, EFolder *folder, gpointer user_data)
185
exchange_hierarchy_removed_folder (hier, folder);
189
hierarchy_foreign_cleanup (ExchangeHierarchy *hier)
193
exchange_hierarchy_webdav_offline_scan_subtree (hier, remove_all_cb,
196
mf_path = e_folder_exchange_get_storage_file (hier->toplevel, "hierarchy.xml");
200
exchange_hierarchy_removed_folder (hier, hier->toplevel);
203
static const char *folder_props[] = {
204
E2K_PR_EXCHANGE_FOLDER_CLASS,
205
E2K_PR_HTTPMAIL_UNREAD_COUNT,
206
E2K_PR_DAV_DISPLAY_NAME,
209
static const int n_folder_props = sizeof (folder_props) / sizeof (folder_props[0]);
211
static ExchangeAccountFolderResult
212
find_folder (ExchangeHierarchy *hier, const char *uri, EFolder **folder_out)
214
ExchangeHierarchyWebDAV *hwd = EXCHANGE_HIERARCHY_WEBDAV (hier);
215
E2kContext *ctx = exchange_account_get_context (hier->account);
216
E2kHTTPStatus status;
223
status = e2k_context_propfind (ctx, NULL, uri,
224
folder_props, n_folder_props,
225
&results, &nresults);
226
if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
227
return exchange_hierarchy_webdav_status_to_folder_result (status);
229
return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
231
access = e2k_properties_get_prop (results[0].props, PR_ACCESS);
232
if (!access || !atoi (access))
233
return EXCHANGE_ACCOUNT_FOLDER_PERMISSION_DENIED;
235
folder = exchange_hierarchy_webdav_parse_folder (hwd, hier->toplevel,
237
e2k_results_free (results, nresults);
240
return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
242
exchange_hierarchy_new_folder (hier, folder);
245
*folder_out = folder;
247
g_object_unref (folder);
248
return EXCHANGE_ACCOUNT_FOLDER_OK;
252
const char *name, *prop;
254
{ N_("Calendar"), E2K_PR_STD_FOLDER_CALENDAR },
255
{ N_("Contacts"), E2K_PR_STD_FOLDER_CONTACTS },
256
{ N_("Deleted Items"), E2K_PR_STD_FOLDER_DELETED_ITEMS },
257
{ N_("Drafts"), E2K_PR_STD_FOLDER_DRAFTS },
258
{ N_("Inbox"), E2K_PR_STD_FOLDER_INBOX },
259
{ N_("Journal"), E2K_PR_STD_FOLDER_JOURNAL },
260
{ N_("Notes"), E2K_PR_STD_FOLDER_NOTES },
261
{ N_("Outbox"), E2K_PR_STD_FOLDER_OUTBOX },
262
{ N_("Sent Items"), E2K_PR_STD_FOLDER_SENT_ITEMS },
263
{ N_("Tasks"), E2K_PR_STD_FOLDER_TASKS }
265
const static int n_std_folders = sizeof (std_folders) / sizeof (std_folders[0]);
266
static ExchangeAccountFolderResult
267
create_internal (ExchangeHierarchy *hier, EFolder *parent,
268
const char *name, const char *type, EFolder **folder_out)
270
ExchangeAccountFolderResult result;
271
char *literal_uri = NULL, *standard_uri = NULL;
272
const char *home_uri;
276
/* For now, no nesting */
277
if (parent != hier->toplevel || strchr (name + 1, '/'))
278
return EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR;
280
check_hide_private (hier);
282
home_uri = e_folder_exchange_get_internal_uri (hier->toplevel);
283
literal_uri = e2k_uri_concat (home_uri, name);
284
if (exchange_account_get_folder (hier->account, literal_uri)) {
285
g_free (literal_uri);
286
if (exchange_hierarchy_is_empty (hier))
287
hierarchy_foreign_cleanup (hier);
288
return EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS;
291
for (i = 0; i < n_std_folders; i++) {
292
if (g_ascii_strcasecmp (std_folders[i].name, name) != 0 &&
293
g_utf8_collate (_(std_folders[i].name), name) != 0)
296
standard_uri = exchange_account_get_standard_uri_for (
297
hier->account, home_uri, std_folders[i].prop);
300
if (!strcmp (literal_uri, standard_uri)) {
301
g_free (standard_uri);
306
if (exchange_account_get_folder (hier->account, standard_uri)) {
307
g_free (standard_uri);
308
g_free (literal_uri);
309
if (exchange_hierarchy_is_empty (hier))
310
hierarchy_foreign_cleanup (hier);
311
return EXCHANGE_ACCOUNT_FOLDER_ALREADY_EXISTS;
317
result = find_folder (hier, literal_uri, folder_out);
318
if (result == EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST && standard_uri)
319
result = find_folder (hier, standard_uri, folder_out);
321
g_free (literal_uri);
322
g_free (standard_uri);
324
/* If the hierarchy is now empty, then we must have just been
325
* created but then the add failed. So remove it again.
327
if (exchange_hierarchy_is_empty (hier))
328
hierarchy_foreign_cleanup (hier);
334
static ExchangeAccountFolderResult
335
create_folder (ExchangeHierarchy *hier, EFolder *parent,
336
const char *name, const char *type)
338
return create_internal (hier, parent, name, type, NULL);
341
static ExchangeAccountFolderResult
342
remove_folder (ExchangeHierarchy *hier, EFolder *folder)
344
const char *folder_type, *physical_uri;
346
/* Temp Fix for remove fav folders. see #59168 */
347
/* remove ESources */
348
folder_type = e_folder_get_type_string (folder);
349
physical_uri = e_folder_get_physical_uri (folder);
351
if (strcmp (folder_type, "calendar") == 0) {
352
remove_folder_esource (hier->account,
353
EXCHANGE_CALENDAR_FOLDER,
356
else if (strcmp (folder_type, "tasks") == 0) {
357
remove_folder_esource (hier->account,
358
EXCHANGE_TASKS_FOLDER,
361
else if (strcmp (folder_type, "contacts") == 0) {
362
remove_folder_esource (hier->account,
363
EXCHANGE_CONTACTS_FOLDER,
366
if (folder != hier->toplevel)
367
exchange_hierarchy_removed_folder (hier, folder);
369
if (folder == hier->toplevel || exchange_hierarchy_is_empty (hier))
370
hierarchy_foreign_cleanup (hier);
372
return EXCHANGE_ACCOUNT_FOLDER_OK;
375
static ExchangeAccountFolderResult
376
scan_subtree (ExchangeHierarchy *hier, EFolder *folder, gboolean offline)
378
ExchangeAccountFolderResult folder_result;
380
check_hide_private (hier);
382
folder_result = EXCHANGE_HIERARCHY_CLASS (parent_class)->scan_subtree (hier, folder, offline);
384
if (exchange_hierarchy_is_empty (hier))
385
hierarchy_foreign_cleanup (hier);
387
return folder_result;
391
add_href (ExchangeHierarchy *hier, EFolder *folder, gpointer hrefs)
393
char *uri = g_strdup (e_folder_exchange_get_internal_uri (folder));
395
g_ptr_array_add (hrefs, (gpointer) uri);
399
get_hrefs (ExchangeHierarchySomeDAV *hsd)
403
hrefs = g_ptr_array_new ();
404
exchange_hierarchy_webdav_offline_scan_subtree (EXCHANGE_HIERARCHY (hsd), add_href, hrefs);
409
* exchange_hierarchy_foreign_add_folder:
410
* @hier: the hierarchy
411
* @folder_name: the name of the folder to add
412
* @folder: on successful return, the created folder
414
* Adds a new folder to @hier.
416
* Return value: the folder result.
418
ExchangeAccountFolderResult
419
exchange_hierarchy_foreign_add_folder (ExchangeHierarchy *hier,
420
const char *folder_name,
423
ExchangeAccountFolderResult result;
424
const char *folder_type = NULL;
425
const char *physical_uri = NULL;
426
char *new_folder_name;
428
result = create_internal (hier, hier->toplevel, folder_name, NULL, folder);
429
if (result == EXCHANGE_ACCOUNT_FOLDER_OK) {
430
/* Add the esources */
431
folder_type = e_folder_get_type_string (*folder);
432
physical_uri = e_folder_get_physical_uri (*folder);
433
new_folder_name = g_strdup_printf("%s's %s",
434
hier->owner_name, folder_name);
436
if (!(strcmp (folder_type, "calendar")) ||
437
!(strcmp (folder_type, "calendar/public"))) {
438
add_folder_esource (hier->account,
439
EXCHANGE_CALENDAR_FOLDER,
443
else if (!(strcmp (folder_type, "tasks")) ||
444
!(strcmp (folder_type, "tasks/public"))) {
445
add_folder_esource (hier->account,
446
EXCHANGE_TASKS_FOLDER,
450
else if (!(strcmp (folder_type, "contacts")) ||
451
!(strcmp (folder_type, "contacts/public")) ||
452
!(strcmp (folder_type, "contacts/ldap"))) {
453
add_folder_esource (hier->account,
454
EXCHANGE_CONTACTS_FOLDER,
458
g_free (new_folder_name);
463
static ExchangeHierarchy *
464
hierarchy_foreign_new (ExchangeAccount *account,
465
const char *hierarchy_name,
466
const char *physical_uri_prefix,
467
const char *internal_uri_prefix,
468
const char *owner_name,
469
const char *owner_email,
470
const char *source_uri)
472
ExchangeHierarchyForeign *hfor;
474
g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
476
hfor = g_object_new (EXCHANGE_TYPE_HIERARCHY_FOREIGN, NULL);
478
exchange_hierarchy_webdav_construct (EXCHANGE_HIERARCHY_WEBDAV (hfor),
480
EXCHANGE_HIERARCHY_FOREIGN,
484
owner_name, owner_email,
488
return EXCHANGE_HIERARCHY (hfor);
492
* exchange_hierarchy_foreign_new:
493
* @account: an #ExchangeAccount
494
* @hierarchy_name: the name of the hierarchy
495
* @physical_uri_prefix: the prefix of physical URIs in this hierarchy
496
* @internal_uri_prefix: the prefix of internal (http) URIs in this hierarchy
497
* @owner_name: display name of the owner of the hierarchy
498
* @owner_email: email address of the owner of the hierarchy
499
* @source_uri: evolution-mail source uri for the hierarchy
501
* Creates a new (initially empty) hierarchy for another user's
504
* Return value: the new hierarchy.
507
exchange_hierarchy_foreign_new (ExchangeAccount *account,
508
const char *hierarchy_name,
509
const char *physical_uri_prefix,
510
const char *internal_uri_prefix,
511
const char *owner_name,
512
const char *owner_email,
513
const char *source_uri)
515
ExchangeHierarchy *hier;
520
g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
522
hier = hierarchy_foreign_new (account, hierarchy_name,
525
owner_name, owner_email,
528
props = g_hash_table_new (g_str_hash, g_str_equal);
529
g_hash_table_insert (props, "name", (char *)hierarchy_name);
530
g_hash_table_insert (props, "physical_uri_prefix",
531
(char *)physical_uri_prefix);
532
g_hash_table_insert (props, "internal_uri_prefix",
533
(char *)internal_uri_prefix);
534
g_hash_table_insert (props, "owner_name", (char *)owner_name);
535
g_hash_table_insert (props, "owner_email", (char *)owner_email);
536
g_hash_table_insert (props, "source_uri", (char *)source_uri);
538
mf_path = e_folder_exchange_get_storage_file (hier->toplevel, "hierarchy.xml");
539
doc = e_xml_from_hash (props, E_XML_HASH_TYPE_PROPERTY,
540
"foreign-hierarchy");
541
xmlSaveFile (mf_path, doc);
542
g_hash_table_destroy (props);
550
* exchange_hierarchy_foreign_new_from_dir:
551
* @account: an #ExchangeAccount
552
* @folder_path: pathname to a directory containing a hierarchy.xml file
554
* Recreates a new hierarchy from saved values.
556
* Return value: the new hierarchy.
559
exchange_hierarchy_foreign_new_from_dir (ExchangeAccount *account,
560
const char *folder_path)
562
ExchangeHierarchy *hier;
567
g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
568
g_return_val_if_fail (folder_path != NULL, NULL);
570
mf_path = g_build_filename (folder_path, "hierarchy.xml", NULL);
571
doc = xmlParseFile (mf_path);
576
props = e_xml_to_hash (doc, E_XML_HASH_TYPE_PROPERTY);
579
hier = hierarchy_foreign_new (account,
580
g_hash_table_lookup (props, "name"),
581
g_hash_table_lookup (props, "physical_uri_prefix"),
582
g_hash_table_lookup (props, "internal_uri_prefix"),
583
g_hash_table_lookup (props, "owner_name"),
584
g_hash_table_lookup (props, "owner_email"),
585
g_hash_table_lookup (props, "source_uri"));
587
e_xml_destroy_hash (props);