~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/exchange/storage/e-folder-exchange.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
 
3
 
/* Copyright (C) 2002-2004 Novell, Inc.
4
 
 *
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.
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
 
 * General Public License for more details.
13
 
 *
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., 51 Franklin Street, Fifth Floor,
17
 
 * Boston, MA 02110-1301, USA.
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include <config.h>
22
 
#endif
23
 
 
24
 
#include <stdlib.h>
25
 
#include <stdio.h>
26
 
#include <string.h>
27
 
#include <unistd.h>
28
 
#include <sys/stat.h>
29
 
#include <sys/types.h>
30
 
 
31
 
#include <libxml/parser.h>
32
 
#include <libxml/tree.h>
33
 
#include <libxml/xmlmemory.h>
34
 
 
35
 
#include <glib.h>
36
 
#include <glib/gstdio.h>
37
 
 
38
 
#include "libedataserver/e-source-list.h"
39
 
#include "libedataserver/e-data-server-util.h"
40
 
#include "libedataserver/e-xml-utils.h"
41
 
 
42
 
#include "e-folder-exchange.h"
43
 
#include "e2k-path.h"
44
 
#include "e2k-uri.h"
45
 
#include "exchange-account.h"
46
 
#include "exchange-esource.h"
47
 
#include "exchange-hierarchy.h"
48
 
 
49
 
#define d(x)
50
 
 
51
 
struct _EFolderExchangePrivate {
52
 
        ExchangeHierarchy *hier;
53
 
        gchar *internal_uri, *permanent_uri;
54
 
        gchar *outlook_class, *storage_dir;
55
 
        gchar *path;
56
 
        gint64 folder_size;
57
 
        gboolean has_subfolders;
58
 
        gboolean rescan_tree;
59
 
};
60
 
 
61
 
#define PARENT_TYPE E_TYPE_FOLDER
62
 
static EFolderClass *parent_class = NULL;
63
 
 
64
 
#define EF_CLASS(hier) (E_FOLDER_CLASS (G_OBJECT_GET_CLASS (hier)))
65
 
 
66
 
static void dispose (GObject *object);
67
 
static void finalize (GObject *object);
68
 
 
69
 
static void
70
 
class_init (GObjectClass *object_class)
71
 
{
72
 
        parent_class = g_type_class_ref (PARENT_TYPE);
73
 
 
74
 
        /* methods */
75
 
        object_class->dispose = dispose;
76
 
        object_class->finalize = finalize;
77
 
}
78
 
 
79
 
static void
80
 
init (GObject *object)
81
 
{
82
 
        EFolderExchange *folder = E_FOLDER_EXCHANGE (object);
83
 
 
84
 
        folder->priv = g_new0 (EFolderExchangePrivate, 1);
85
 
        folder->priv->rescan_tree = TRUE;
86
 
}
87
 
 
88
 
static void
89
 
dispose (GObject *object)
90
 
{
91
 
        EFolderExchange *folder = E_FOLDER_EXCHANGE (object);
92
 
 
93
 
        if (folder->priv->hier) {
94
 
                g_object_unref (folder->priv->hier);
95
 
                folder->priv->hier = NULL;
96
 
        }
97
 
 
98
 
        G_OBJECT_CLASS (parent_class)->dispose (object);
99
 
}
100
 
 
101
 
static void
102
 
finalize (GObject *object)
103
 
{
104
 
        EFolderExchange *folder = E_FOLDER_EXCHANGE (object);
105
 
 
106
 
        g_free (folder->priv->internal_uri);
107
 
        g_free (folder->priv->permanent_uri);
108
 
        g_free (folder->priv->outlook_class);
109
 
        g_free (folder->priv->storage_dir);
110
 
        g_free (folder->priv->path);
111
 
        g_free (folder->priv);
112
 
 
113
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
114
 
}
115
 
 
116
 
E2K_MAKE_TYPE (e_folder_exchange, EFolderExchange, class_init, init, PARENT_TYPE)
117
 
 
118
 
static gchar *
119
 
sanitize_path (const gchar *path)
120
 
{
121
 
        gchar **comps;
122
 
        gchar *new_path = NULL;
123
 
 
124
 
        if (!path)
125
 
                return g_strdup("");    /* ??? or NULL? */
126
 
 
127
 
        comps = g_strsplit (path, ";", 2);
128
 
        if (comps[1])
129
 
                new_path = g_strdup_printf ("%s%s", comps[0], comps[1]);
130
 
        else if (comps[0])
131
 
                new_path = g_strdup (comps[0]);
132
 
 
133
 
        g_strfreev (comps);
134
 
        return new_path;
135
 
}
136
 
 
137
 
#define d(x)
138
 
 
139
 
/**
140
 
 * e_folder_exchange_new:
141
 
 * @hier: the #ExchangeHierarchy containing the new folder
142
 
 * @name: the display name of the folder
143
 
 * @type: the Evolution type of the folder (eg, "mail")
144
 
 * @outlook_class: the Outlook IPM class of the folder (eg, "IPM.Note")
145
 
 * @physical_uri: the "exchange:" URI of the folder
146
 
 * @internal_uri: the "http:" URI of the folder
147
 
 *
148
 
 * Return value: a new #EFolderExchange
149
 
 **/
150
 
EFolder *
151
 
e_folder_exchange_new (ExchangeHierarchy *hier, const gchar *name,
152
 
                       const gchar *type, const gchar *outlook_class,
153
 
                       const gchar *physical_uri, const gchar *internal_uri)
