* make the memory card Archive folder a localized one,
[modest] / src / modest-tny-local-folders-account.c
1 /* Copyright (c) 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30
31 #include <string.h>
32 #include <stdio.h>
33 #include <config.h>
34 #include <glib/gi18n.h>
35 #include <tny-error.h>
36 #include <modest-tny-local-folders-account.h>
37 #include <modest-tny-outbox-account.h>
38 #include <modest-tny-folder.h>
39 #include <tny-camel-folder.h>
40 #include <tny-merge-folder.h>
41 #include <tny-simple-list.h>
42
43 G_DEFINE_TYPE (ModestTnyLocalFoldersAccount, 
44         modest_tny_local_folders_account, 
45         TNY_TYPE_CAMEL_STORE_ACCOUNT);
46
47 #define TNY_LOCAL_FOLDERS_ACCOUNT_GET_PRIVATE(o) \
48   (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_TNY_LOCAL_FOLDERS_ACCOUNT, ModestTnyLocalFoldersAccountPrivate))
49
50 typedef struct _ModestTnyLocalFoldersAccountPrivate ModestTnyLocalFoldersAccountPrivate;
51
52 struct _ModestTnyLocalFoldersAccountPrivate
53 {
54         GSList *list_extra_folders;
55 };
56
57 static void         get_folders    (TnyFolderStore *self, 
58                                     TnyList *list, 
59                                     TnyFolderStoreQuery *query, 
60                                     GError **err);
61
62 static TnyFolder*   create_folder  (TnyFolderStore *self, 
63                                     const gchar *name, 
64                                     GError **err);
65
66 static void
67 modest_tny_local_folders_account_dispose (GObject *object)
68 {
69   if (G_OBJECT_CLASS (modest_tny_local_folders_account_parent_class)->dispose)
70     G_OBJECT_CLASS (modest_tny_local_folders_account_parent_class)->dispose (object);
71 }
72
73
74 static void
75 modest_tny_local_folders_account_remove_all_extra_folders (ModestTnyLocalFoldersAccount *store)
76 {
77         ModestTnyLocalFoldersAccountPrivate *priv = 
78                 TNY_LOCAL_FOLDERS_ACCOUNT_GET_PRIVATE (store);
79                 
80         GSList *iter = priv->list_extra_folders;
81         while (iter)
82         {
83                 TnyFolder *folder = (TnyFolder*)iter->data;
84                 if (folder) {
85                         g_object_unref (folder);
86                         iter->data = NULL;
87                 }
88                         
89                 iter = g_slist_next (iter);
90         }
91         
92         g_slist_free (priv->list_extra_folders);
93         priv->list_extra_folders = NULL;
94 }
95
96 static void
97 modest_tny_local_folders_account_finalize (GObject *object)
98 {
99         G_OBJECT_CLASS (modest_tny_local_folders_account_parent_class)->finalize (object);
100   
101         ModestTnyLocalFoldersAccount *self = 
102                 MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (object);
103                 
104         modest_tny_local_folders_account_remove_all_extra_folders (self);
105 }
106
107 static void
108 modest_tny_local_folders_account_class_init (ModestTnyLocalFoldersAccountClass *klass)
109 {
110         GObjectClass *object_class = G_OBJECT_CLASS (klass);
111         
112         g_type_class_add_private (klass, sizeof (ModestTnyLocalFoldersAccountPrivate));
113         
114         object_class->dispose = modest_tny_local_folders_account_dispose;
115         object_class->finalize = modest_tny_local_folders_account_finalize;
116           
117         /* Override virtual functions from the parent class: */
118         TNY_CAMEL_STORE_ACCOUNT_CLASS(klass)->get_folders_func = get_folders;
119         TNY_CAMEL_STORE_ACCOUNT_CLASS(klass)->create_folder_func = create_folder;
120 }
121
122 static void
123 modest_tny_local_folders_account_init (ModestTnyLocalFoldersAccount *self)
124 {
125 }
126
127 ModestTnyLocalFoldersAccount*
128 modest_tny_local_folders_account_new (void)
129 {
130   return g_object_new (MODEST_TYPE_TNY_LOCAL_FOLDERS_ACCOUNT, NULL);
131 }
132
133 void
134 modest_tny_local_folders_account_add_extra_folder (ModestTnyLocalFoldersAccount *store, 
135         TnyFolder *folder)
136 {
137         ModestTnyLocalFoldersAccountPrivate *priv = 
138                 TNY_LOCAL_FOLDERS_ACCOUNT_GET_PRIVATE (store);
139                 
140         /* Check that it isn't already in the list: */
141         GSList *exists = g_slist_find (priv->list_extra_folders, folder);
142         if (exists)
143                 return;
144                 
145         /* Add it: */
146         /* The reference is released in finalize: */
147         priv->list_extra_folders = g_slist_append (priv->list_extra_folders, folder);
148         g_object_ref (folder);
149 }
150
151 static gboolean 
152 modest_tny_local_folders_account_query_passes (TnyFolderStoreQuery *query, TnyFolder *folder)
153 {
154         gboolean retval = FALSE;
155
156         if (query && (tny_list_get_length (tny_folder_store_query_get_items (query)) > 0))
157         {
158                 TnyList *items = tny_folder_store_query_get_items (query);
159                 TnyIterator *iterator;
160                 iterator = tny_list_create_iterator (items);
161
162                 while (!tny_iterator_is_done (iterator))
163                 {
164                         TnyFolderStoreQueryItem *item = (TnyFolderStoreQueryItem*) tny_iterator_get_current (iterator);
165                         if (item) {
166                                 TnyFolderStoreQueryOption options = tny_folder_store_query_item_get_options (item);
167                                 regex_t *regex = tny_folder_store_query_item_get_regex (item);
168
169                                 if ((options & TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED) &&
170                                    tny_folder_is_subscribed (folder))
171                                         retval = TRUE;
172
173                                 if ((options & TNY_FOLDER_STORE_QUERY_OPTION_UNSUBSCRIBED) &&
174                                     !(tny_folder_is_subscribed (folder)))
175                                         retval = TRUE;
176
177                                 if (regex && options & TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME)
178                                    if (regexec (regex, tny_folder_get_name (folder), 0, NULL, 0) == 0)
179                                         retval = TRUE;
180
181                                 if (regex && options & TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_ID)
182                                   if (regexec (regex, tny_folder_get_id (folder), 0, NULL, 0) == 0)
183                                         retval = TRUE;
184
185                                 g_object_unref (G_OBJECT (item));
186                         }
187
188                         tny_iterator_next (iterator);
189                 }
190                  
191                 g_object_unref (G_OBJECT (iterator));    
192                 g_object_unref (G_OBJECT (items));
193         } else
194                 retval = TRUE;
195
196         return retval;
197 }
198
199
200 static void
201 get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
202 {
203         ModestTnyLocalFoldersAccountPrivate *priv = 
204                 TNY_LOCAL_FOLDERS_ACCOUNT_GET_PRIVATE (self);
205                 
206         /* Call the base class implementation: */
207         TnyCamelStoreAccountClass *parent_class = g_type_class_peek_parent (
208                 MODEST_TNY_LOCAL_FOLDERS_ACCOUNT_GET_CLASS (self));
209         parent_class->get_folders_func (self, list, query, err);
210         
211         /* Add our extra folders only if it passes the query */
212         GSList *iter = priv->list_extra_folders;
213         while (iter) {
214                 TnyFolder *folder = TNY_FOLDER (iter->data);
215
216                 if (folder && modest_tny_local_folders_account_query_passes (query, folder))
217                         tny_list_prepend (list, G_OBJECT (folder));
218                         
219                 iter = g_slist_next (iter);
220         }
221 }
222
223 static void
224 add_account_folders_to_merged_folder (TnyAccount *account, TnyMergeFolder* merge_folder)
225 {
226         const gchar* account_id = tny_account_get_id (account);
227         const gboolean is_actual_local_folders_account = account_id && 
228                 (strcmp (account_id, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0);
229                 
230         TnyList *list_outbox_folders = tny_simple_list_new ();
231         tny_folder_store_get_folders (TNY_FOLDER_STORE (account), 
232                 list_outbox_folders, NULL, NULL);
233                 
234         TnyIterator*  iter =  tny_list_create_iterator (list_outbox_folders);
235         while (!tny_iterator_is_done (iter))
236         {
237                 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (iter));
238                 
239                 if (folder) {
240                         gboolean add = TRUE;
241                         /* TODO: Do not add outboxes that are inside local-folders/, 
242                          * because these are just left-over from earlier Modest versions 
243                          * that put the outbox there: */
244                         if (is_actual_local_folders_account) {
245                                 const TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
246                                 if (type == TNY_FOLDER_TYPE_OUTBOX) {
247                                         add = FALSE;
248                                 }
249                         }
250                         
251                         if (add)
252                                 tny_merge_folder_add_folder (merge_folder, folder);
253                                 
254                         g_object_unref (folder);        
255                 }
256                 
257                 tny_iterator_next (iter);
258         }
259         
260         g_object_unref (list_outbox_folders);
261 }
262
263 void modest_tny_local_folders_account_add_merged_outbox_folders (ModestTnyLocalFoldersAccount *self, 
264         GSList *accounts)
265 {
266         modest_tny_local_folders_account_remove_all_extra_folders (self);
267         
268         /* All per-account outbox folders are merged into one folders
269          * so that they appear as one outbox to the user: */
270         TnyMergeFolder *merged_outbox = TNY_MERGE_FOLDER (tny_merge_folder_new(_("mcen_me_folder_outbox")));
271         
272         /* Set type to outbox (NB#61580) */
273         tny_merge_folder_set_folder_type (merged_outbox, TNY_FOLDER_TYPE_OUTBOX);
274         
275         GSList *iter = accounts;
276         while (iter)
277         {
278                 TnyAccount *account = TNY_ACCOUNT (iter->data);
279                 if (account) {
280                         /* Add both outbox account and local-folders account folders
281                          * to our one combined account:
282                          */
283                         if (MODEST_IS_TNY_OUTBOX_ACCOUNT (account)) {
284                                 /* Add the folder to the merged folder.
285                                  * We will add it later to the virtual local-folders store: */
286                                 add_account_folders_to_merged_folder (account, merged_outbox);
287                         }
288                 }
289            
290                 iter = g_slist_next (iter);
291         }
292         
293         /* Add the merged outbox folder to the virtual local-folders store: */
294         /* printf ("Debug: %s: adding merged outbox.\n", __FUNCTION__); */
295         modest_tny_local_folders_account_add_extra_folder (self, TNY_FOLDER(merged_outbox));
296         g_object_unref (merged_outbox);
297         merged_outbox = NULL;
298 }
299
300 gboolean
301 modest_tny_local_folders_account_extra_folder_exists (ModestTnyLocalFoldersAccount *self,
302                                                       const gchar *name)
303 {
304         ModestTnyLocalFoldersAccountPrivate *priv;
305         GSList *iter;
306         gboolean found;
307         gchar *down_name;
308         
309         /* Check that we're not trying to create/rename any folder
310            with the same name that our extra folders */
311         priv = TNY_LOCAL_FOLDERS_ACCOUNT_GET_PRIVATE (self);
312         iter = priv->list_extra_folders;
313         found = FALSE;
314         down_name = g_utf8_strdown (name, strlen (name));
315         while (iter && !found) {
316                 TnyFolder *folder = TNY_FOLDER (iter->data);
317                 const gchar *type_name;
318
319                 type_name = modest_local_folder_info_get_type_name (tny_folder_get_folder_type (folder));
320                 if (!strcmp (type_name, down_name))
321                         found = TRUE;
322                 else
323                         iter = g_slist_next (iter);
324         }
325         g_free (down_name);
326
327         return found;
328 }
329
330 static TnyFolder*
331 create_folder (TnyFolderStore *self, 
332                const gchar *name, 
333                GError **err)
334 {
335         TnyCamelStoreAccountClass *parent_class;
336
337         parent_class = g_type_class_peek_parent (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT_GET_CLASS (self));
338
339         /* If the folder name is been used by our extra folders */
340         if (modest_tny_local_folders_account_extra_folder_exists (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (self), name)) {
341                 g_set_error (err, TNY_FOLDER_STORE_ERROR, 
342                              TNY_FOLDER_STORE_ERROR_CREATE_FOLDER,
343                              "Folder name already in use");
344                 return NULL;
345         }
346
347         /* Call the base class implementation: */
348         return parent_class->create_folder_func (self, name, err);
349 }