Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / providers / groupwise / camel-groupwise-store.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-groupwise-store.c : class for an groupwise store */
3
4 /*
5  *  Authors:
6  *  Sivaiah Nallagatla <snallagatla@novell.com>
7  *  parthasarathi susarla <sparthasarathi@novell.com>
8  *
9  *  Copyright 2004 Novell, Inc.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of version 2 of the GNU Lesser General Public
13  * License as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this program; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26
27 #include <config.h>
28
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #include <glib.h>
38 #include <glib/gi18n-lib.h>
39 #include <glib/gstdio.h>
40
41 #include "camel-debug.h"
42 #include "camel-folder.h" 
43 #include "camel-net-utils.h"
44 #include "camel-private.h"
45 #include "camel-session.h"
46 #include "camel-types.h"
47
48 #include "camel-groupwise-folder.h"
49 #include "camel-groupwise-store-summary.h"
50 #include "camel-groupwise-store.h"
51 #include "camel-groupwise-summary.h"
52 #include "camel-groupwise-utils.h"
53
54 #define d(x) 
55 #define CURSOR_ITEM_LIMIT 100
56 #define JUNK_ENABLE 1
57 #define JUNK_PERSISTENCE 14
58
59
60 struct _CamelGroupwiseStorePrivate {
61         char *server_name;
62         char *port;
63         char *user;
64         char *use_ssl;
65
66         char *base_url;
67         char *storage_path;
68
69         GHashTable *id_hash; /*get names from ids*/
70         GHashTable *name_hash;/*get ids from names*/
71         GHashTable *parent_hash;
72         EGwConnection *cnc;
73 };
74
75 static CamelOfflineStoreClass *parent_class = NULL;
76
77 extern CamelServiceAuthType camel_groupwise_password_authtype; /*for the query_auth_types function*/
78 CamelFolderInfo *convert_to_folder_info (CamelGroupwiseStore *store, EGwContainer *container, const char *url, CamelException *ex);
79 static void groupwise_folders_sync (CamelGroupwiseStore *store, CamelException *ex);
80 static int match_path(const char *path, const char *name);
81
82
83
84 static void
85 groupwise_store_construct (CamelService *service, CamelSession *session,
86                            CamelProvider *provider, CamelURL *url,
87                            CamelException *ex)
88 {
89         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (service);
90         CamelStore *store = CAMEL_STORE (service);
91         const char *property_value;
92         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
93         char *path = NULL;
94         
95         d("in groupwise store constrcut\n");
96
97         CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
98         if (camel_exception_is_set (ex))
99                 return;
100         
101         if (!(url->host || url->user)) {
102                 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID,
103                                      _("Host or user not available in url"));
104         }
105
106         /*XXX: The number 3 assigned to the list_loaded variable denotes
107          * the number of times the get_folder_info is called during startup.
108          * We are just trying to minimize the call.
109          * This is a dirty hack. But it *WORKS*
110          */
111         groupwise_store->list_loaded = 3;
112         
113         /*storage path*/
114         priv->storage_path = camel_session_get_storage_path (session, service, ex);
115         if (!priv->storage_path)
116                 return;
117         
118         /*store summary*/
119         path = g_alloca (strlen (priv->storage_path) + 32);
120         sprintf (path, "%s/.summary", priv->storage_path);
121         groupwise_store->summary = camel_groupwise_store_summary_new ();
122         camel_store_summary_set_filename ((CamelStoreSummary *)groupwise_store->summary, path);
123         camel_store_summary_touch ((CamelStoreSummary *)groupwise_store->summary);
124         camel_store_summary_load ((CamelStoreSummary *) groupwise_store->summary);
125         
126         /*host and user*/
127         priv->server_name = g_strdup (url->host);
128         priv->user = g_strdup (url->user);
129
130         /*base url*/
131         priv->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
132                                                        CAMEL_URL_HIDE_PARAMS   |
133                                                        CAMEL_URL_HIDE_AUTH)  );
134
135         /*soap port*/
136         property_value =  camel_url_get_param (url, "soap_port");
137         if (property_value == NULL)
138                 priv->port = g_strdup ("7191");
139         else if(strlen(property_value) == 0)
140                 priv->port = g_strdup ("7191");
141         else
142                 priv->port = g_strdup (property_value);
143
144         /*filter*/
145         if (camel_url_get_param (url, "filter")) 
146                 store->flags |= CAMEL_STORE_FILTER_INBOX;
147         
148         /*Hash Table*/  
149         priv->id_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
150         priv->name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
151         priv->parent_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
152
153         /*ssl*/
154         priv->use_ssl = g_strdup (camel_url_get_param (url, "use_ssl"));
155
156         store->flags &= ~CAMEL_STORE_VJUNK;
157         store->flags &= ~CAMEL_STORE_VTRASH;
158 }
159
160 static guint
161 groupwise_hash_folder_name (gconstpointer key)
162 {
163         return g_str_hash (key);
164 }
165
166 static gint
167 groupwise_compare_folder_name (gconstpointer a, gconstpointer b)
168 {
169         gconstpointer aname = a, bname = b;
170
171         return g_str_equal (aname, bname);
172 }
173
174 static gboolean
175 groupwise_auth_loop (CamelService *service, CamelException *ex)
176 {
177         CamelSession *session = camel_service_get_session (service);
178         CamelStore *store = CAMEL_STORE (service);
179         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
180         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
181         char *errbuf = NULL;
182         gboolean authenticated = FALSE;
183         char *uri;
184
185         if (priv->use_ssl && !g_str_equal (priv->use_ssl, "never")) 
186                 uri = g_strconcat ("https://", priv->server_name, ":", priv->port, "/soap", NULL);
187         else 
188                 uri = g_strconcat ("http://", priv->server_name, ":", priv->port, "/soap", NULL);
189         service->url->passwd = NULL;
190         
191
192         while (!authenticated) {
193                 if (errbuf) {
194                         /* We need to un-cache the password before prompting again */
195                         camel_session_forget_password (session, service, "Groupwise", "password", ex);
196                         g_free (service->url->passwd);
197                         service->url->passwd = NULL;
198                 }
199                 
200         
201                 if (!service->url->passwd && !(store->flags & CAMEL_STORE_PROXY)) {
202                         char *prompt;
203                         
204                         prompt = g_strdup_printf (_("%sPlease enter the GroupWise "
205                                                     "password for %s@%s"),
206                                                   errbuf ? errbuf : "",
207                                                   service->url->user,
208                                                   service->url->host);
209                         service->url->passwd =
210                                 camel_session_get_password (session, service, "Groupwise",
211                                                             prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex);
212                         g_free (prompt);
213                         g_free (errbuf);
214                         errbuf = NULL;
215                         
216                         if (!service->url->passwd) {
217                                 camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
218                                                      _("You did not enter a password."));
219                                 return FALSE;
220                         }
221                 }
222                 
223                 priv->cnc = e_gw_connection_new (uri, priv->user, service->url->passwd);
224                 if (!E_IS_GW_CONNECTION(priv->cnc) && priv->use_ssl && g_str_equal (priv->use_ssl, "when-possible")) {
225                         char *http_uri = g_strconcat ("http://", uri + 8, NULL);
226                         priv->cnc = e_gw_connection_new (http_uri, priv->user, service->url->passwd);
227                         g_free (http_uri);
228                 }
229                 if (!E_IS_GW_CONNECTION(priv->cnc)) {
230                         errbuf = g_strdup_printf (_("Unable to authenticate "
231                                             "to GroupWise server. "));
232                                                   
233                         camel_exception_clear (ex);
234                 } else 
235                         authenticated = TRUE;
236                 
237         }
238         
239         return TRUE;
240 }
241
242 static gboolean
243 check_for_connection (CamelService *service, CamelException *ex)
244 {
245         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (service);
246         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
247         struct addrinfo hints, *ai;
248
249         memset (&hints, 0, sizeof(hints));
250         hints.ai_socktype = SOCK_STREAM;
251         hints.ai_family = PF_UNSPEC;
252         ai = camel_getaddrinfo(priv->server_name, "groupwise", &hints, ex);
253         if (ai == NULL && priv->port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
254                 camel_exception_clear (ex);
255                 ai = camel_getaddrinfo(priv->server_name, priv->port, &hints, ex);
256         }
257         if (ai == NULL)
258                 return FALSE;
259
260         camel_freeaddrinfo (ai);
261
262         return TRUE;
263
264 }
265
266 static gboolean
267 groupwise_connect (CamelService *service, CamelException *ex)
268 {
269         CamelGroupwiseStore *store = CAMEL_GROUPWISE_STORE (service);
270         CamelGroupwiseStorePrivate *priv = store->priv;
271         CamelGroupwiseStoreNamespace *ns;
272         CamelSession *session = service->session;
273
274         d("in groupwise store connect\n");
275         
276 /*      if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL || 
277              (service->status == CAMEL_SERVICE_DISCONNECTED))
278                 return FALSE; */
279         if (service->status == CAMEL_SERVICE_DISCONNECTED)
280                 return FALSE;
281
282         if (!priv) {
283                 store->priv = g_new0 (CamelGroupwiseStorePrivate, 1);
284                 priv = store->priv;
285                 camel_service_construct (service, service->session, service->provider, service->url, ex);
286         }
287
288         CAMEL_SERVICE_REC_LOCK (service, connect_lock);
289         
290         if (priv->cnc) {
291                 CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
292                 return TRUE;
293         }
294
295         if (!check_for_connection (service, ex) || !groupwise_auth_loop (service, ex)) {
296                 CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
297                 camel_service_disconnect (service, TRUE, NULL);
298                 return FALSE;
299         }
300         
301         
302         service->status = CAMEL_SERVICE_CONNECTED;
303         ((CamelOfflineStore *) store)->state = CAMEL_OFFLINE_STORE_NETWORK_AVAIL;
304
305         if (!e_gw_connection_get_version (priv->cnc)) {
306                 camel_session_alert_user(session, 
307                                 CAMEL_SESSION_ALERT_WARNING, 
308                                 _("Some features may not work correctly with your current server version"),
309                                 FALSE);
310
311         }
312
313         ns = camel_groupwise_store_summary_namespace_new (store->summary, priv->storage_path, '/');
314         camel_groupwise_store_summary_namespace_set (store->summary, ns);
315
316         if (camel_store_summary_count ((CamelStoreSummary *)store->summary) == 0) {
317                 /*Settting the refresh stamp to the current time*/
318                 store->refresh_stamp = time (0);
319         }
320
321         camel_store_summary_save ((CamelStoreSummary *) store->summary);
322
323         CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
324         if (E_IS_GW_CONNECTION (priv->cnc)) {
325                 return TRUE;
326         }
327
328         return FALSE;
329
330 }
331 #if 0
332 static void
333 groupwise_disconnect_cleanup (CamelService *service, gboolean clean, CamelException *ex)
334 {
335         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (service);
336         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
337         
338         g_print ("camel_groupwise_store_finalize\n");
339         if (groupwise_store->summary) {
340                 camel_store_summary_save ((CamelStoreSummary *)groupwise_store->summary);
341                 camel_object_unref (groupwise_store->summary);
342         }
343         
344         if (priv) {
345                 if (priv->user) {
346                         g_free (priv->user);
347                         priv->user = NULL;
348                 }
349                 if (priv->server_name) {
350                         g_free (priv->server_name);
351                         priv->server_name = NULL;
352                 }
353                 if (priv->port) {
354                         g_free (priv->port);
355                         priv->port = NULL;
356                 }
357                 if (priv->use_ssl) {
358                         g_free (priv->use_ssl);
359                         priv->use_ssl = NULL;
360                 }
361                 if (priv->base_url) {
362                         g_free (priv->base_url);
363                         priv->base_url = NULL;
364                 }
365                 
366                 if (priv->storage_path)
367                         g_free(priv->storage_path);
368
369                 if(groupwise_store->root_container)
370                         g_free (groupwise_store->root_container);
371                 
372                 if (priv->id_hash)
373                         g_hash_table_destroy (priv->id_hash);
374
375                 if (priv->name_hash)
376                         g_hash_table_destroy (priv->name_hash);
377
378                 if (priv->parent_hash)
379                         g_hash_table_destroy (priv->parent_hash);
380
381                 g_free (groupwise_store->priv);
382                 groupwise_store->priv = NULL;
383         }
384 }
385 #endif
386
387 static gboolean
388 groupwise_disconnect (CamelService *service, gboolean clean, CamelException *ex)
389 {
390         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (service);
391         
392         if (clean) {
393                 CAMEL_SERVICE_REC_LOCK (groupwise_store, connect_lock);
394                 if (groupwise_store->priv && groupwise_store->priv->cnc) {
395                         g_object_unref (groupwise_store->priv->cnc);
396                         groupwise_store->priv->cnc = NULL;
397                 }
398                 CAMEL_SERVICE_REC_UNLOCK (groupwise_store, connect_lock);
399         }
400         
401         //groupwise_disconnect_cleanup (service, clean, ex);
402         return TRUE;
403 }
404
405 static  GList*
406 groupwise_store_query_auth_types (CamelService *service, CamelException *ex)
407 {
408         GList *auth_types = NULL;
409         
410         d("in query auth types\n");
411         auth_types = g_list_prepend (auth_types,  &camel_groupwise_password_authtype);
412         return auth_types;
413 }
414
415 static gboolean
416 groupwise_is_system_folder (const char *folder_name)
417 {
418         if (!strcmp (folder_name, "Mailbox") ||
419             !strcmp (folder_name, "Trash") ||
420             !strcmp (folder_name, "Junk Mail") ||
421             !strcmp (folder_name, "Sent Items") ||
422             !strcmp (folder_name, "Cabinet") ||
423             !strcmp (folder_name, "Documents") )
424                 return TRUE;
425         else
426                 return FALSE;
427 }
428
429 /*Build/populate CamelFolderInfo structure based on the imap_build_folder_info function*/
430 static CamelFolderInfo *
431 groupwise_build_folder_info(CamelGroupwiseStore *gw_store, const char *parent_name, const char *folder_name)
432 {
433         CamelURL *url;
434         const char *name;
435         CamelFolderInfo *fi;
436         CamelGroupwiseStorePrivate *priv = gw_store->priv;
437
438         fi = g_malloc0(sizeof(*fi));
439         
440         fi->unread = -1;
441         fi->total = -1;
442
443         if (parent_name) {
444                 if (strlen(parent_name) > 0) 
445                         fi->full_name = g_strconcat(parent_name, "/", folder_name, NULL);
446                 else
447                         fi->full_name = g_strdup (folder_name);
448         } else 
449                 fi->full_name = g_strdup(folder_name);
450  
451         url = camel_url_new(priv->base_url,NULL);
452         g_free(url->path);
453         url->path = g_strdup_printf("/%s", fi->full_name);
454         fi->uri = camel_url_to_string(url,CAMEL_URL_HIDE_ALL);
455         camel_url_free(url);
456
457         name = strrchr(fi->full_name,'/');
458         if(name == NULL)
459                 name = fi->full_name;
460         else
461                 name++;
462         if (!strcmp (folder_name, "Sent Items"))
463                 fi->flags |= CAMEL_FOLDER_TYPE_SENT;
464         else if (!strcmp (folder_name, "Mailbox"))
465                 fi->flags |= CAMEL_FOLDER_TYPE_INBOX;
466         else if (!strcmp (folder_name, "Trash"))
467                 fi->flags |= CAMEL_FOLDER_TYPE_TRASH;
468         else if (!strcmp (folder_name, "Junk Mail"))
469                 fi->flags |= CAMEL_FOLDER_TYPE_JUNK;
470                 
471         fi->name = g_strdup(name);
472         return fi;
473 }
474
475 static void
476 groupwise_forget_folder (CamelGroupwiseStore *gw_store, const char *folder_name, CamelException *ex)
477 {
478         CamelFolderSummary *summary;
479         CamelGroupwiseStorePrivate *priv = gw_store->priv;
480         char *summary_file, *state_file;
481         char *folder_dir, *storage_path;
482         CamelFolderInfo *fi;
483         const char *name;
484
485         
486         name = folder_name;
487
488         storage_path = g_strdup_printf ("%s/folders", priv->storage_path);
489         folder_dir = g_strdup(e_path_to_physical (storage_path,folder_name));
490
491         if (g_access(folder_dir, F_OK) != 0) {
492                 g_free(folder_dir);
493                 return;
494         }
495
496         summary_file = g_strdup_printf ("%s/summary", folder_dir);
497         summary = camel_groupwise_summary_new(NULL,summary_file);
498         if(!summary) {
499                 g_free(summary_file);
500                 g_free(folder_dir);
501                 return;
502         }
503
504         camel_object_unref (summary);
505         g_unlink (summary_file);
506         g_free (summary_file);
507
508
509         state_file = g_strdup_printf ("%s/cmeta", folder_dir);
510         g_unlink (state_file);
511         g_free (state_file);
512
513         g_rmdir (folder_dir);
514         g_free (folder_dir);
515
516         camel_store_summary_remove_path ( (CamelStoreSummary *)gw_store->summary, folder_name);
517         camel_store_summary_save ( (CamelStoreSummary *)gw_store->summary);
518
519         fi = groupwise_build_folder_info(gw_store, NULL, folder_name);
520         camel_object_trigger_event (CAMEL_OBJECT (gw_store), "folder_deleted", fi);
521         camel_folder_info_free (fi);
522 }
523
524 static CamelFolder *
525 groupwise_get_folder_from_disk (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
526 {
527         CamelGroupwiseStore *gw_store = CAMEL_GROUPWISE_STORE (store);
528         CamelGroupwiseStorePrivate *priv = gw_store->priv;
529         CamelFolder *folder;
530         char *folder_dir, *storage_path;
531
532         storage_path = g_strdup_printf("%s/folders", priv->storage_path);
533         folder_dir = e_path_to_physical (storage_path, folder_name);
534         g_free(storage_path);
535         if (!folder_dir || g_access (folder_dir, F_OK) != 0) {
536                 g_free (folder_dir);
537                 camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
538                                 _("No such folder %s"), folder_name);
539                 return NULL;
540         }
541
542         folder = camel_gw_folder_new (store, folder_name, folder_dir, ex);
543         g_free (folder_dir);
544
545         return folder;
546 }
547
548 static CamelFolder * 
549 groupwise_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
550 {
551         CamelGroupwiseStore *gw_store = CAMEL_GROUPWISE_STORE (store);
552         CamelGroupwiseStorePrivate *priv = gw_store->priv;
553         CamelFolder *folder;
554         CamelGroupwiseSummary *summary;
555         char *container_id, *folder_dir, *storage_path;
556         EGwConnectionStatus status;
557         GList *list = NULL;
558         gboolean done = FALSE, all_ok = TRUE;
559         const char *position = E_GW_CURSOR_POSITION_END; 
560         int count = 0, cursor, summary_count = 0;
561         CamelStoreInfo *si = NULL;
562         guint total = 0;
563         
564         folder = groupwise_get_folder_from_disk (store, folder_name, flags, ex);
565         if (folder) {
566                 camel_object_ref (folder);
567                 return folder;
568         }
569
570         camel_exception_clear (ex);
571
572         CAMEL_SERVICE_REC_LOCK (gw_store, connect_lock);
573
574         if (!camel_groupwise_store_connected ((CamelGroupwiseStore *)store, ex)) {
575                 CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
576                 return NULL;
577         }
578         
579         if (gw_store->current_folder) {
580                 camel_object_unref (gw_store->current_folder);
581                 gw_store->current_folder = NULL;
582         }
583
584         if (!E_IS_GW_CONNECTION( priv->cnc)) {
585                 if (!groupwise_connect (CAMEL_SERVICE(store), ex)) {
586                         camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, _("Authentication failed"));
587                         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
588                         return NULL;
589                 }
590         }
591
592         container_id =  g_strdup (g_hash_table_lookup (priv->name_hash, folder_name));
593
594
595         storage_path = g_strdup_printf("%s/folders", priv->storage_path);
596         folder_dir = e_path_to_physical (storage_path, folder_name);
597         g_free(storage_path);
598         folder = camel_gw_folder_new (store, folder_name, folder_dir, ex);
599         if (!folder) {
600                 CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
601                 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Authentication failed"));
602                 g_free (folder_dir);
603                 g_free (container_id);
604                 return NULL;
605         }
606         g_free (folder_dir);
607         
608         si = camel_store_summary_path ((CamelStoreSummary *)gw_store->summary, folder_name);
609         if (si) {
610                 total = si->total;
611                 camel_store_summary_info_free ((CamelStoreSummary *)(gw_store)->summary, si);
612         }
613
614         summary = (CamelGroupwiseSummary *) folder->summary;
615
616         summary_count = camel_folder_summary_count (folder->summary);
617         if(!summary_count || !summary->time_string) {
618                 d(g_print ("\n\n** %s **: No summary as yet : using get cursor request\n\n", folder->name);)
619
620                 status = e_gw_connection_create_cursor (priv->cnc, container_id, 
621                                 "peek id recipient attachments distribution subject status options priority startDate created delivered size hasAttachment",
622                                 NULL,
623                                 &cursor);
624                 if (status != E_GW_CONNECTION_STATUS_OK) {
625                         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
626                         g_free (container_id);
627                         return NULL;
628                 }
629
630                 camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
631                 camel_folder_summary_clear (folder->summary);
632
633                 while (!done) {
634                         status = e_gw_connection_read_cursor (priv->cnc, container_id, 
635                                                               cursor, FALSE, 
636                                                               CURSOR_ITEM_LIMIT, position, &list);
637                         if (status != E_GW_CONNECTION_STATUS_OK) {
638                                 all_ok = FALSE;
639                                 break;
640                                 /*
641                                 CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
642                                 e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
643                                 //camel_folder_summary_clear (folder->summary);
644                                 camel_folder_summary_save (folder->summary);
645                                 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Authentication failed"));
646                                 camel_operation_end (NULL);
647                                 camel_object_unref (folder);
648                                 g_free (container_id);
649                                 return NULL;*/
650                         }
651                         
652                         count += g_list_length (list);
653                 
654                         if (total > 0)
655                                 camel_operation_progress (NULL, (100*count)/total);
656                         gw_update_summary (folder, list,  ex);
657                         
658                         if (!list)
659                                 done = TRUE;
660                         g_list_foreach (list, (GFunc)g_object_unref, NULL);
661                         g_list_free (list);
662                         list = NULL;
663                         position = E_GW_CURSOR_POSITION_CURRENT;
664                 }
665
666                 e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
667
668                 camel_operation_end (NULL);
669         } 
670         if (done && all_ok) {
671                 if (summary->time_string)
672                         g_free (summary->time_string);
673                 summary->time_string = g_strdup (e_gw_connection_get_server_time (priv->cnc));
674         }
675
676         camel_folder_summary_save (folder->summary);
677
678         gw_store->current_folder = folder;
679         camel_object_ref (folder);
680
681         g_free (container_id);
682         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
683
684         return folder;
685 }
686
687 void 
688 gw_store_reload_folder (CamelGroupwiseStore *gw_store, CamelFolder *folder, guint32 flags, CamelException *ex)
689 {
690         CamelGroupwiseStorePrivate *priv = gw_store->priv;
691         CamelGroupwiseSummary *summary;
692         char *container_id;
693         EGwConnectionStatus status;
694         GList *list = NULL;
695         gboolean done = FALSE;
696         const char *position = E_GW_CURSOR_POSITION_END; 
697         int count = 0, cursor, summary_count = 0;
698         CamelStoreInfo *si = NULL;
699         guint total = 0;
700         
701         camel_exception_clear (ex);
702
703         CAMEL_SERVICE_REC_LOCK (gw_store, connect_lock);
704
705         if (!camel_groupwise_store_connected (gw_store, ex)) {
706                 CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
707                 return;
708         }
709         
710         if (!E_IS_GW_CONNECTION( priv->cnc)) {
711                 if (!groupwise_connect (CAMEL_SERVICE((CamelStore*)gw_store), ex)) {
712                         camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, _("Authentication failed"));
713                         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
714                         return;
715                 }
716         }
717         
718         container_id =  g_strdup (g_hash_table_lookup (priv->name_hash, folder->full_name));
719
720         si = camel_store_summary_path ((CamelStoreSummary *)gw_store->summary, folder->name);
721         if (si) {
722                 total = si->total;
723                 camel_store_summary_info_free ((CamelStoreSummary *)(gw_store)->summary, si);
724         }
725
726         summary = (CamelGroupwiseSummary *) folder->summary;
727         camel_folder_summary_clear (folder->summary);
728         camel_folder_summary_save (folder->summary);
729
730         summary_count = camel_folder_summary_count (folder->summary);
731         if(!summary_count || !summary->time_string) {
732                 d(g_print ("\n\n** %s **: Summary missing???? Reloading summary....\n\n", folder->name);)
733
734                 status = e_gw_connection_create_cursor (priv->cnc, container_id, 
735                                 "peek id recipient attachments distribution subject status options priority startDate created delivered size hasAttachment",
736                                 NULL,
737                                 &cursor);
738                 if (status != E_GW_CONNECTION_STATUS_OK) {
739                         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
740                         g_free (container_id);
741                         return;
742                 }
743
744                 camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
745
746                 while (!done) {
747                         status = e_gw_connection_read_cursor (priv->cnc, container_id, 
748                                                               cursor, FALSE, 
749                                                               CURSOR_ITEM_LIMIT, position, &list);
750                         if (status != E_GW_CONNECTION_STATUS_OK) {
751                                 CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
752                                 e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
753                                 camel_folder_summary_save (folder->summary);
754                                 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Authentication failed"));
755                                 camel_operation_end (NULL);
756                                 g_free (container_id);
757                                 return;
758                         }
759                         
760                         count += g_list_length (list);
761                 
762                         if (total > 0)
763                                 camel_operation_progress (NULL, (100*count)/total);
764                         gw_update_summary (folder, list,  ex);
765                         
766                         if (!list)
767                                 done = TRUE;
768                         g_list_foreach (list, (GFunc)g_object_unref, NULL);
769                         g_list_free (list);
770                         list = NULL;
771                         position = E_GW_CURSOR_POSITION_CURRENT;
772                 }
773
774                 e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
775
776                 camel_operation_end (NULL);
777         } 
778
779         if (done) {
780                 if (summary->time_string)
781                         g_free (summary->time_string);
782                 summary->time_string = g_strdup (e_gw_connection_get_server_time (priv->cnc));
783         }
784
785         camel_folder_summary_save (folder->summary);
786
787         gw_store->current_folder = folder;
788         
789         g_free (container_id);
790         CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
791         return;
792 }
793
794 CamelFolderInfo *
795 convert_to_folder_info (CamelGroupwiseStore *store, EGwContainer *container, const char *url, CamelException *ex)
796 {
797         const char *name = NULL, *id = NULL, *parent = NULL;
798         char *par_name = NULL;
799         CamelFolderInfo *fi;
800         CamelGroupwiseStoreInfo *si = NULL;
801         CamelGroupwiseStorePrivate *priv = store->priv;
802         EGwContainerType type;
803
804         name = e_gw_container_get_name (container);
805         id = e_gw_container_get_id (container);
806         type = e_gw_container_get_container_type (container);
807                 
808         fi = g_new0 (CamelFolderInfo, 1);
809
810         if (type == E_GW_CONTAINER_TYPE_INBOX)
811                 fi->flags |= CAMEL_FOLDER_TYPE_INBOX;
812         if (type == E_GW_CONTAINER_TYPE_TRASH)
813                 fi->flags |= CAMEL_FOLDER_TYPE_TRASH;
814         if (type == E_GW_CONTAINER_TYPE_SENT)
815                 fi->flags |= CAMEL_FOLDER_TYPE_SENT;
816
817         if ( (type == E_GW_CONTAINER_TYPE_INBOX) ||
818                 (type == E_GW_CONTAINER_TYPE_SENT) ||
819                 (type == E_GW_CONTAINER_TYPE_DOCUMENTS) ||
820                 (type == E_GW_CONTAINER_TYPE_QUERY) ||
821                 (type == E_GW_CONTAINER_TYPE_CHECKLIST) ||
822                 (type == E_GW_CONTAINER_TYPE_DRAFT) ||
823                 (type == E_GW_CONTAINER_TYPE_CABINET) ||
824                 (type == E_GW_CONTAINER_TYPE_JUNK) ||
825                 (type == E_GW_CONTAINER_TYPE_TRASH) ) 
826                 fi->flags |= CAMEL_FOLDER_SYSTEM;
827         /*
828            parent_hash contains the "parent id <-> container id" combination. So we form
829            the path for the full name in camelfolder info by looking up the hash table until
830            NULL is found
831          */
832
833         parent = e_gw_container_get_parent_id (container);
834         par_name = g_hash_table_lookup (priv->id_hash, parent);
835
836         if (par_name != NULL) {
837                 gchar *temp_parent = NULL, *temp = NULL;
838                 gchar *str = g_strconcat (par_name, "/", name, NULL);
839
840                 fi->name = g_strdup (name);
841
842                 temp_parent = g_hash_table_lookup (priv->parent_hash, parent);
843                 while (temp_parent) {
844                         temp = g_hash_table_lookup (priv->id_hash, temp_parent );
845                         if (temp == NULL) {
846                                 break;
847                         }       
848                         str = g_strconcat ( temp, "/", str, NULL);
849
850                         temp_parent = g_hash_table_lookup (priv->parent_hash, temp_parent);
851
852                 } 
853                 fi->full_name = g_strdup (str);
854                 fi->uri = g_strconcat (url, str, NULL);
855                 g_free (str);
856         }
857         else {
858                 fi->name =  g_strdup (name);
859                 fi->full_name = g_strdup (name);
860                 fi->uri = g_strconcat (url, "", name, NULL);
861         }
862
863         si = camel_groupwise_store_summary_add_from_full (store->summary, fi->full_name, '/');
864         if (si == NULL) {
865                 camel_folder_info_free (fi);
866                 return NULL;
867         }
868
869         /*name_hash returns the container id given the name */
870         g_hash_table_insert (priv->name_hash, g_strdup(fi->full_name), g_strdup(id));
871
872         if (e_gw_container_get_is_shared_to_me (container))
873                 fi->flags |= CAMEL_FOLDER_SHARED_TO_ME;
874
875         if (e_gw_container_get_is_shared_by_me (container))
876                 fi->flags |= CAMEL_FOLDER_SHARED_BY_ME;
877
878         fi->total = e_gw_container_get_total_count (container);
879         fi->unread = e_gw_container_get_unread_count (container);
880
881         si->info.total = fi->total;
882         si->info.unread = fi->unread;
883         si->info.flags = fi->flags;
884         /*refresh info*/
885         if (store->current_folder 
886             && !strcmp (store->current_folder->full_name, fi->full_name)
887             && type != E_GW_CONTAINER_TYPE_INBOX) {
888                 CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (store->current_folder))->refresh_info(store->current_folder, ex);
889         }
890         return fi;
891 }
892
893 static void
894 get_folders_free (void *k, void *v, void *d)
895 {
896         CamelFolderInfo *fi = v;
897         camel_folder_info_free (fi);
898 }
899
900 static void
901 groupwise_folders_sync (CamelGroupwiseStore *store, CamelException *ex)
902 {
903         CamelGroupwiseStorePrivate  *priv = store->priv;
904         int status;
905         GList *folder_list = NULL, *temp_list = NULL, *list = NULL;
906         char *url, *temp_url;
907         CamelFolderInfo *info = NULL, *hfi = NULL;
908         GHashTable *present;
909         CamelStoreInfo *si = NULL;
910         int count, i;
911
912         if (!priv->cnc && ((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL) {
913                 if (((CamelService *)store)->status == CAMEL_SERVICE_DISCONNECTED){
914                         ((CamelService *)store)->status = CAMEL_SERVICE_CONNECTING;
915                         groupwise_connect ((CamelService *)store, ex);
916                 }
917         }
918
919         status = e_gw_connection_get_container_list (priv->cnc, "folders", &folder_list);
920         if (status != E_GW_CONNECTION_STATUS_OK) {
921                 g_warning ("Could not get folder list..\n");
922                 return;
923         }
924
925         temp_list = folder_list;
926         list = folder_list;
927
928         url = camel_url_to_string (CAMEL_SERVICE(store)->url,
929                                    (CAMEL_URL_HIDE_PASSWORD|
930                                     CAMEL_URL_HIDE_PARAMS|
931                                     CAMEL_URL_HIDE_AUTH) );
932
933         if ( url[strlen(url) - 1] != '/') {
934                 temp_url = g_strconcat (url, "/", NULL);
935                 g_free ((char *)url);
936                 url = temp_url;
937         }
938         
939         /*populate the hash table for finding the mapping from container id <-> folder name*/
940         for (;temp_list != NULL ; temp_list = g_list_next (temp_list) ) {
941                 const char *name, *id, *parent;
942                 name = e_gw_container_get_name (E_GW_CONTAINER (temp_list->data));
943                 id = e_gw_container_get_id(E_GW_CONTAINER(temp_list->data));
944                 parent = e_gw_container_get_parent_id (E_GW_CONTAINER(temp_list->data));
945
946                 if (e_gw_container_is_root (E_GW_CONTAINER(temp_list->data))) {
947                         store->root_container = g_strdup (id);
948                         continue;
949                 }
950
951                 /*id_hash returns the name for a given container id*/
952                 g_hash_table_insert (priv->id_hash, g_strdup(id), g_strdup(name)); 
953                 /*parent_hash returns the parent container id, given an id*/
954                 g_hash_table_insert (priv->parent_hash, g_strdup(id), g_strdup(parent));
955         }
956
957         present = g_hash_table_new (g_str_hash, g_str_equal);
958
959         for (;folder_list != NULL; folder_list = g_list_next (folder_list)) {
960                 EGwContainerType type;
961                 EGwContainer *container = E_GW_CONTAINER (folder_list->data);
962                 
963                 type = e_gw_container_get_container_type (container);
964
965                 if (e_gw_container_is_root(container))
966                         continue;
967                 if ( (type == E_GW_CONTAINER_TYPE_CALENDAR) || (type == E_GW_CONTAINER_TYPE_CONTACTS) )
968                         continue;
969
970                 info = convert_to_folder_info (store, E_GW_CONTAINER (folder_list->data), (const char *)url, ex);
971                 if (info) {
972                         hfi = g_hash_table_lookup (present, info->full_name);
973                         if (hfi == NULL)
974                                 g_hash_table_insert (present, info->full_name, info);
975                         else {
976                                 camel_folder_info_free (info);
977                                 info = NULL;
978                         }
979                 }
980         }
981         
982         g_free ((char *)url);
983         e_gw_connection_free_container_list (list);
984         count = camel_store_summary_count ((CamelStoreSummary *)store->summary);
985
986         count = camel_store_summary_count ((CamelStoreSummary *)store->summary);
987         for (i=0;i<count;i++) {
988                 si = camel_store_summary_index ((CamelStoreSummary *)store->summary, i);
989                 if (si == NULL)
990                         continue;
991
992                 info = g_hash_table_lookup (present, camel_store_info_path (store->summary, si));
993                 if (info != NULL) {
994                         camel_store_summary_touch ((CamelStoreSummary *)store->summary);
995                 } else {
996                         camel_store_summary_remove ((CamelStoreSummary *)store->summary, si);
997                         count--;
998                         i--;
999                 }
1000                 camel_store_summary_info_free ((CamelStoreSummary *)store->summary, si);
1001         }
1002
1003         g_hash_table_foreach (present, get_folders_free, NULL);
1004         g_hash_table_destroy (present);
1005 }
1006
1007 static CamelFolderInfo *
1008 groupwise_get_folder_info_offline (CamelStore *store, const char *top,
1009                          guint32 flags, CamelException *ex)
1010 {
1011         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1012         CamelFolderInfo *fi;
1013         GPtrArray *folders;
1014         char *path, *name;
1015         int i;
1016
1017         folders = g_ptr_array_new ();
1018
1019         if (top == NULL)
1020                 top = "";
1021
1022         /* get starting point */
1023         if (top[0] == 0) {
1024                         name = g_strdup("");
1025         } else {
1026                 name = camel_groupwise_store_summary_full_from_path(groupwise_store->summary, top);
1027                 if (name == NULL)
1028                         name = camel_groupwise_store_summary_path_to_full(groupwise_store->summary, top, '/');
1029         }
1030
1031         path = gw_concat (name, "*");
1032
1033         for (i=0;i<camel_store_summary_count((CamelStoreSummary *)groupwise_store->summary);i++) {
1034                 CamelStoreInfo *si = camel_store_summary_index((CamelStoreSummary *)groupwise_store->summary, i);
1035
1036                 if (si == NULL) 
1037                         continue;
1038                 
1039                 if ( !strcmp(name, camel_groupwise_store_info_full_name (groupwise_store->summary, si))
1040                      || match_path (path, camel_groupwise_store_info_full_name (groupwise_store->summary, si))) {
1041                         fi = groupwise_build_folder_info(groupwise_store, NULL, camel_store_info_path((CamelStoreSummary *)groupwise_store->summary, si));
1042                         fi->unread = si->unread;
1043                         fi->total = si->total;
1044                         fi->flags = si->flags;
1045                         g_ptr_array_add (folders, fi);
1046                 }
1047                 camel_store_summary_info_free((CamelStoreSummary *)groupwise_store->summary, si);
1048         }
1049
1050         g_free(name);
1051         g_free (path);
1052         fi = camel_folder_info_build (folders, top, '/', TRUE);
1053         g_ptr_array_free (folders, TRUE);
1054         return fi;
1055 }
1056
1057 /*** Thread stuff for refreshing folder tree begins ***/
1058 struct _store_refresh_msg {
1059         CamelSessionThreadMsg msg;
1060
1061         CamelStore *store;
1062         CamelException ex;
1063 };
1064
1065 #if 0
1066 static void
1067 store_refresh_refresh (CamelSession *session, CamelSessionThreadMsg *msg)
1068 {
1069         struct _store_refresh_msg *m = (struct _store_refresh_msg *)msg;
1070         CamelGroupwiseStore *groupwise_store = (CamelGroupwiseStore *)m->store;
1071         
1072         CAMEL_SERVICE_REC_LOCK (m->store, connect_lock);
1073         if (!camel_groupwise_store_connected ((CamelGroupwiseStore *)m->store, &m->ex))
1074                 goto done;
1075         /*Get the folder list and save it here*/
1076         groupwise_folders_sync (groupwise_store, &m->ex);
1077         if (camel_exception_is_set (&m->ex))
1078                 goto done;
1079         camel_store_summary_save ((CamelStoreSummary *)groupwise_store->summary);
1080 done:
1081         CAMEL_SERVICE_REC_UNLOCK (m->store, connect_lock);
1082 }
1083
1084 static void
1085 store_refresh_free(CamelSession *session, CamelSessionThreadMsg *msg)
1086 {
1087         struct _store_refresh_msg *m = (struct _store_refresh_msg *)msg;
1088
1089         camel_object_unref (m->store);
1090         camel_exception_clear (&m->ex);
1091 }
1092
1093 static CamelSessionThreadOps store_refresh_ops = {
1094         store_refresh_refresh,
1095         store_refresh_free,
1096 };
1097 #endif
1098
1099 /*** Thread stuff ends ***/
1100
1101 static CamelFolderInfo *
1102 groupwise_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
1103 {
1104         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1105         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
1106         CamelFolderInfo *info = NULL;
1107         char *top_folder = NULL;
1108         
1109         if (top) {
1110                 top_folder = g_hash_table_lookup (priv->name_hash, top);
1111                 /* 'top' is a valid path, but doesnt have a container id
1112                  *  return NULL */
1113 /*              if (!top_folder) {
1114                         camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
1115                                         _("You must be working online to complete this operation"));
1116                         return NULL;
1117                 }*/
1118         }
1119
1120         if (top && groupwise_is_system_folder (top)) 
1121                 return groupwise_build_folder_info (groupwise_store, NULL, top );
1122
1123         /*
1124          * Thanks to Michael, for his cached folders implementation in IMAP
1125          * is used as is here.
1126          */
1127         if (camel_store_summary_count ((CamelStoreSummary *)groupwise_store->summary) == 0) {
1128                 CAMEL_SERVICE_REC_LOCK (store, connect_lock);
1129                 if (groupwise_store->list_loaded == 3) {
1130                         groupwise_folders_sync (groupwise_store, ex);
1131                         groupwise_store->list_loaded -= 1;
1132                 }
1133                 if (camel_exception_is_set (ex)) {
1134                         camel_store_summary_save ((CamelStoreSummary *) groupwise_store->summary);
1135                         CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1136                         return NULL;
1137                 }
1138                 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1139                 camel_store_summary_save ((CamelStoreSummary *)groupwise_store->summary);
1140                 goto end_r;
1141         }
1142
1143         if ((camel_store_summary_count((CamelStoreSummary *)groupwise_store->summary) > 0) && (groupwise_store->list_loaded > 1)) {
1144                 /*Load from cache*/
1145                 groupwise_store->list_loaded -= 1;
1146                 goto end_r;
1147         }
1148
1149         CAMEL_SERVICE_REC_LOCK (store, connect_lock);
1150         if ((groupwise_store->list_loaded == 1) && check_for_connection((CamelService *)store, ex)) {
1151                 if (!priv->cnc) {
1152                         if (groupwise_connect ((CamelService *)store, ex)) {
1153                                 g_warning ("Could connect!!!\n");
1154                         } else 
1155                                 g_warning ("Could not connect..failure connecting\n");
1156                 }
1157                 if (camel_groupwise_store_connected ((CamelGroupwiseStore *)store, ex)) {
1158                         if (groupwise_store->current_folder)
1159                                 CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (groupwise_store->current_folder))->sync(groupwise_store->current_folder, FALSE, ex);
1160                         groupwise_folders_sync (groupwise_store, ex);
1161                         if (camel_exception_is_set (ex)) {
1162                                 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1163                                 return NULL;
1164                         }
1165                         camel_store_summary_touch ((CamelStoreSummary *)groupwise_store->summary);
1166                         camel_store_summary_save ((CamelStoreSummary *)groupwise_store->summary);
1167                 }
1168         }
1169         CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1170
1171         /*camel_exception_clear (ex);*/
1172 end_r:
1173         info = groupwise_get_folder_info_offline (store, top, flags, ex);
1174         return info;
1175 }
1176
1177 /* To create a junk mail folder in case  we want it and it isn't there*/
1178 CamelFolderInfo *
1179 create_junk_folder (CamelStore *store)
1180 {
1181         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1182         CamelGroupwiseStorePrivate  *priv = groupwise_store->priv;
1183         CamelFolderInfo *root = NULL;
1184         char *parent_name, *folder_name, *child_container_id, *parent_id;
1185         int status;
1186
1187         parent_name = "";
1188         folder_name = "Junk Mail";
1189         parent_id = "";
1190         /* TODO: check for offlining*/
1191                 
1192         CAMEL_SERVICE_REC_LOCK (store, connect_lock);
1193         status = e_gw_connection_modify_junk_settings (priv->cnc, JUNK_ENABLE, 0, 0,  JUNK_PERSISTENCE);
1194         if (status == E_GW_CONNECTION_STATUS_OK) {
1195                 root = groupwise_build_folder_info(groupwise_store, parent_name, folder_name);
1196                 camel_store_summary_save((CamelStoreSummary *)groupwise_store->summary);
1197                 
1198                 child_container_id = e_gw_connection_get_container_id (priv->cnc, "Junk Mail");
1199                 if (!child_container_id)
1200                         g_warning("failed to retrieve id for junk folder");
1201                 
1202                 g_hash_table_insert (priv->id_hash, g_strdup(child_container_id), g_strdup(folder_name)); 
1203                 g_hash_table_insert (priv->name_hash, g_strdup(folder_name), g_strdup(child_container_id));
1204                 g_hash_table_insert (priv->parent_hash, g_strdup(child_container_id), g_strdup(parent_id));
1205                 camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
1206         }
1207         CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1208
1209         return root;
1210 }
1211
1212 static CamelFolderInfo*
1213 groupwise_create_folder(CamelStore *store,
1214                 const char *parent_name,
1215                 const char *folder_name,
1216                 CamelException *ex)
1217 {
1218         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1219         CamelGroupwiseStorePrivate  *priv = groupwise_store->priv;
1220         CamelFolderInfo *root = NULL;
1221         char *parent_id , *child_container_id;
1222         int status;
1223
1224         if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
1225                 camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create GroupWise folders in offline mode."));
1226                 return NULL;
1227         }
1228         
1229         if(parent_name == NULL) {
1230                 parent_name = "";
1231                 if (groupwise_is_system_folder (folder_name)) {
1232                         camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, NULL);
1233                         return NULL;
1234                 }
1235         }
1236
1237         if (parent_name && (strlen(parent_name) > 0) ) {
1238                 if (strcmp (parent_name, "Cabinet") && groupwise_is_system_folder (parent_name)) {
1239                         camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE, _("The parent folder is not allowed to contain subfolders"));
1240                         return NULL;
1241                 }
1242                 parent_id = g_hash_table_lookup (priv->name_hash, parent_name);
1243         } else
1244                 parent_id = "";
1245
1246         if (!E_IS_GW_CONNECTION( priv->cnc)) {
1247                 if (!groupwise_connect (CAMEL_SERVICE(store), ex)) {
1248                         camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, _("Authentication failed"));
1249                         return NULL;
1250                 }
1251         }
1252         CAMEL_SERVICE_REC_LOCK (store, connect_lock);
1253         status = e_gw_connection_create_folder(priv->cnc,parent_id,folder_name, &child_container_id);
1254         if (status == E_GW_CONNECTION_STATUS_OK) {
1255                 root = groupwise_build_folder_info(groupwise_store, parent_name,folder_name);
1256                 camel_store_summary_save((CamelStoreSummary *)groupwise_store->summary);
1257
1258                 g_hash_table_insert (priv->id_hash, g_strdup(child_container_id), g_strdup(folder_name)); 
1259                 g_hash_table_insert (priv->name_hash, g_strdup(root->full_name), g_strdup(child_container_id));
1260                 g_hash_table_insert (priv->parent_hash, g_strdup(child_container_id), g_strdup(parent_id));
1261
1262                 camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
1263         }
1264         CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1265         return root;
1266 }
1267
1268 static void 
1269 groupwise_delete_folder(CamelStore *store,
1270                                    const char *folder_name,
1271                                    CamelException *ex)
1272 {
1273         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1274         CamelGroupwiseStorePrivate  *priv = groupwise_store->priv;
1275         EGwConnectionStatus status;
1276         const char * container; 
1277         
1278         CAMEL_SERVICE_REC_LOCK (store, connect_lock);
1279         
1280         if (!camel_groupwise_store_connected ((CamelGroupwiseStore *)store, ex)) {
1281                 CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1282                 return;
1283         }
1284
1285         container = g_hash_table_lookup (priv->name_hash, folder_name);
1286
1287         status = e_gw_connection_remove_item (priv->cnc, container, container);
1288
1289         if (status == E_GW_CONNECTION_STATUS_OK) {
1290                 if (groupwise_store->current_folder)
1291                         camel_object_unref (groupwise_store->current_folder);
1292
1293                 groupwise_forget_folder(groupwise_store,folder_name,ex);
1294
1295                 g_hash_table_remove (priv->id_hash, container);
1296                 g_hash_table_remove (priv->name_hash, folder_name);
1297                 
1298                 g_hash_table_remove (priv->parent_hash, container);
1299         }
1300         CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
1301 }
1302
1303 static void 
1304 groupwise_rename_folder(CamelStore *store,
1305                         const char *old_name,
1306                         const char *new_name,
1307                         CamelException *ex)
1308 {
1309         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (store);
1310         CamelGroupwiseStorePrivate  *priv = groupwise_store->priv;
1311         char *oldpath, *newpath, *storepath;
1312         const char *container_id;
1313         char *temp_new = NULL;
1314         
1315         if (groupwise_is_system_folder (old_name)) {
1316                 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename Groupwise folder `%s' to `%s'"),
1317                                       old_name, new_name);
1318                 return;
1319         }
1320
1321         CAMEL_SERVICE_REC_LOCK (groupwise_store, connect_lock);
1322         
1323         if (!camel_groupwise_store_connected ((CamelGroupwiseStore *)store, ex)) {
1324                 CAMEL_SERVICE_REC_UNLOCK (groupwise_store, connect_lock);
1325                 return;
1326         }
1327         
1328         container_id = camel_groupwise_store_container_id_lookup (groupwise_store, old_name);
1329         temp_new = strrchr (new_name, '/');
1330         if (temp_new) 
1331                 temp_new++;
1332         else
1333                 temp_new = (char *)new_name;
1334         
1335         if (!container_id || e_gw_connection_rename_folder (priv->cnc, container_id , temp_new) != E_GW_CONNECTION_STATUS_OK)
1336         {
1337                 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename Groupwise folder `%s' to `%s'"),
1338                                       old_name, new_name);
1339                 CAMEL_SERVICE_REC_UNLOCK (groupwise_store, connect_lock);
1340                 return;
1341         }
1342
1343         g_hash_table_replace (priv->id_hash, g_strdup(container_id), g_strdup(temp_new));
1344
1345         g_hash_table_insert (priv->name_hash, g_strdup(new_name), g_strdup(container_id));
1346         g_hash_table_remove (priv->name_hash, old_name);
1347         /*FIXME:Update all the id in the parent_hash*/
1348
1349         storepath = g_strdup_printf ("%s/folders", priv->storage_path);
1350         oldpath = e_path_to_physical (storepath, old_name);
1351         newpath = e_path_to_physical (storepath, new_name);
1352         g_free (storepath);
1353
1354         /*XXX: make sure the summary is also renamed*/
1355         if (g_rename (oldpath, newpath) == -1) {
1356                 g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
1357                                 oldpath, newpath, strerror (errno));
1358         }
1359
1360         g_free (oldpath);
1361         g_free (newpath);
1362         CAMEL_SERVICE_REC_UNLOCK (groupwise_store, connect_lock);
1363 }
1364
1365 char * 
1366 groupwise_get_name(CamelService *service, gboolean brief) 
1367 {
1368         if(brief) 
1369                 return g_strdup_printf(_("GroupWise server %s"), service->url->host);
1370         else
1371                 return g_strdup_printf(_("GroupWise service for %s on %s"), 
1372                                        service->url->user, service->url->host);
1373 }
1374
1375 const char *
1376 camel_groupwise_store_container_id_lookup (CamelGroupwiseStore *gw_store, const char *folder_name)
1377 {
1378         CamelGroupwiseStorePrivate *priv = gw_store->priv;
1379
1380         return g_hash_table_lookup (priv->name_hash, folder_name);
1381 }
1382
1383 const char *
1384 camel_groupwise_store_folder_lookup (CamelGroupwiseStore *gw_store, const char *container_id)
1385 {
1386         CamelGroupwiseStorePrivate *priv = gw_store->priv;
1387
1388         return g_hash_table_lookup (priv->id_hash, container_id);
1389 }
1390
1391
1392 EGwConnection *
1393 cnc_lookup (CamelGroupwiseStorePrivate *priv)
1394 {
1395         return priv->cnc;
1396 }
1397
1398 char *
1399 storage_path_lookup (CamelGroupwiseStorePrivate *priv)
1400 {
1401         return priv->storage_path;
1402 }
1403
1404 const char *
1405 groupwise_base_url_lookup (CamelGroupwiseStorePrivate *priv)
1406 {
1407         return priv->base_url;
1408 }
1409
1410 static CamelFolder *
1411 groupwise_get_trash (CamelStore *store, CamelException *ex)
1412 {
1413         CamelFolder *folder = camel_store_get_folder(store, "Trash", 0, ex);
1414         if (folder) {
1415                  char *state = g_build_filename(((CamelGroupwiseStore *)store)->priv->storage_path, "folders", "Trash", "cmeta", NULL);
1416
1417                 camel_object_set(folder, NULL, CAMEL_OBJECT_STATE_FILE, state, NULL);
1418                 g_free(state);
1419                 camel_object_state_read(folder);
1420
1421                 return folder;
1422         } else 
1423                 return NULL;
1424 }
1425
1426 /*
1427  * Function to check if we are both connected and are _actually_
1428  * online. Based on an equivalient function in IMAP
1429  */ 
1430 gboolean
1431 camel_groupwise_store_connected (CamelGroupwiseStore *store, CamelException *ex)
1432 {
1433         if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_AVAIL
1434             && camel_service_connect ((CamelService *)store, ex)) {
1435                 return TRUE;
1436         }
1437         /*Not online, so return FALSE*/
1438         return FALSE;
1439 }
1440
1441 static int 
1442 match_path(const char *path, const char *name)
1443 {
1444         char p, n;
1445
1446         p = *path++;
1447         n = *name++;
1448         while (n && p) {
1449                 if (n == p) {
1450                         p = *path++;
1451                         n = *name++;
1452                 } else if (p == '%') {
1453                         if (n != '/') {
1454                                 n = *name++;
1455                         } else {
1456                                 p = *path++;
1457                         }
1458                 } else if (p == '*') {
1459                         return TRUE;
1460                 } else
1461                         return FALSE;
1462         }
1463
1464         return n == 0 && (p == '%' || p == 0);
1465 }
1466
1467 /* GObject Init and finalise methods */
1468 static void
1469 camel_groupwise_store_class_init (CamelGroupwiseStoreClass *camel_groupwise_store_class)
1470 {
1471         CamelServiceClass *camel_service_class =
1472                 CAMEL_SERVICE_CLASS (camel_groupwise_store_class);
1473         CamelStoreClass *camel_store_class =
1474                 CAMEL_STORE_CLASS (camel_groupwise_store_class);
1475         
1476         parent_class = CAMEL_OFFLINE_STORE_CLASS (camel_type_get_global_classfuncs (camel_offline_store_get_type ()));
1477         
1478         camel_service_class->construct = groupwise_store_construct;
1479         camel_service_class->query_auth_types = groupwise_store_query_auth_types;
1480         camel_service_class->get_name = groupwise_get_name;
1481         camel_service_class->connect = groupwise_connect;
1482         camel_service_class->disconnect = groupwise_disconnect;
1483         
1484         camel_store_class->hash_folder_name = groupwise_hash_folder_name;
1485         camel_store_class->compare_folder_name = groupwise_compare_folder_name;
1486         
1487         camel_store_class->get_folder = groupwise_get_folder;
1488         camel_store_class->create_folder = groupwise_create_folder;
1489         camel_store_class->delete_folder = groupwise_delete_folder;
1490         camel_store_class->rename_folder = groupwise_rename_folder;
1491         camel_store_class->get_folder_info = groupwise_get_folder_info;
1492         camel_store_class->free_folder_info = camel_store_free_folder_info_full;
1493         camel_store_class->get_trash = groupwise_get_trash;
1494 }
1495
1496
1497 /*This frees the private structure*/
1498 static void
1499 camel_groupwise_store_finalize (CamelObject *object)
1500 {
1501         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (object);
1502         CamelGroupwiseStorePrivate *priv = groupwise_store->priv;
1503         
1504         g_print ("camel_groupwise_store_finalize\n");
1505         if (groupwise_store->summary) {
1506                 camel_store_summary_save ((CamelStoreSummary *)groupwise_store->summary);
1507                 camel_object_unref (groupwise_store->summary);
1508         }
1509         
1510         if (priv) {
1511                 if (priv->user) {
1512                         g_free (priv->user);
1513                         priv->user = NULL;
1514                 }
1515                 if (priv->server_name) {
1516                         g_free (priv->server_name);
1517                         priv->server_name = NULL;
1518                 }
1519                 if (priv->port) {
1520                         g_free (priv->port);
1521                         priv->port = NULL;
1522                 }
1523                 if (priv->use_ssl) {
1524                         g_free (priv->use_ssl);
1525                         priv->use_ssl = NULL;
1526                 }
1527                 if (priv->base_url) {
1528                         g_free (priv->base_url);
1529                         priv->base_url = NULL;
1530                 }
1531                 
1532                 if (E_IS_GW_CONNECTION (priv->cnc)) {
1533                         g_object_unref (priv->cnc);
1534                         priv->cnc = NULL;
1535                 }
1536
1537                 if (priv->storage_path)
1538                         g_free(priv->storage_path);
1539
1540                 if(groupwise_store->root_container)
1541                         g_free (groupwise_store->root_container);
1542                 
1543                 if (priv->id_hash)
1544                         g_hash_table_destroy (priv->id_hash);
1545
1546                 if (priv->name_hash)
1547                         g_hash_table_destroy (priv->name_hash);
1548
1549                 if (priv->parent_hash)
1550                         g_hash_table_destroy (priv->parent_hash);
1551
1552                 g_free (groupwise_store->priv);
1553                 groupwise_store->priv = NULL;
1554         }
1555
1556 }
1557
1558 static void
1559 camel_groupwise_store_init (gpointer object, gpointer klass)
1560 {
1561         CamelGroupwiseStore *groupwise_store = CAMEL_GROUPWISE_STORE (object);
1562         CamelGroupwiseStorePrivate *priv = g_new0 (CamelGroupwiseStorePrivate, 1);
1563         
1564         d("in groupwise store init\n");
1565         priv->server_name = NULL;
1566         priv->port = NULL;
1567         priv->use_ssl = NULL;
1568         priv->user = NULL;
1569         priv->cnc = NULL;
1570         groupwise_store->priv = priv;
1571         
1572 }
1573
1574 CamelType
1575 camel_groupwise_store_get_type (void)
1576 {
1577         static CamelType camel_groupwise_store_type = CAMEL_INVALID_TYPE;
1578         
1579         if (camel_groupwise_store_type == CAMEL_INVALID_TYPE)   {
1580                 camel_groupwise_store_type =
1581                         camel_type_register (camel_offline_store_get_type (),
1582                                              "CamelGroupwiseStore",
1583                                              sizeof (CamelGroupwiseStore),
1584                                              sizeof (CamelGroupwiseStoreClass),
1585                                              (CamelObjectClassInitFunc) camel_groupwise_store_class_init,
1586                                              NULL,
1587                                              (CamelObjectInitFunc) camel_groupwise_store_init,
1588                                              (CamelObjectFinalizeFunc) camel_groupwise_store_finalize);
1589         }
1590         
1591         return camel_groupwise_store_type;
1592 }