154
 
{
155
 
        EFolderExchange *efe;
156
 
        EFolder *ef;
157
 
        gchar *sanitized_path;
158
 
 
159
 
        g_return_val_if_fail (EXCHANGE_IS_HIERARCHY (hier), NULL);
160
 
        g_return_val_if_fail (name != NULL, NULL);
161
 
        g_return_val_if_fail (type != NULL, NULL);
162
 
        g_return_val_if_fail (physical_uri != NULL, NULL);
163
 
        g_return_val_if_fail (internal_uri != NULL, NULL);
164
 
 
165
 
        d(g_print ("e_folder_exchange_new: name=[%s], type=[%s], internal_uri=[%s], physical_uri=[%s]\n",
166
 
                   name, type, internal_uri, physical_uri));
167
 
 
168
 
        efe = g_object_new (E_TYPE_FOLDER_EXCHANGE, NULL);
169
 
        ef = (EFolder *)efe;
170
 
 
171
 
        e_folder_construct (ef, name, type, "");
172
 
 
173
 
        efe->priv->hier = hier;
174
 
        g_object_ref (hier);
175
 
 
176
 
        efe->priv->internal_uri = g_strdup (internal_uri);
177
 
        e_folder_set_physical_uri (ef, physical_uri);
178
 
 
179
 
        sanitized_path = sanitize_path (e2k_uri_path (physical_uri));
180
 
        e2k_uri_decode (sanitized_path);
181
 
        efe->priv->path = sanitized_path;
182
 
        d(g_print ("e_folder_exchange_new: sanitized=[%s]\n", sanitized_path));
183
 
 
184
 
        efe->priv->outlook_class = g_strdup (outlook_class);
185
 
 
186
 
        /* Add ESources */
187
 
        if (hier->type == EXCHANGE_HIERARCHY_PERSONAL ||
188
 
            hier->type == EXCHANGE_HIERARCHY_FAVORITES) {
189
 
 
190
 
                if ((strcmp (type, "calendar") == 0) ||
191
 
                    (strcmp (type, "calendar/public") == 0)) {
192
 
                        add_folder_esource (hier->account,
193
 
                                            EXCHANGE_CALENDAR_FOLDER,
194
 
                                            name,
195
 
                                            physical_uri);
196
 
                }
197
 
                else if ((strcmp (type, "tasks") == 0) ||
198
 
                         (strcmp (type, "tasks/public") == 0)) {
199
 
                        add_folder_esource (hier->account,
200
 
                                            EXCHANGE_TASKS_FOLDER,
201
 
                                            name,
202
 
                                            physical_uri);
203
 
                }
204
 
                else if ((strcmp (type, "contacts") == 0) ||
205
 
                         (strcmp (type, "contacts/public") == 0)) {
206
 
                        add_folder_esource (hier->account,
207
 
                                            EXCHANGE_CONTACTS_FOLDER,
208
 
                                            name,
209
 
                                            physical_uri);
210
 
                }
211
 
        }
212
 
        return ef;
213
 
}
214
 
 
215
 
/**
216
 
 * e_folder_exchange_get_internal_uri:
217
 
 * @folder: an #EFolderExchange
218
 
 *
219
 
 * Returns the folder's internal (http/https) URI. The caller
220
 
 * should not cache this value, since it may change if the server
221
 
 * sends a redirect when we try to use it.
222
 
 *
223
 
 * Return value: @folder's internal (http/https) URI
224
 
 **/
225
 
const gchar *
226
 
e_folder_exchange_get_internal_uri (EFolder *folder)
227
 
{
228
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
229
 
 
230
 
        return E_FOLDER_EXCHANGE (folder)->priv->internal_uri;
231
 
}
232
 
 
233
 
/**
234
 
 * e_folder_exchange_set_internal_uri:
235
 
 * @folder: an #EFolderExchange
236
 
 * @internal_uri: new internal_uri value
237
 
 *
238
 
 * Updates @folder's internal URI to reflect a redirection response
239
 
 * from the server.
240
 
 **/
241
 
void
242
 
e_folder_exchange_set_internal_uri (EFolder *folder, const gchar *internal_uri)
243
 
{
244
 
        EFolderExchange *efe;
245
 
 
246
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
247
 
        g_return_if_fail (internal_uri != NULL);
248
 
 
249
 
        efe = E_FOLDER_EXCHANGE (folder);
250
 
        g_free (efe->priv->internal_uri);
251
 
        efe->priv->internal_uri = g_strdup (internal_uri);
252
 
}
253
 
 
254
 
/**
255
 
 * e_folder_exchange_get_path:
256
 
 * @folder: an #EFolderExchange
257
 
 *
258
 
 * Return value: @folder's path within its Evolution storage
259
 
 **/
260
 
const gchar *
261
 
e_folder_exchange_get_path (EFolder *folder)
262
 
{
263
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
264
 
 
265
 
        return E_FOLDER_EXCHANGE (folder)->priv->path;
266
 
}
267
 
 
268
 
/**
269
 
 * e_folder_exchange_get_permanent_uri:
270
 
 * @folder: an #EFolderExchange
271
 
 *
272
 
 * Returns the folder's permanent URI. See docs/entryids for more
273
 
 * details.
274
 
 *
275
 
 * Return value: @folder's permanent URI
276
 
 **/
277
 
const gchar *
278
 
