5 * Copyright (C) 2010-2011 Nokia Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <sys/types.h>
38 static char *root_folder = NULL;
46 struct folder_listing_data {
47 struct session *session;
51 messages_folder_listing_cb callback;
55 /* NOTE: Neither IrOBEX nor MAP specs says that folder listing needs to
56 * be sorted (in IrOBEX examples it is not). However existing implementations
57 * seem to follow the fig. 3-2 from MAP specification v1.0, and I've seen a
58 * test suite requiring folder listing to be in that order.
60 static gint folder_names_cmp(gconstpointer a, gconstpointer b,
63 static const char *order[] = {
64 "inbox", "outbox", "sent", "deleted", "draft", NULL
66 struct session *session = user_data;
69 if (g_strcmp0(session->cwd, "telecom/msg") == 0) {
70 for (ia = 0; order[ia]; ia++) {
71 if (g_strcmp0(a, order[ia]) == 0)
74 for (ib = 0; order[ib]; ib++) {
75 if (g_strcmp0(b, order[ib]) == 0)
82 return g_strcmp0(a, b);
85 static char *get_next_subdir(DIR *dp, char *path)
91 if ((ep = readdir(dp)) == NULL)
94 if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
97 abs = g_build_filename(path, ep->d_name, NULL);
99 if (g_file_test(abs, G_FILE_TEST_IS_DIR)) {
107 name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
110 DBG("g_filename_to_utf8(): invalid filename");
117 static ssize_t get_subdirs(struct folder_listing_data *fld, GSList **list)
123 path = g_build_filename(fld->session->cwd_absolute, fld->name, NULL);
129 DBG("opendir(): %d, %s", -err, strerror(-err));
137 while ((name = get_next_subdir(dp, path)) != NULL) {
140 *list = g_slist_prepend(*list, name);
146 *list = g_slist_sort_with_data(*list, folder_names_cmp, fld->session);
151 static void return_folder_listing(struct folder_listing_data *fld, GSList *list)
153 struct session *session = fld->session;
158 /* XXX: This isn't really documented for MAP. I need to take a look how
159 * other implementations choose to deal with parent folder.
161 if (session->cwd[0] != 0 && fld->offset == 0) {
163 fld->callback(session, -EAGAIN, 0, "..", fld->user_data);
168 for (cur = list; offs < fld->offset; offs++) {
174 for (; cur != NULL && num < fld->max; cur = cur->next, num++)
175 fld->callback(session, -EAGAIN, 0, cur->data, fld->user_data);
177 fld->callback(session, 0, 0, NULL, fld->user_data);
180 static gboolean get_folder_listing(void *d)
182 struct folder_listing_data *fld = d;
186 n = get_subdirs(fld, &list);
189 fld->callback(fld->session, n, 0, NULL, fld->user_data);
194 fld->callback(fld->session, 0, n, NULL, fld->user_data);
198 return_folder_listing(fld, list);
199 g_slist_free_full(list, g_free);
204 int messages_init(void)
211 tmp = getenv("MAP_ROOT");
213 root_folder = g_strdup(tmp);
217 tmp = getenv("HOME");
221 root_folder = g_build_filename(tmp, "map-messages", NULL);
226 void messages_exit(void)
232 int messages_connect(void **s)
234 struct session *session;
236 session = g_new0(struct session, 1);
237 session->cwd = g_strdup("");
238 session->cwd_absolute = g_strdup(root_folder);
245 void messages_disconnect(void *s)
247 struct session *session = s;
249 g_free(session->cwd);
250 g_free(session->cwd_absolute);
254 int messages_set_notification_registration(void *session,
255 void (*send_event)(void *session,
256 const struct messages_event *event, void *user_data),
262 int messages_set_folder(void *s, const char *name, gboolean cdup)
264 struct session *session = s;
269 if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
273 if (session->cwd[0] == 0)
276 newrel = g_path_get_dirname(session->cwd);
278 /* We use empty string for indication of the root directory */
279 if (newrel[0] == '.' && newrel[1] == 0)
284 if (!cdup && (!name || name[0] == 0))
285 newrel = g_strdup("");
287 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
291 newabs = g_build_filename(root_folder, newrel, NULL);
293 if (!g_file_test(newabs, G_FILE_TEST_IS_DIR)) {
299 g_free(session->cwd);
300 session->cwd = newrel;
302 g_free(session->cwd_absolute);
303 session->cwd_absolute = newabs;
308 int messages_get_folder_listing(void *s, const char *name, uint16_t max,
310 messages_folder_listing_cb callback,
313 struct session *session = s;
314 struct folder_listing_data *fld;
316 fld = g_new0(struct folder_listing_data, 1);
317 fld->session = session;
320 fld->offset = offset;
321 fld->callback = callback;
322 fld->user_data = user_data;
324 session->request = fld;
326 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, get_folder_listing,
332 int messages_get_messages_listing(void *session, const char *name,
333 uint16_t max, uint16_t offset,
334 const struct messages_filter *filter,
335 messages_get_messages_listing_cb callback,
341 int messages_get_message(void *session, const char *handle,
343 messages_get_message_cb callback,
349 int messages_update_inbox(void *session, messages_update_inbox_cb callback,
355 void messages_abort(void *s)
357 struct session *session = s;
359 if (session->request) {
360 g_idle_remove_by_data(session->request);
361 session->request = NULL;