tizen 2.3.1 release
[framework/connectivity/bluez.git] / obexd / plugins / messages-dummy.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2010-2011  Nokia Corporation
6  *
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "obexd/src/log.h"
35
36 #include "messages.h"
37
38 static char *root_folder = NULL;
39
40 struct session {
41         char *cwd;
42         char *cwd_absolute;
43         void *request;
44 };
45
46 struct folder_listing_data {
47         struct session *session;
48         const char *name;
49         uint16_t max;
50         uint16_t offset;
51         messages_folder_listing_cb callback;
52         void *user_data;
53 };
54
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.
59  */
60 static int folder_names_cmp(gconstpointer a, gconstpointer b,
61                                                 gpointer user_data)
62 {
63         static const char *order[] = {
64                 "inbox", "outbox", "sent", "deleted", "draft", NULL
65         };
66         struct session *session = user_data;
67         int ia, ib;
68
69         if (g_strcmp0(session->cwd, "telecom/msg") == 0) {
70                 for (ia = 0; order[ia]; ia++) {
71                         if (g_strcmp0(a, order[ia]) == 0)
72                                 break;
73                 }
74                 for (ib = 0; order[ib]; ib++) {
75                         if (g_strcmp0(b, order[ib]) == 0)
76                                 break;
77                 }
78                 if (ia != ib)
79                         return ia - ib;
80         }
81
82         return g_strcmp0(a, b);
83 }
84
85 static char *get_next_subdir(DIR *dp, char *path)
86 {
87         struct dirent *ep;
88         char *abs, *name;
89
90         for (;;) {
91                 if ((ep = readdir(dp)) == NULL)
92                         return NULL;
93
94                 if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
95                         continue;
96
97                 abs = g_build_filename(path, ep->d_name, NULL);
98
99                 if (g_file_test(abs, G_FILE_TEST_IS_DIR)) {
100                         g_free(abs);
101                         break;
102                 }
103
104                 g_free(abs);
105         }
106
107         name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
108
109         if (name == NULL) {
110                 DBG("g_filename_to_utf8(): invalid filename");
111                 return NULL;
112         }
113
114         return name;
115 }
116
117 static ssize_t get_subdirs(struct folder_listing_data *fld, GSList **list)
118 {
119         DIR *dp;
120         char *path, *name;
121         size_t n;
122
123         path = g_build_filename(fld->session->cwd_absolute, fld->name, NULL);
124         dp = opendir(path);
125
126         if (dp == NULL) {
127                 int err = -errno;
128
129                 DBG("opendir(): %d, %s", -err, strerror(-err));
130                 g_free(path);
131
132                 return err;
133         }
134
135         n = 0;
136
137         while ((name = get_next_subdir(dp, path)) != NULL) {
138                 n++;
139                 if (fld->max > 0)
140                         *list = g_slist_prepend(*list, name);
141         }
142
143         closedir(dp);
144         g_free(path);
145
146         *list = g_slist_sort_with_data(*list, folder_names_cmp, fld->session);
147
148         return n;
149 }
150
151 static void return_folder_listing(struct folder_listing_data *fld, GSList *list)
152 {
153         struct session *session = fld->session;
154         GSList *cur;
155         uint16_t num = 0;
156         uint16_t offs = 0;
157
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.
160          */
161         if (session->cwd[0] != 0 && fld->offset == 0) {
162                 num++;
163                 fld->callback(session, -EAGAIN, 0, "..", fld->user_data);
164         } else {
165                 offs++;
166         }
167
168         for (cur = list; offs < fld->offset; offs++) {
169                 cur = cur->next;
170                 if (cur == NULL)
171                         break;
172         }
173
174         for (; cur != NULL && num < fld->max; cur = cur->next, num++)
175                 fld->callback(session, -EAGAIN, 0, cur->data, fld->user_data);
176
177         fld->callback(session, 0, 0, NULL, fld->user_data);
178 }
179
180 static gboolean get_folder_listing(void *d)
181 {
182         struct folder_listing_data *fld = d;
183         ssize_t n;
184         GSList *list = NULL;
185
186         n = get_subdirs(fld, &list);
187
188         if (n < 0) {
189                 fld->callback(fld->session, n, 0, NULL, fld->user_data);
190                 return FALSE;
191         }
192
193         if (fld->max == 0) {
194                 fld->callback(fld->session, 0, n, NULL, fld->user_data);
195                 return FALSE;
196         }
197
198         return_folder_listing(fld, list);
199         g_slist_free_full(list, g_free);
200
201         return FALSE;
202 }
203
204 int messages_init(void)
205 {
206         char *tmp;
207
208         if (root_folder)
209                 return 0;
210
211         tmp = getenv("MAP_ROOT");
212         if (tmp) {
213                 root_folder = g_strdup(tmp);
214                 return 0;
215         }
216
217         tmp = getenv("HOME");
218         if (!tmp)
219                 return -ENOENT;
220
221         root_folder = g_build_filename(tmp, "map-messages", NULL);
222
223         return 0;
224 }
225
226 void messages_exit(void)
227 {
228         g_free(root_folder);
229         root_folder = NULL;
230 }
231
232 int messages_connect(void **s)
233 {
234         struct session *session;
235
236         session = g_new0(struct session, 1);
237         session->cwd = g_strdup("");
238         session->cwd_absolute = g_strdup(root_folder);
239
240         *s = session;
241
242         return 0;
243 }
244
245 void messages_disconnect(void *s)
246 {
247         struct session *session = s;
248
249         g_free(session->cwd);
250         g_free(session->cwd_absolute);
251         g_free(session);
252 }
253
254 int messages_set_notification_registration(void *session,
255                 void (*send_event)(void *session,
256                         const struct messages_event *event, void *user_data),
257                 void *user_data)
258 {
259         return -ENOSYS;
260 }
261
262 int messages_set_folder(void *s, const char *name, gboolean cdup)
263 {
264         struct session *session = s;
265         char *newrel = NULL;
266         char *newabs;
267         char *tmp;
268
269         if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
270                 return -EBADR;
271
272         if (cdup) {
273                 if (session->cwd[0] == 0)
274                         return -ENOENT;
275
276                 newrel = g_path_get_dirname(session->cwd);
277
278                 /* We use empty string for indication of the root directory */
279                 if (newrel[0] == '.' && newrel[1] == 0)
280                         newrel[0] = 0;
281         }
282
283         tmp = newrel;
284         if (!cdup && (!name || name[0] == 0))
285                 newrel = g_strdup("");
286         else
287                 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
288                                 NULL);
289         g_free(tmp);
290
291         newabs = g_build_filename(root_folder, newrel, NULL);
292
293         if (!g_file_test(newabs, G_FILE_TEST_IS_DIR)) {
294                 g_free(newrel);
295                 g_free(newabs);
296                 return -ENOENT;
297         }
298
299         g_free(session->cwd);
300         session->cwd = newrel;
301
302         g_free(session->cwd_absolute);
303         session->cwd_absolute = newabs;
304
305         return 0;
306 }
307
308 int messages_get_folder_listing(void *s, const char *name, uint16_t max,
309                                         uint16_t offset,
310                                         messages_folder_listing_cb callback,
311                                         void *user_data)
312 {
313         struct session *session =  s;
314         struct folder_listing_data *fld;
315
316         fld = g_new0(struct folder_listing_data, 1);
317         fld->session = session;
318         fld->name = name;
319         fld->max = max;
320         fld->offset = offset;
321         fld->callback = callback;
322         fld->user_data = user_data;
323
324         session->request = fld;
325
326         g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, get_folder_listing,
327                                                                 fld, g_free);
328
329         return 0;
330 }
331
332 int messages_get_messages_listing(void *session, const char *name,
333                                 uint16_t max, uint16_t offset,
334                                 uint8_t subject_len,
335                                 const struct messages_filter *filter,
336                                 messages_get_messages_listing_cb callback,
337                                 void *user_data)
338 {
339         return -ENOSYS;
340 }
341
342 int messages_get_message(void *session, const char *handle,
343                                         unsigned long flags,
344                                         messages_get_message_cb callback,
345                                         void *user_data)
346 {
347         return -ENOSYS;
348 }
349
350 int messages_update_inbox(void *session, messages_status_cb callback,
351                                                         void *user_data)
352 {
353         return -ENOSYS;
354 }
355
356 int messages_set_read(void *session, const char *handle, uint8_t value,
357                                 messages_status_cb callback, void *user_data)
358 {
359         return -ENOSYS;
360 }
361
362 int messages_set_delete(void *session, const char *handle, uint8_t value,
363                                 messages_status_cb callback, void *user_data)
364 {
365         return -ENOSYS;
366 }
367
368 void messages_abort(void *s)
369 {
370         struct session *session = s;
371
372         if (session->request) {
373                 g_idle_remove_by_data(session->request);
374                 session->request = NULL;
375         }
376 }