e_folder_exchange_get_permanent_uri (EFolder *folder)
279
 
{
280
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
281
 
 
282
 
        return E_FOLDER_EXCHANGE (folder)->priv->permanent_uri;
283
 
}
284
 
 
285
 
/**
286
 
 * e_folder_exchange_set_permanent_uri:
287
 
 * @folder: an #EFolderExchange
288
 
 * @permanent_uri: permanent_uri value
289
 
 *
290
 
 * Sets @folder's permanent URI (which must, for obvious reasons, have
291
 
 * previously been unset).
292
 
 **/
293
 
void
294
 
e_folder_exchange_set_permanent_uri (EFolder *folder, const gchar *permanent_uri)
295
 
{
296
 
        EFolderExchange *efe;
297
 
 
298
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
299
 
 
300
 
        efe = E_FOLDER_EXCHANGE (folder);
301
 
        g_return_if_fail (efe->priv->permanent_uri == NULL && permanent_uri != NULL);
302
 
 
303
 
        efe->priv->permanent_uri = g_strdup (permanent_uri);
304
 
}
305
 
 
306
 
/**
307
 
 * e_folder_exchange_get_folder_size:
308
 
 * @folder: an #EFolderExchange
309
 
 *
310
 
 * Returns the folder's size. See docs/entryids for more
311
 
 * details.
312
 
 *
313
 
 * Return value: @folder's size
314
 
 **/
315
 
gint64
316
 
e_folder_exchange_get_folder_size (EFolder *folder)
317
 
{
318
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), -1);
319
 
 
320
 
        return E_FOLDER_EXCHANGE (folder)->priv->folder_size;
321
 
}
322
 
 
323
 
/**
324
 
 * e_folder_exchange_set_folder_size:
325
 
 * @folder: an #EFolderExchange
326
 
 * @folder_size: folder size
327
 
 *
328
 
 * Sets @folder's folder_size
329
 
 **/
330
 
void
331
 
e_folder_exchange_set_folder_size (EFolder *folder, gint64 folder_size)
332
 
{
333
 
        EFolderExchange *efe;
334
 
 
335
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
336
 
 
337
 
        efe = E_FOLDER_EXCHANGE (folder);
338
 
 
339
 
        efe->priv->folder_size = folder_size;
340
 
}
341
 
 
342
 
/**
343
 
 * e_folder_exchange_get_has_subfolders:
344
 
 * @folder: an #EFolderExchange
345
 
 *
346
 
 * Return value: whether or not @folder has subfolders
347
 
 **/
348
 
gboolean
349
 
e_folder_exchange_get_has_subfolders (EFolder *folder)
350
 
{
351
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), FALSE);
352
 
 
353
 
        return E_FOLDER_EXCHANGE (folder)->priv->has_subfolders;
354
 
}
355
 
 
356
 
/**
357
 
 * e_folder_exchange_set_has_subfolders
358
 
 * @folder: an #EFolderExchange
359
 
 * @has_subfolders: whether or not @folder has subfolders
360
 
 *
361
 
 * Sets @folder's has_subfolders flag.
362
 
 **/
363
 
void
364
 
e_folder_exchange_set_has_subfolders (EFolder *folder,
365
 
                                      gboolean has_subfolders)
366
 
{
367
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
368
 
 
369
 
        E_FOLDER_EXCHANGE (folder)->priv->has_subfolders = has_subfolders;
370
 
}
371
 
 
372
 
/**
373
 
 * e_folder_exchange_get_rescan_tree:
374
 
 * @folder: an #EFolderExchange
375
 
 *
376
 
 * Return value: whether or not to rescan @folder tree
377
 
 **/
378
 
gboolean
379
 
e_folder_exchange_get_rescan_tree (EFolder *folder)
380
 
{
381
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), FALSE);
382
 
 
383
 
        return E_FOLDER_EXCHANGE (folder)->priv->rescan_tree;
384
 
}
385
 
 
386
 
/**
387
 
 * e_folder_exchange_set_rescan_tree
388
 
 * @folder: an #EFolderExchange
389
 
 * @rescan_tree: whether or not @folder needs to be rescanned
390
 
 *
391
 
 * Sets @folder's has_subfolders flag.
392
 
 **/
393
 
void
394
 
e_folder_exchange_set_rescan_tree (EFolder *folder,
395
 
                                   gboolean rescan_tree)
396
 
{
397
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
398
 
 
399
 
        E_FOLDER_EXCHANGE (folder)->priv->rescan_tree = rescan_tree;
400
 
}
401
 
 
402
 
/**
403
 
 * e_folder_exchange_get_outlook_class:
404
 
 * @folder: an #EFolderExchange
405
 
 *
406
 
 * Return value: @folder's Outlook IPM class
407
 
 **/
408
 
const gchar *
409
 
e_folder_exchange_get_outlook_class (EFolder *folder)
410
 
{
411
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
412
 
 
413
 
        return E_FOLDER_EXCHANGE (folder)->priv->outlook_class;
414
 
}
415
 
 
416
 
/**
417
 
 * e_folder_exchange_get_hierarchy
418
 
 * @folder: an #EFolderExchange
419
 
 *
420
 
 * Return value: @folder's hierarchy
421
 
 **/
422
 
ExchangeHierarchy *
423
 
e_folder_exchange_get_hierarchy (EFolder *folder)
424
 
{
425
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
426
 
 
427
 
        return E_FOLDER_EXCHANGE (folder)->priv->hier;
428
 
}
429
 
 
430
 
