Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / servers / exchange / storage / exchange-hierarchy-favorites.c
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 /* ExchangeHierarchyFavorites: class for the "Favorites" Public Folders
21  * hierarchy (and favorites-handling code).
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "exchange-hierarchy-favorites.h"
29 #include "exchange-account.h"
30 #include "e-folder-exchange.h"
31 #include "e2k-propnames.h"
32 #include "e2k-uri.h"
33 #include "e2k-utils.h"
34 #include "exchange-esource.h"
35
36 #include <libedataserver/e-source-list.h>
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 struct _ExchangeHierarchyFavoritesPrivate {
43         char *public_uri, *shortcuts_uri;
44         GHashTable *shortcuts;
45 };
46
47 #define PARENT_TYPE EXCHANGE_TYPE_HIERARCHY_SOMEDAV
48 static ExchangeHierarchySomeDAVClass *parent_class = NULL;
49
50 static GPtrArray *get_hrefs (ExchangeHierarchySomeDAV *hsd);
51 static ExchangeAccountFolderResult remove_folder (ExchangeHierarchy *hier,
52                                                   EFolder *folder);
53 static void finalize (GObject *object);
54
55 static void
56 class_init (GObjectClass *object_class)
57 {
58         ExchangeHierarchySomeDAVClass *somedav_class =
59                 EXCHANGE_HIERARCHY_SOMEDAV_CLASS (object_class);
60         ExchangeHierarchyClass *hier_class =
61                 EXCHANGE_HIERARCHY_CLASS (object_class);
62
63         parent_class = g_type_class_ref (PARENT_TYPE);
64
65         /* virtual method override */
66         object_class->finalize = finalize;
67         hier_class->remove_folder = remove_folder;
68         somedav_class->get_hrefs = get_hrefs;
69 }
70
71 static void
72 init (GObject *object)
73 {
74         ExchangeHierarchyFavorites *hfav = EXCHANGE_HIERARCHY_FAVORITES (object);
75
76         hfav->priv = g_new0 (ExchangeHierarchyFavoritesPrivate, 1);
77         hfav->priv->shortcuts = g_hash_table_new_full (g_str_hash, g_str_equal,
78                                                        g_free, g_free);
79 }
80
81 static void
82 finalize (GObject *object)
83 {
84         ExchangeHierarchyFavorites *hfav = EXCHANGE_HIERARCHY_FAVORITES (object);
85
86         g_hash_table_destroy (hfav->priv->shortcuts);
87         g_free (hfav->priv->public_uri);
88         g_free (hfav->priv->shortcuts_uri);
89         g_free (hfav->priv);
90
91         G_OBJECT_CLASS (parent_class)->finalize (object);
92 }
93
94 E2K_MAKE_TYPE (exchange_hierarchy_favorites, ExchangeHierarchyFavorites, class_init, init, PARENT_TYPE)
95
96 static void
97 add_hrefs (ExchangeHierarchy *hier, EFolder *folder, gpointer hrefs)
98 {
99         g_ptr_array_add (hrefs, (char *)e2k_uri_path (e_folder_exchange_get_internal_uri (folder)));
100 }
101
102 static const char *shortcuts_props[] = {
103         PR_FAV_DISPLAY_NAME,            /* PR_DISPLAY_NAME of referent */
104         PR_FAV_DISPLAY_ALIAS,           /* if set, user-chosen display name */
105         PR_FAV_PUBLIC_SOURCE_KEY,       /* PR_SOURCE_KEY of referent */
106         PR_FAV_PARENT_SOURCE_KEY,       /* PR_FAV_PUBLIC_SOURCE_KEY of parent */
107         PR_FAV_LEVEL_MASK               /* depth in hierarchy (first level is 1) */
108 };
109 static const int n_shortcuts_props = G_N_ELEMENTS (shortcuts_props);
110
111 static GPtrArray *
112 get_hrefs (ExchangeHierarchySomeDAV *hsd)
113 {
114         ExchangeHierarchy *hier = EXCHANGE_HIERARCHY (hsd);
115         ExchangeHierarchyFavorites *hfav = EXCHANGE_HIERARCHY_FAVORITES (hsd);
116         E2kContext *ctx = exchange_account_get_context (hier->account);
117         GPtrArray *hrefs;
118         E2kResultIter *iter;
119         E2kResult *result, *results;
120         E2kHTTPStatus status;
121         GByteArray *source_key;
122         const char *prop = E2K_PR_DAV_HREF, *shortcut_uri;
123         char *perm_url, *folder_uri;
124         int i, nresults = 0, mode;
125
126         hrefs = g_ptr_array_new ();
127
128         exchange_account_is_offline (hier->account, &mode);
129         if (mode != ONLINE_MODE) {
130                 exchange_hierarchy_webdav_offline_scan_subtree (EXCHANGE_HIERARCHY (hfav), add_hrefs, hrefs);
131                 return hrefs;
132         }
133         /* Scan the shortcut links and use PROPFIND to resolve the
134          * permanent_urls. Unfortunately it doesn't seem to be possible
135          * to BPROPFIND a group of permanent_urls.
136          */
137         iter = e2k_context_search_start (ctx, NULL, hfav->priv->shortcuts_uri, 
138                                          shortcuts_props, n_shortcuts_props,
139                                          NULL, NULL, TRUE);
140         while ((result = e2k_result_iter_next (iter))) {
141                 shortcut_uri = result->href;
142                 source_key = e2k_properties_get_prop (result->props, PR_FAV_PUBLIC_SOURCE_KEY);
143                 if (!source_key)
144                         continue;
145
146                 perm_url = e2k_entryid_to_permanenturl (source_key, hfav->priv->public_uri);
147
148                 status = e2k_context_propfind (ctx, NULL, perm_url,
149                                                &prop, 1, &results, &nresults);
150                 if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status) && nresults) {
151                         folder_uri = g_strdup (results[0].href);
152                         g_ptr_array_add (hrefs, folder_uri);
153                         g_hash_table_insert (hfav->priv->shortcuts,
154                                              g_strdup (folder_uri),
155                                              g_strdup (shortcut_uri));
156                         e2k_results_free (results, nresults);
157                 }
158
159                 g_free (perm_url);
160         }
161
162         status = e2k_result_iter_free (iter);
163         if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
164                 /* FIXME: need to be able to return an error */
165                 for (i = 0; i < hrefs->len; i++)
166                         g_free (hrefs->pdata[i]);
167                 g_ptr_array_free (hrefs, TRUE);
168                 hrefs = NULL;
169         }
170
171         return hrefs;
172 }       
173 /**
174  * exchange_hierarchy_favorites_is_added:
175  * @hier: the hierarchy
176  * @folder: the Public Folder to check in the favorites tree
177  *
178  * Checks if @folder is present in the favorites hierarchy
179  *
180  * Return value: TRUE if @folder is already added as a favorite.
181  **/
182
183 gboolean
184 exchange_hierarchy_favorites_is_added (ExchangeHierarchy *hier, EFolder *folder)
185 {
186         ExchangeHierarchyFavorites *hfav =
187                 EXCHANGE_HIERARCHY_FAVORITES (hier);
188         const char *folder_uri, *shortcut_uri;
189
190         folder_uri = e_folder_exchange_get_internal_uri (folder);
191         shortcut_uri = g_hash_table_lookup (hfav->priv->shortcuts, folder_uri);
192         
193         return shortcut_uri ? TRUE : FALSE;
194 }
195
196 static ExchangeAccountFolderResult
197 remove_folder (ExchangeHierarchy *hier, EFolder *folder)
198 {
199         ExchangeHierarchyFavorites *hfav =
200                 EXCHANGE_HIERARCHY_FAVORITES (hier);
201         const char *folder_uri, *shortcut_uri;
202         E2kHTTPStatus status;
203         const char *folder_type, *physical_uri;
204
205         folder_uri = e_folder_exchange_get_internal_uri (folder);
206         shortcut_uri = g_hash_table_lookup (hfav->priv->shortcuts, folder_uri);
207         if (!shortcut_uri)
208                 return EXCHANGE_ACCOUNT_FOLDER_DOES_NOT_EXIST;
209
210         status = e2k_context_delete (
211                 exchange_account_get_context (hier->account), NULL,
212                 shortcut_uri);
213
214         if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
215                 g_hash_table_remove (hfav->priv->shortcuts, folder_uri);
216                 exchange_hierarchy_removed_folder (hier, folder);
217
218                 /* Temp Fix for remove fav folders. see #59168 */
219                 /* remove ESources */
220                 folder_type = e_folder_get_type_string (folder);
221                 physical_uri = e_folder_get_physical_uri (folder);
222
223                 if (strcmp (folder_type, "calendar") == 0) {
224                         remove_folder_esource (hier->account,
225                                                EXCHANGE_CALENDAR_FOLDER,
226                                                physical_uri);
227                 }
228                 else if (strcmp (folder_type, "tasks") == 0) {
229                         remove_folder_esource (hier->account,
230                                                EXCHANGE_TASKS_FOLDER,
231                                                physical_uri);
232                 }
233                 else if (strcmp (folder_type, "contacts") == 0) {
234                         remove_folder_esource (hier->account,
235                                                EXCHANGE_CONTACTS_FOLDER,
236                                                physical_uri);
237                 }
238         }
239         
240         return exchange_hierarchy_webdav_status_to_folder_result (status);
241 }
242
243 /**
244  * exchange_hierarchy_favorites_add_folder:
245  * @hier: the hierarchy
246  * @folder: the Public Folder to add to the favorites tree
247  *
248  * Adds a new folder to @hier.
249  *
250  * Return value: the folder result.
251  **/
252 ExchangeAccountFolderResult
253 exchange_hierarchy_favorites_add_folder (ExchangeHierarchy *hier,
254                                          EFolder *folder)
255 {
256         ExchangeHierarchyFavorites *hfav;
257         E2kProperties *props;
258         E2kHTTPStatus status;
259         const char *folder_uri, *permanent_uri;
260         char *shortcut_uri;
261
262         g_return_val_if_fail (EXCHANGE_IS_HIERARCHY (hier), EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR);
263         g_return_val_if_fail (E_IS_FOLDER (folder), EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR);
264         g_return_val_if_fail (e_folder_exchange_get_hierarchy (folder)->type == EXCHANGE_HIERARCHY_PUBLIC, EXCHANGE_ACCOUNT_FOLDER_GENERIC_ERROR);
265
266         hfav = EXCHANGE_HIERARCHY_FAVORITES (hier);
267         permanent_uri = e_folder_exchange_get_permanent_uri (folder);
268
269         props = e2k_properties_new ();
270         e2k_properties_set_string (props, PR_FAV_DISPLAY_NAME,
271                                    g_strdup (e_folder_get_name (folder)));
272         if (permanent_uri)      
273                 e2k_properties_set_binary (props, PR_FAV_PUBLIC_SOURCE_KEY,
274                                    e2k_permanenturl_to_entryid (permanent_uri));
275         e2k_properties_set_int (props, PR_FAV_LEVEL_MASK, 1);
276
277         status = e2k_context_proppatch_new (
278                 exchange_account_get_context (hier->account), NULL,
279                 hfav->priv->shortcuts_uri,
280                 e_folder_get_name (folder), NULL, NULL,
281                 props, &shortcut_uri, NULL);
282         e2k_properties_free (props);
283
284         if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
285                 folder_uri = e_folder_exchange_get_internal_uri (folder);
286
287                 g_hash_table_insert (hfav->priv->shortcuts,
288                                      g_strdup (folder_uri), shortcut_uri);
289                 return exchange_hierarchy_somedav_add_folder (EXCHANGE_HIERARCHY_SOMEDAV (hier),
290                                                               folder_uri);
291         } else
292                 return exchange_hierarchy_webdav_status_to_folder_result (status);
293 }
294
295 /**
296  * exchange_hierarchy_favorites_new:
297  * @account: an #ExchangeAccount
298  * @hierarchy_name: the name of the hierarchy
299  * @physical_uri_prefix: prefix for physical URIs in this hierarchy
300  * @home_uri: the home URI of the owner's mailbox
301  * @public_uri: the URI of the public folder tree
302  * @owner_name: display name of the owner of the hierarchy
303  * @owner_email: email address of the owner of the hierarchy
304  * @source_uri: account source URI for folders in this hierarchy
305  *
306  * Creates a new Favorites hierarchy
307  *
308  * Return value: the new hierarchy.
309  **/
310 ExchangeHierarchy *
311 exchange_hierarchy_favorites_new (ExchangeAccount *account,
312                                   const char *hierarchy_name,
313                                   const char *physical_uri_prefix,
314                                   const char *home_uri,
315                                   const char *public_uri,
316                                   const char *owner_name,
317                                   const char *owner_email,
318                                   const char *source_uri)
319 {
320         ExchangeHierarchy *hier;
321         ExchangeHierarchyFavorites *hfav;
322
323         g_return_val_if_fail (EXCHANGE_IS_ACCOUNT (account), NULL);
324
325         hier = g_object_new (EXCHANGE_TYPE_HIERARCHY_FAVORITES, NULL);
326
327         hfav = (ExchangeHierarchyFavorites *)hier;
328         hfav->priv->public_uri = g_strdup (public_uri);
329         hfav->priv->shortcuts_uri = e2k_uri_concat (home_uri, "NON_IPM_SUBTREE/Shortcuts");
330
331         exchange_hierarchy_webdav_construct (EXCHANGE_HIERARCHY_WEBDAV (hier),
332                                              account,
333                                              EXCHANGE_HIERARCHY_FAVORITES,
334                                              hierarchy_name,
335                                              physical_uri_prefix,
336                                              public_uri,
337                                              owner_name, owner_email,
338                                              source_uri,
339                                              TRUE);
340         return hier;
341 }