/**
431
 
 * e_folder_exchange_get_storage_file:
432
 
 * @folder: an #EFolderExchange
433
 
 * @filename: name of a file
434
 
 *
435
 
 * This returns a unique filename ending in @filename in the local
436
 
 * storage space reserved for @folder.
437
 
 *
438
 
 * Return value: the full filename, which must be freed.
439
 
 **/
440
 
gchar *
441
 
e_folder_exchange_get_storage_file (EFolder *folder, const gchar *filename)
442
 
{
443
 
        EFolderExchange *efe;
444
 
        gchar *path;
445
 
 
446
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
447
 
 
448
 
        efe = (EFolderExchange *)folder;
449
 
 
450
 
        if (!efe->priv->storage_dir) {
451
 
                efe->priv->storage_dir = e_path_to_physical (
452
 
                        efe->priv->hier->account->storage_dir,
453
 
                        efe->priv->path);
454
 
                g_mkdir_with_parents (efe->priv->storage_dir, 0755);
455
 
        }
456
 
 
457
 
        path = g_build_filename (efe->priv->storage_dir, filename, NULL);
458
 
        return path;
459
 
}
460
 
 
461
 
/**
462
 
 * e_folder_exchange_save_to_file:
463
 
 * @folder: the folder
464
 
 * @filename: a filename
465
 
 *
466
 
 * Saves all relevant information about @folder to @filename.
467
 
 *
468
 
 * Return value: success or failure
469
 
 **/
470
 
gboolean
471
 
e_folder_exchange_save_to_file (EFolder *folder, const gchar *filename)
472
 
{
473
 
        xmlDoc *doc;
474
 
        xmlNode *root;
475
 
        const gchar *name, *type, *outlook_class;
476
 
        const gchar *physical_uri, *internal_uri, *permanent_uri;
477
 
        gchar *folder_size;
478
 
        gint64 fsize;
479
 
        gint status;
480
 
 
481
 
        name = e_folder_get_name (folder);
482
 
        type = e_folder_get_type_string (folder);
483
 
        outlook_class = e_folder_exchange_get_outlook_class (folder);
484
 
        physical_uri = e_folder_get_physical_uri (folder);
485
 
        internal_uri = e_folder_exchange_get_internal_uri (folder);
486
 
        permanent_uri = e_folder_exchange_get_permanent_uri (folder);
487
 
 
488
 
        g_return_val_if_fail (name && type && physical_uri && internal_uri,
489
 
                              FALSE);
490
 
 
491
 
        if ((fsize = e_folder_exchange_get_folder_size (folder)) >= 0)
492
 
                folder_size = g_strdup_printf ("%" G_GINT64_FORMAT, fsize);
493
 
        else
494
 
                return FALSE;
495
 
 
496
 
        doc = xmlNewDoc ((xmlChar *) "1.0");
497
 
        root = xmlNewDocNode (doc, NULL, (xmlChar *) "connector-folder", NULL);
498
 
        xmlNewProp (root, (xmlChar *) "version", (xmlChar *) "1");
499
 
        xmlDocSetRootElement (doc, root);
500
 
 
501
 
        xmlNewChild (
502
 
                root, NULL,
503
 
                (xmlChar *) "displayname",
504
 
                (xmlChar *) name);
505
 
        xmlNewChild (
506
 
                root, NULL,
507
 
                (xmlChar *) "type",
508
 
                (xmlChar *) type);
509
 
        xmlNewChild (
510
 
                root, NULL,
511
 
                (xmlChar *) "outlook_class",
512
 
                (xmlChar *) outlook_class);
513
 
        xmlNewChild (
514
 
                root, NULL,
515
 
                (xmlChar *) "physical_uri",
516
 
                (xmlChar *) physical_uri);
517
 
        xmlNewChild (
518
 
                root, NULL,
519
 
                (xmlChar *) "internal_uri",
520
 
                (xmlChar *) internal_uri);
521
 
        xmlNewChild (
522
 
                root, NULL,
523
 
                (xmlChar *) "folder_size",
524
 
                (xmlChar *) folder_size);
525
 
        if (permanent_uri)
526
 
                xmlNewChild (
527
 
                        root, NULL,
528
 
                        (xmlChar *) "permanent_uri",
529
 
                        (xmlChar *) permanent_uri);
530
 
 
531
 
        status = e_xml_save_file (filename, doc);
532
 
 
533
 
        if (status < 0)
534
 
                g_unlink (filename);
535
 
 
536
 
        xmlFreeDoc (doc);
537
 
 
538
 
        g_free (folder_size);
539
 
 
540
 
        return status == 0;
541
 
}
542
 
 
543
 
/**
544
 
 * e_folder_exchange_new_from_file:
545
 
 * @hier: the hierarchy to create the folder under
546
 
 * @filename: a filename
547
 
 *
548
 
 * Loads information about a folder from a saved file.
549
 
 *
550
 
 * Return value: the folder, or %NULL on a failed load.
551
 
 **/
552
 
EFolder *
553
 
e_folder_exchange_new_from_file (ExchangeHierarchy *hier, const gchar *filename)
554
 
{
555
 
        EFolder *folder = NULL;
556
 
        xmlDoc *doc;
557
 
        xmlNode *root, *node;
558
 
        xmlChar *version, *display_name = NULL;
559
 
        xmlChar *type = NULL, *outlook_class = NULL;
560
 
        xmlChar *physical_uri = NULL, *internal_uri = NULL;
561
 
        xmlChar *permanent_uri = NULL;
562
 
        xmlChar *folder_size = NULL;
563
 
 
564
 
        doc = e_xml_parse_file (filename);
565
 
 
566
 
        if (!doc)
567
 
                return NULL;
568
 
 
569
 
        root = xmlDocGetRootElement (doc);
570
 
        if (root == NULL || strcmp ((gchar *) root->name, "connector-folder") != 0) {
571
 
                xmlFreeDoc (doc);
572
 
                return NULL;
573
 
        }
574
 
        version = xmlGetProp (root, (xmlChar *) "version");
575
 
        if (!version) {
576
 
                xmlFreeDoc (doc);
577
 
                return NULL;
578
 
        }
579
 
        if (strcmp ((gchar *) version, "1") != 0) {
580
 
                xmlFreeDoc (doc);
581
 
                xmlFree (version);
582
 
                return NULL;
583
 
        }
584
 
        xmlFree (version);
585
 
 
586
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "displayname");
587
 
        if (!node)
588
 
                goto done;
589
 
        display_name = xmlNodeGetContent (node);
590
 
 
591
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "type");
592
 
        if (!node)
593
 
                goto done;
594
 
        type = xmlNodeGetContent (node);
595
 
 
596
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "outlook_class");
597
 
        if (!node)
598
 
                goto done;
599
 
        outlook_class = xmlNodeGetContent (node);
600
 
 
601
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "physical_uri");
602
 
        if (!node)
603
 
                goto done;
604
 
        physical_uri = xmlNodeGetContent (node);
605
 
 
606
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "internal_uri");
607
 
        if (!node)
608
 
                goto done;
609
 
        internal_uri = xmlNodeGetContent (node);
610
 
 
611
 
        if (!display_name || !type || !physical_uri || !internal_uri)
612
 
                goto done;
613
 
 
614
 
        folder = e_folder_exchange_new (
615
 
                hier,
616
 
                (gchar *) display_name,
617
 
                (gchar *) type,
618
 
                (gchar *) outlook_class,
619
 
                (gchar *) physical_uri,
620
 
                (gchar *) internal_uri);
621
 
 
622
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "permanent_uri");
623
 
        if (node) {
624
 
                permanent_uri = xmlNodeGetContent (node);
625
 
                e_folder_exchange_set_permanent_uri (folder, (gchar *) permanent_uri);
626
 
        }
627
 
 
628
 
        node = e_xml_get_child_by_name (root, (xmlChar *) "folder_size");
629
 
        if (node) {
630
 
                folder_size = xmlNodeGetContent (node);
631
 
                e_folder_exchange_set_folder_size (folder, atoi ((gchar *) folder_size));
632
 
        }
633
 
 
634
 
 done:
635
 
        xmlFree (display_name);
636
 
        xmlFree (type);
637
 
        xmlFree (outlook_class);
638
 
        xmlFree (physical_uri);
639
 
        xmlFree (internal_uri);
640
 
        xmlFree (permanent_uri);
641
 
        xmlFree (folder_size);
642
 
        xmlFreeDoc (doc);
643
 
 
644
 
        return folder;
645
 
}
646
 
 
647
 
/* E2kContext wrappers */
648
 
#define E_FOLDER_EXCHANGE_CONTEXT(efe) (exchange_account_get_context (((EFolderExchange *)efe)->priv->hier->account))
649
 
#define E_FOLDER_EXCHANGE_URI(efe) (((EFolderExchange *)efe)->priv->internal_uri)
650
 
 
651
 
/**
652
 
 * e_folder_exchange_propfind:
653
 
 * @folder: the folder
654
 
 * @op: pointer to an #E2kOperation to use for cancellation
655
 
 * @props: array of properties to find
656
 
 * @nprops: length of @props
657
 
 * @results: on return, the results
658
 
 * @nresults: length of @results
659
 
 *
660
 
 * Performs a PROPFIND operation on @folder. This is a convenience
661
 
 * wrapper around e2k_context_propfind(), qv.
662
 
 *
663
 
 * Return value: the HTTP status
664
 
 **/
665
 
E2kHTTPStatus
666
 
e_folder_exchange_propfind (EFolder *folder, E2kOperation *op,
667
 
                            const gchar **props, gint nprops,
668
 
                            E2kResult **results, gint *nresults)
669
 
{
670
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), E2K_HTTP_MALFORMED);
671
 
 
672
 
        return e2k_context_propfind (
673
 
                E_FOLDER_EXCHANGE_CONTEXT (folder), op,
674
 
                E_FOLDER_EXCHANGE_URI (folder),
675
 
                props, nprops, results, nresults);
676
 
}
677
 
 
678
 
/**
679
 
 * e_folder_exchange_bpropfind_start:
680
 
 * @folder: the folder
681
 
 * @op: pointer to an #E2kOperation to use for cancellation
682
 
 * @hrefs: array of URIs, relative to @folder
683
 
 * @nhrefs: length of @hrefs
684
 
 * @props: array of properties to find
685
 
 * @nprops: length of @props
686
 
 *
687
 
 * Begins a BPROPFIND (bulk PROPFIND) operation on @folder for @hrefs.
688
 
 * This is a convenience wrapper around e2k_context_bpropfind_start(),
689
 
 * qv.
690
 
 *
691
 
 * Return value: an iterator for getting the results
692
 
 **/
693
 
E2kResultIter *
694
 
e_folder_exchange_bpropfind_start (EFolder *folder, E2kOperation *op,
695
 
                                   const gchar **hrefs, gint nhrefs,
696
 
                                   const gchar **props, gint nprops)
697
 
{
698
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
699
 
 
700
 
        return e2k_context_bpropfind_start (
701
 
                E_FOLDER_EXCHANGE_CONTEXT (folder), op,
702
 
                E_FOLDER_EXCHANGE_URI (folder),
703
 
                hrefs, nhrefs, props, nprops);
704
 
}
705
 
 
706
 
/**
707
 
 * e_folder_exchange_search_start:
708
 
 * @folder: the folder
709
 
 * @op: pointer to an #E2kOperation to use for cancellation
710
 
 * @props: the properties to search for
711
 
 * @nprops: size of @props array
712
 
 * @rn: the search restriction
713
 
 * @orderby: if non-%NULL, the field to sort the search results by
714
 
 * @ascending: %TRUE for an ascending search, %FALSE for descending.
715
 
 *
716
 
 * Begins a SEARCH on the contents of @folder. This is a convenience
717
 
 * wrapper around e2k_context_search_start(), qv.
718
 
 *
719
 
 * Return value: an iterator for returning the search results
720
 
 **/
721
 
E2kResultIter *
722
 
e_folder_exchange_search_start (EFolder *folder, E2kOperation *op,
723
 
                                const gchar **props, gint nprops,
724
 
                                E2kRestriction *rn, const gchar *orderby,
725
 
                                gboolean ascending)
726
 
{
727
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
728
 
 
729
 
        return e2k_context_search_start (
730
 
                E_FOLDER_EXCHANGE_CONTEXT (folder), op,
731
 
                E_FOLDER_EXCHANGE_URI (folder),
732
 
                props, nprops, rn, orderby, ascending);
733
 
}
734
 
 
735
 
/**
736
 
 * e_folder_exchange_subscribe:
737
 
 * @folder: the folder to subscribe to notifications on
738
 
 * @type: the type of notification to subscribe to
739
 
 * @min_interval: the minimum interval (in seconds) between
740
 
 * notifications.
741
 
 * @callback: the callback to call when a notification has been
742
 
 * received
743
 
 * @user_data: data to pass to @callback.
744
 
 *
745
 
 * This subscribes to change notifications of the given @type on
746
 
 * @folder. This is a convenience wrapper around
747
 
 * e2k_context_subscribe(), qv.
748
 
 **/
749
 
void
750
 
e_folder_exchange_subscribe (EFolder *folder,
751
 
                             E2kContextChangeType type, gint min_interval,
752
 
                             E2kContextChangeCallback callback,
753
 
                             gpointer user_data)
754
 
{
755
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
756
 
 
757
 
        e2k_context_subscribe (E_FOLDER_EXCHANGE_CONTEXT (folder),
758
 
                               E_FOLDER_EXCHANGE_URI (folder),
759
 
                               type, min_interval, callback, user_data);
760
 
}
761
 
 
762
 
/**
763
 
 * e_folder_exchange_unsubscribe:
764
 
 * @folder: the folder to unsubscribe from
765
 
 *
766
 
 * Unsubscribes to all notifications on @folder. This is a convenience
767
 
 * wrapper around e2k_context_unsubscribe(), qv.
768
 
 **/
769
 
void
770
 
e_folder_exchange_unsubscribe (EFolder *folder)
771
 
{
772
 
        E2kContext *ctx;
773
 
 
774
 
        g_return_if_fail (E_IS_FOLDER_EXCHANGE (folder));
775
 
 
776
 
        /* FIXME : This is a hack as of now. The free_folder in mail-stub
777
 
        gets called when we are in offline and the context is NULL then. */
778
 
        ctx = E_FOLDER_EXCHANGE_CONTEXT (folder);
779
 
        if (ctx) {
780
 
                e2k_context_unsubscribe (E_FOLDER_EXCHANGE_CONTEXT (folder),
781
 
                                         E_FOLDER_EXCHANGE_URI (folder));
782
 
        }
783
 
}
784
 
 
785
 
/**
786
 
 * e_folder_exchange_transfer_start:
787
 
 * @source: the source folder
788
 
 * @op: pointer to an #E2kOperation to use for cancellation
789
 
 * @dest: the destination folder
790
 
 * @source_hrefs: an array of hrefs to move, relative to @source_folder
791
 
 * @delete_originals: whether or not to delete the original objects
792
 
 *
793
 
 * Starts a BMOVE or BCOPY (depending on @delete_originals) operation
794
 
 * on @source. This is a convenience wrapper around
795
 
 * e2k_context_transfer_start(), qv.
796
 
 *
797
 
 * Return value: the iterator for the results
798
 
 **/
799
 
E2kResultIter *
800
 
e_folder_exchange_transfer_start (EFolder *source, E2kOperation *op,
801
 
                                  EFolder *dest, GPtrArray *source_hrefs,
802
 
                                  gboolean delete_originals)
803
 
{
804
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (source), NULL);
805
 
 
806
 
        return e2k_context_transfer_start (E_FOLDER_EXCHANGE_CONTEXT (source), op,
807
 
                                           E_FOLDER_EXCHANGE_URI (source),
808
 
                                           E_FOLDER_EXCHANGE_URI (dest),
809
 
                                           source_hrefs, delete_originals);
810
 
}
811
 
 
812
 
/**
813
 
 * e_folder_exchange_put_new:
814
 
 * @folder: the folder to PUT the new item into
815
 
 * @op: pointer to an #E2kOperation to use for cancellation
816
 
 * @object_name: base name of the new object (not URI-encoded)
817
 
 * @test_callback: callback to use to test possible object URIs
818
 
 * @user_data: data for @test_callback
819
 
 * @content_type: MIME Content-Type of the data
820
 
 * @body: data to PUT
821
 
 * @length: length of @body
822
 
 * @location: if not %NULL, will contain the Location of the POSTed
823
 
 * object on return
824
 
 * @repl_uid: if not %NULL, will contain the Repl-UID of the POSTed
825
 
 * object on return
826
 
 *
827
 
 * PUTs data into @folder with a new name based on @object_name. This
828
 
 * is a convenience wrapper around e2k_context_put_new(), qv.
829
 
 *
830
 
 * Return value: the HTTP status
831
 
 **/
832
 
E2kHTTPStatus
833
 
e_folder_exchange_put_new (EFolder *folder,
834
 
                           E2kOperation *op,
835
 
                           const gchar *object_name,
836
 
                           E2kContextTestCallback test_callback,
837
 
                           gpointer user_data,
838
 
                           const gchar *content_type,
839
 
                           const gchar *body, gint length,
840
 
                           gchar **location, gchar **repl_uid)
841
 
{
842
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), E2K_HTTP_MALFORMED);
843
 
 
844
 
        return e2k_context_put_new (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
845
 
                                    E_FOLDER_EXCHANGE_URI (folder),
846
 
                                    object_name, test_callback, user_data,
847
 
                                    content_type, body, length,
848
 
                                    location, repl_uid);
849
 
}
850
 
 
851
 
/**
852
 
 * e_folder_exchange_proppatch_new:
853
 
 * @folder: the folder to PROPPATCH a new object in
854
 
 * @op: pointer to an #E2kOperation to use for cancellation
855
 
 * @object_name: base name of the new object (not URI-encoded)
856
 
 * @test_callback: callback to use to test possible object URIs
857
 
 * @user_data: data for @test_callback
858
 
 * @props: the properties to set/remove
859
 
 * @location: if not %NULL, will contain the Location of the
860
 
 * PROPPATCHed object on return
861
 
 * @repl_uid: if not %NULL, will contain the Repl-UID of the
862
 
 * PROPPATCHed object on return
863
 
 *
864
 
 * PROPPATCHes data into @folder with a new name based on
865
 
 * @object_name. This is a convenience wrapper around
866
 
 * e2k_context_proppatch_new(), qv.
867
 
 
868
 
 * Return value: the HTTP status
869
 
 **/
870
 
E2kHTTPStatus
871
 
e_folder_exchange_proppatch_new (EFolder *folder, E2kOperation *op,
872
 
                                 const gchar *object_name,
873
 
                                 E2kContextTestCallback test_callback,
874
 
                                 gpointer user_data,
875
 
                                 E2kProperties *props,
876
 
                                 gchar **location, gchar **repl_uid)
877
 
{
878
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), E2K_HTTP_MALFORMED);
879
 
 
880
 
        return e2k_context_proppatch_new (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
881
 
                                          E_FOLDER_EXCHANGE_URI (folder),
882
 
                                          object_name,
883
 
                                          test_callback, user_data,
884
 
                                          props,
885
 
                                          location, repl_uid);
886
 
}
887
 
 
888
 
/**
889
 
 * e_folder_exchange_bproppatch_start:
890
 
 * @folder: the folder
891
 
 * @op: pointer to an #E2kOperation to use for cancellation
892
 
 * @hrefs: array of URIs, relative to @folder
893
 
 * @nhrefs: length of @hrefs
894
 
 * @props: the properties to set/remove
895
 
 * @create: whether or not to create the objects if they do not exist
896
 
 *
897
 
 * Begins BPROPPATCHing @hrefs under @folder. This is a convenience
898
 
 * wrapper around e2k_context_bproppatch_start(), qv.
899
 
 *
900
 
 * Return value: an iterator for getting the results of the BPROPPATCH
901
 
 **/
902
 
E2kResultIter *
903
 
e_folder_exchange_bproppatch_start (EFolder *folder, E2kOperation *op,
904
 
                                    const gchar **hrefs, gint nhrefs,
905
 
                                    E2kProperties *props, gboolean create)
906
 
{
907
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
908
 
 
909
 
        return e2k_context_bproppatch_start (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
910
 
                                             E_FOLDER_EXCHANGE_URI (folder),
911
 
                                             hrefs, nhrefs, props, create);
912
 
}
913
 
 
914
 
/**
915
 
 * e_folder_exchange_bdelete_start:
916
 
 * @folder: the folder
917
 
 * @op: pointer to an #E2kOperation to use for cancellation
918
 
 * @hrefs: array of URIs, relative to @folder, to delete
919
 
 * @nhrefs: length of @hrefs
920
 
 *
921
 
 * Begins a BDELETE (bulk DELETE) operation in @folder for @hrefs.
922
 
 * This is a convenience wrapper around e2k_context_bdelete_start(),
923
 
 * qv.
924
 
 *
925
 
 * Return value: an iterator for returning the results
926
 
 **/
927
 
E2kResultIter *
928
 
e_folder_exchange_bdelete_start (EFolder *folder, E2kOperation *op,
929
 
                                 const gchar **hrefs, gint nhrefs)
930
 
{
931
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), NULL);
932
 
 
933
 
        return e2k_context_bdelete_start (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
934
 
                                          E_FOLDER_EXCHANGE_URI (folder),
935
 
                                          hrefs, nhrefs);
936
 
}
937
 
 
938
 
/**
939
 
 * e_folder_exchange_mkcol:
940
 
 * @folder: the folder to create
941
 
 * @op: pointer to an #E2kOperation to use for cancellation
942
 
 * @props: properties to set on the new folder, or %NULL
943
 
 * @permanent_url: if not %NULL, will contain the permanent URL of the
944
 
 * new folder on return
945
 
 *
946
 
 * Performs a MKCOL operation to create @folder, with optional
947
 
 * additional properties. This is a convenience wrapper around
948
 
 * e2k_context_mkcol(), qv.
949
 
 *
950
 
 * Return value: the HTTP status
951
 
 **/
952
 
E2kHTTPStatus
953
 
e_folder_exchange_mkcol (EFolder *folder, E2kOperation *op,
954
 
                         E2kProperties *props,
955
 
                         gchar **permanent_url)
956
 
{
957
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), E2K_HTTP_MALFORMED);
958
 
 
959
 
        return e2k_context_mkcol (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
960
 
                                  E_FOLDER_EXCHANGE_URI (folder),
961
 
                                  props, permanent_url);
962
 
}
963
 
 
964
 
/**
965
 
 * e_folder_exchange_delete:
966
 
 * @folder: the folder to delete
967
 
 * @op: pointer to an #E2kOperation to use for cancellation
968
 
 *
969
 
 * Attempts to DELETE @folder. This is a convenience wrapper around
970
 
 * e2k_context_delete(), qv.
971
 
 *
972
 
 * Return value: the HTTP status
973
 
 **/
974
 
E2kHTTPStatus
975
 
e_folder_exchange_delete (EFolder *folder, E2kOperation *op)
976
 
{
977
 
        ExchangeHierarchy *hier;
978
 
        const gchar *folder_type, *physical_uri;
979
 
 
980
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (folder), E2K_HTTP_MALFORMED);
981
 
        /* remove ESources */
982
 
        hier = e_folder_exchange_get_hierarchy (folder);
983
 
 
984
 
        if (hier->type == EXCHANGE_HIERARCHY_PERSONAL ||
985
 
            hier->type == EXCHANGE_HIERARCHY_FAVORITES) {
986
 
                folder_type = e_folder_get_type_string (folder);
987
 
                physical_uri = e_folder_get_physical_uri (folder);
988
 
 
989
 
                if ((strcmp (folder_type, "calendar") == 0) ||
990
 
                    (strcmp (folder_type, "calendar/public") == 0)) {
991
 
                        remove_folder_esource (hier->account,
992
 
                                               EXCHANGE_CALENDAR_FOLDER,
993
 
                                               physical_uri);
994
 
                }
995
 
                else if ((strcmp (folder_type, "tasks") == 0) ||
996
 
                         (strcmp (folder_type, "tasks/public") == 0)) {
997
 
                        remove_folder_esource (hier->account,
998
 
                                               EXCHANGE_TASKS_FOLDER,
999
 
                                               physical_uri);
1000
 
                }
1001
 
                else if ((strcmp (folder_type, "contacts") == 0) ||
1002
 
                         (strcmp (folder_type, "contacts/public") == 0)) {
1003
 
                        remove_folder_esource (hier->account,
1004
 
                                               EXCHANGE_CONTACTS_FOLDER,
1005
 
                                               physical_uri);
1006
 
                }
1007
 
        }
1008
 
 
1009
 
        return e2k_context_delete (E_FOLDER_EXCHANGE_CONTEXT (folder), op,
1010
 
                                   E_FOLDER_EXCHANGE_URI (folder));
1011
 
}
1012
 
 
1013
 
/**
1014
 
 * e_folder_exchange_transfer_dir:
1015
 
 * @source: source folder
1016
 
 * @op: pointer to an #E2kOperation to use for cancellation
1017
 
 * @dest: destination folder
1018
 
 * @delete_original: whether or not to delete the original folder
1019
 
 * @permanent_url: if not %NULL, will contain the permanent URL of the
1020
 
 * new folder on return
1021
 
 *
1022
 
 * Performs a MOVE or COPY (depending on @delete_original) operation
1023
 
 * on @source. This is a convenience wrapper around
1024
 
 * e2k_context_transfer_dir(), qv.
1025
 
 *
1026
 
 * Return value: the HTTP status
1027
 
 **/
1028
 
E2kHTTPStatus
1029
 
e_folder_exchange_transfer_dir (EFolder *source, E2kOperation *op,
1030
 
                                EFolder *dest, gboolean delete_original,
1031
 
                                gchar **permanent_url)
1032
 
{
1033
 
        g_return_val_if_fail (E_IS_FOLDER_EXCHANGE (source), E2K_HTTP_MALFORMED);
1034
 
 
1035
 
        return e2k_context_transfer_dir (E_FOLDER_EXCHANGE_CONTEXT (source), op,
1036
 
                                         E_FOLDER_EXCHANGE_URI (source),
1037
 
                                         E_FOLDER_EXCHANGE_URI (dest),
1038
 
                                         delete_original, permanent_url);
1039
 
}