tizen 2.3.1 release
[framework/connectivity/bluez.git] / obexd / plugins / mas.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 <string.h>
29 #include <errno.h>
30 #include <glib.h>
31 #include <fcntl.h>
32 #include <inttypes.h>
33 #include <sys/time.h>
34
35 #include "gobex/gobex.h"
36 #include "gobex/gobex-apparam.h"
37
38 #include "obexd/src/obexd.h"
39 #include "obexd/src/plugin.h"
40 #include "obexd/src/log.h"
41 #include "obexd/src/obex.h"
42 #include "obexd/src/service.h"
43 #include "obexd/src/mimetype.h"
44 #include "obexd/src/manager.h"
45 #include "obexd/src/map_ap.h"
46 #include "filesystem.h"
47 #include "messages.h"
48
49 #define READ_STATUS_REQ 0
50 #define DELETE_STATUS_REQ 1
51
52 #define XML_DECL "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
53
54 /* Building blocks for x-obex/folder-listing */
55 #define FL_DTD "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">"
56 #define FL_BODY_BEGIN "<folder-listing version=\"1.0\">"
57 #define FL_BODY_EMPTY "<folder-listing version=\"1.0\"/>"
58 #define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>"
59 #define FL_FOLDER_ELEMENT "<folder name=\"%s\"/>"
60 #define FL_BODY_END "</folder-listing>"
61
62 #define ML_BODY_BEGIN "<MAP-msg-listing version=\"1.0\">"
63 #define ML_BODY_END "</MAP-msg-listing>"
64
65 struct mas_session {
66         struct mas_request *request;
67         void *backend_data;
68         gboolean finished;
69         gboolean nth_call;
70         GString *buffer;
71         GObexApparam *inparams;
72         GObexApparam *outparams;
73         gboolean ap_sent;
74 #ifdef __TIZEN_PATCH__
75         gboolean headers_sent;
76         int notification_status;
77         char *remote_addr;
78         char *response_handle;
79 #else
80         uint8_t notification_status;
81 #endif
82 };
83
84 static const uint8_t MAS_TARGET[TARGET_SIZE] = {
85                         0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, 0xdb,
86                         0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66  };
87
88 static int get_params(struct obex_session *os, struct mas_session *mas)
89 {
90         const uint8_t *buffer;
91         ssize_t size;
92
93         size = obex_get_apparam(os, &buffer);
94         if (size <= 0)
95                 return 0;
96
97         mas->inparams = g_obex_apparam_decode(buffer, size);
98         if (mas->inparams == NULL) {
99                 DBG("Error when parsing parameters!");
100                 return -EBADR;
101         }
102
103         return 0;
104 }
105
106 static void reset_request(struct mas_session *mas)
107 {
108         if (mas->buffer) {
109                 g_string_free(mas->buffer, TRUE);
110                 mas->buffer = NULL;
111         }
112
113         if (mas->inparams) {
114                 g_obex_apparam_free(mas->inparams);
115                 mas->inparams = NULL;
116         }
117
118         if (mas->outparams) {
119                 g_obex_apparam_free(mas->outparams);
120                 mas->outparams = NULL;
121         }
122
123         mas->nth_call = FALSE;
124         mas->finished = FALSE;
125         mas->ap_sent = FALSE;
126 #ifdef __TIZEN_PATCH__
127         mas->headers_sent = FALSE;
128         g_free(mas->response_handle);
129         mas->response_handle = NULL;
130 #endif
131 }
132
133 static void mas_clean(struct mas_session *mas)
134 {
135         reset_request(mas);
136 #ifdef __TIZEN_PATCH__
137         g_free(mas->remote_addr);
138 #endif
139         g_free(mas);
140 }
141
142 static void *mas_connect(struct obex_session *os, int *err)
143 {
144         struct mas_session *mas;
145 #ifdef __TIZEN_PATCH__
146         char *address;
147 #endif
148
149         DBG("");
150
151         mas = g_new0(struct mas_session, 1);
152
153         *err = messages_connect(&mas->backend_data);
154         if (*err < 0)
155                 goto failed;
156
157         manager_register_session(os);
158
159 #ifdef __TIZEN_PATCH__
160         if (obex_getpeername(os, &address) == 0) {
161                 mas->remote_addr = address;
162                 DBG("mas->remote_addr = %s\n", mas->remote_addr);
163         }
164 #endif
165
166         return mas;
167
168 failed:
169         g_free(mas);
170
171         return NULL;
172 }
173
174 static void mas_disconnect(struct obex_session *os, void *user_data)
175 {
176         struct mas_session *mas = user_data;
177
178         DBG("");
179
180         manager_unregister_session(os);
181         messages_disconnect(mas->backend_data);
182
183         mas_clean(mas);
184 }
185
186 static int mas_get(struct obex_session *os, void *user_data)
187 {
188         struct mas_session *mas = user_data;
189         const char *type = obex_get_type(os);
190         const char *name = obex_get_name(os);
191         int ret;
192
193         DBG("GET: name %s type %s mas %p",
194                         name, type, mas);
195
196         if (type == NULL)
197                 return -EBADR;
198
199         ret = get_params(os, mas);
200         if (ret < 0)
201                 goto failed;
202
203         ret = obex_get_stream_start(os, name);
204         if (ret < 0)
205                 goto failed;
206
207         return 0;
208
209 failed:
210         reset_request(mas);
211
212         return ret;
213 }
214
215 static int mas_put(struct obex_session *os, void *user_data)
216 {
217         struct mas_session *mas = user_data;
218         const char *type = obex_get_type(os);
219         const char *name = obex_get_name(os);
220         int ret;
221
222         DBG("PUT: name %s type %s mas %p", name, type, mas);
223
224         if (type == NULL)
225                 return -EBADR;
226
227         ret = get_params(os, mas);
228         if (ret < 0)
229                 goto failed;
230
231         ret = obex_put_stream_start(os, name);
232         if (ret < 0)
233                 goto failed;
234
235         return 0;
236
237 failed:
238         reset_request(mas);
239
240         return ret;
241 }
242
243 /* FIXME: Preserve whitespaces */
244 static void g_string_append_escaped_printf(GString *string,
245                                                 const char *format, ...)
246 {
247         va_list ap;
248         char *escaped;
249
250         va_start(ap, format);
251         escaped = g_markup_vprintf_escaped(format, ap);
252         g_string_append(string, escaped);
253         g_free(escaped);
254         va_end(ap);
255 }
256
257 static gchar *get_mse_timestamp(void)
258 {
259         struct timeval time_val;
260         struct tm ltime;
261         gchar *local_ts;
262         char sign;
263
264         if (gettimeofday(&time_val, NULL) < 0)
265                 return NULL;
266
267         if (!localtime_r(&time_val.tv_sec, &ltime))
268                 return NULL;
269
270         if (difftime(mktime(localtime(&time_val.tv_sec)),
271                                 mktime(gmtime(&time_val.tv_sec))) < 0)
272                 sign = '+';
273         else
274                 sign = '-';
275
276         local_ts = g_strdup_printf("%04d%02d%02dT%02d%02d%02d%c%2ld%2ld",
277                                         ltime.tm_year + 1900, ltime.tm_mon + 1,
278                                         ltime.tm_mday, ltime.tm_hour,
279                                         ltime.tm_min, ltime.tm_sec, sign,
280                                         ltime.tm_gmtoff/3600,
281                                         (ltime.tm_gmtoff%3600)/60);
282
283         return local_ts;
284 }
285
286 static const char *yesorno(gboolean a)
287 {
288         if (a)
289                 return "yes";
290
291         return "no";
292 }
293
294 static void get_messages_listing_cb(void *session, int err, uint16_t size,
295                                         gboolean newmsg,
296                                         const struct messages_message *entry,
297                                         void *user_data)
298 {
299         struct mas_session *mas = user_data;
300         uint16_t max = 1024;
301         gchar *mse_time;
302
303         if (err < 0 && err != -EAGAIN) {
304                 obex_object_set_io_flags(mas, G_IO_ERR, err);
305                 return;
306         }
307
308         if (mas->inparams)
309                 g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT,
310                                                                         &max);
311
312         if (max == 0) {
313                 if (!entry)
314                         mas->finished = TRUE;
315
316                 goto proceed;
317         }
318
319         if (!mas->nth_call) {
320                 g_string_append(mas->buffer, ML_BODY_BEGIN);
321                 mas->nth_call = TRUE;
322         }
323
324         if (!entry) {
325                 g_string_append(mas->buffer, ML_BODY_END);
326                 mas->finished = TRUE;
327
328                 goto proceed;
329         }
330
331         g_string_append(mas->buffer, "<msg");
332
333         g_string_append_escaped_printf(mas->buffer, " handle=\"%s\"",
334                                                                 entry->handle);
335
336         if (entry->mask & PMASK_SUBJECT)
337                 g_string_append_escaped_printf(mas->buffer, " subject=\"%s\"",
338                                 entry->subject);
339
340         if (entry->mask & PMASK_DATETIME)
341                 g_string_append_escaped_printf(mas->buffer, " datetime=\"%s\"",
342                                 entry->datetime);
343
344         if (entry->mask & PMASK_SENDER_NAME)
345                 g_string_append_escaped_printf(mas->buffer,
346                                                 " sender_name=\"%s\"",
347                                                 entry->sender_name);
348
349         if (entry->mask & PMASK_SENDER_ADDRESSING)
350                 g_string_append_escaped_printf(mas->buffer,
351                                                 " sender_addressing=\"%s\"",
352                                                 entry->sender_addressing);
353
354         if (entry->mask & PMASK_REPLYTO_ADDRESSING)
355                 g_string_append_escaped_printf(mas->buffer,
356                                                 " replyto_addressing=\"%s\"",
357                                                 entry->replyto_addressing);
358
359         if (entry->mask & PMASK_RECIPIENT_NAME)
360                 g_string_append_escaped_printf(mas->buffer,
361                                                 " recipient_name=\"%s\"",
362                                                 entry->recipient_name);
363
364         if (entry->mask & PMASK_RECIPIENT_ADDRESSING)
365                 g_string_append_escaped_printf(mas->buffer,
366                                                 " recipient_addressing=\"%s\"",
367                                                 entry->recipient_addressing);
368
369         if (entry->mask & PMASK_TYPE)
370                 g_string_append_escaped_printf(mas->buffer, " type=\"%s\"",
371                                 entry->type);
372
373         if (entry->mask & PMASK_RECEPTION_STATUS)
374                 g_string_append_escaped_printf(mas->buffer,
375                                                 " reception_status=\"%s\"",
376                                                 entry->reception_status);
377
378         if (entry->mask & PMASK_SIZE)
379                 g_string_append_escaped_printf(mas->buffer, " size=\"%s\"",
380                                 entry->size);
381
382         if (entry->mask & PMASK_ATTACHMENT_SIZE)
383                 g_string_append_escaped_printf(mas->buffer,
384                                                 " attachment_size=\"%s\"",
385                                                 entry->attachment_size);
386
387         if (entry->mask & PMASK_TEXT)
388                 g_string_append_escaped_printf(mas->buffer, " text=\"%s\"",
389                                 yesorno(entry->text));
390
391         if (entry->mask & PMASK_READ)
392                 g_string_append_escaped_printf(mas->buffer, " read=\"%s\"",
393                                 yesorno(entry->read));
394
395         if (entry->mask & PMASK_SENT)
396                 g_string_append_escaped_printf(mas->buffer, " sent=\"%s\"",
397                                 yesorno(entry->sent));
398
399         if (entry->mask & PMASK_PROTECTED)
400                 g_string_append_escaped_printf(mas->buffer, " protected=\"%s\"",
401                                 yesorno(entry->protect));
402
403         if (entry->mask & PMASK_PRIORITY)
404                 g_string_append_escaped_printf(mas->buffer, " priority=\"%s\"",
405                                 yesorno(entry->priority));
406
407         g_string_append(mas->buffer, "/>\n");
408
409 proceed:
410         if (!entry) {
411                 mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
412                                                 MAP_AP_MESSAGESLISTINGSIZE,
413                                                 size);
414                 mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
415                                                 MAP_AP_NEWMESSAGE,
416                                                 newmsg ? 1 : 0);
417                 /* Response to report the local time of MSE */
418                 mse_time = get_mse_timestamp();
419                 if (mse_time) {
420                         g_obex_apparam_set_string(mas->outparams,
421                                                 MAP_AP_MSETIME, mse_time);
422                         g_free(mse_time);
423                 }
424         }
425
426         if (err != -EAGAIN)
427                 obex_object_set_io_flags(mas, G_IO_IN, 0);
428 }
429
430 #ifdef __TIZEN_PATCH__
431 static void put_message_cb(void *session, int err, guint64 handle,
432                                                         void *user_data)
433 {
434         struct mas_session *mas = user_data;
435
436         DBG("");
437
438         if (err < 0) {
439                 obex_object_set_io_flags(mas, G_IO_ERR, err);
440                 return;
441         }
442         mas->finished = FALSE;
443         mas->response_handle = g_strdup_printf("%llx", handle);
444
445         obex_object_set_io_flags(mas, G_IO_OUT, 0);
446 }
447 #endif
448
449 static void get_message_cb(void *session, int err, gboolean fmore,
450                                         const char *chunk, void *user_data)
451 {
452         struct mas_session *mas = user_data;
453
454         DBG("");
455
456         if (err < 0 && err != -EAGAIN) {
457                 obex_object_set_io_flags(mas, G_IO_ERR, err);
458                 return;
459         }
460
461         if (!chunk) {
462                 mas->finished = TRUE;
463                 goto proceed;
464         }
465
466         g_string_append(mas->buffer, chunk);
467
468 proceed:
469         if (err != -EAGAIN)
470                 obex_object_set_io_flags(mas, G_IO_IN, 0);
471 }
472
473 static void get_folder_listing_cb(void *session, int err, uint16_t size,
474                                         const char *name, void *user_data)
475 {
476         struct mas_session *mas = user_data;
477         uint16_t max = 1024;
478
479         if (err < 0 && err != -EAGAIN) {
480                 obex_object_set_io_flags(mas, G_IO_ERR, err);
481                 return;
482         }
483
484         if (mas->inparams)
485                 g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT,
486                                                                         &max);
487
488         if (max == 0) {
489                 if (err != -EAGAIN)
490                         mas->outparams = g_obex_apparam_set_uint16(
491                                                 mas->outparams,
492                                                 MAP_AP_FOLDERLISTINGSIZE,
493                                                 size);
494
495                 if (!name)
496                         mas->finished = TRUE;
497
498                 goto proceed;
499 #ifdef __TIZEN_PATCH__
500         } else {
501                 mas->ap_sent = TRUE;
502 #endif
503         }
504
505         if (!mas->nth_call) {
506                 g_string_append(mas->buffer, XML_DECL);
507                 g_string_append(mas->buffer, FL_DTD);
508                 if (!name) {
509                         g_string_append(mas->buffer, FL_BODY_EMPTY);
510                         mas->finished = TRUE;
511                         goto proceed;
512                 }
513                 g_string_append(mas->buffer, FL_BODY_BEGIN);
514                 mas->nth_call = TRUE;
515         }
516
517         if (!name) {
518                 g_string_append(mas->buffer, FL_BODY_END);
519                 mas->finished = TRUE;
520                 goto proceed;
521         }
522
523         if (g_strcmp0(name, "..") == 0)
524                 g_string_append(mas->buffer, FL_PARENT_FOLDER_ELEMENT);
525         else
526                 g_string_append_escaped_printf(mas->buffer, FL_FOLDER_ELEMENT,
527                                                                         name);
528
529 proceed:
530         if (err != -EAGAIN)
531                 obex_object_set_io_flags(mas, G_IO_IN, err);
532 }
533
534 static void set_status_cb(void *session, int err, void *user_data)
535 {
536         struct mas_session *mas = user_data;
537
538         DBG("");
539
540         mas->finished = TRUE;
541
542         if (err < 0)
543                 obex_object_set_io_flags(mas, G_IO_ERR, err);
544         else
545                 obex_object_set_io_flags(mas, G_IO_OUT, 0);
546 }
547
548 static int mas_setpath(struct obex_session *os, void *user_data)
549 {
550         const char *name;
551         const uint8_t *nonhdr;
552         struct mas_session *mas = user_data;
553
554         if (obex_get_non_header_data(os, &nonhdr) != 2) {
555                 error("Set path failed: flag and constants not found!");
556                 return -EBADR;
557         }
558
559         name = obex_get_name(os);
560
561         DBG("SETPATH: name %s nonhdr 0x%x%x", name, nonhdr[0], nonhdr[1]);
562
563         if ((nonhdr[0] & 0x02) != 0x02) {
564                 DBG("Error: requested directory creation");
565                 return -EBADR;
566         }
567
568         return messages_set_folder(mas->backend_data, name, nonhdr[0] & 0x01);
569 }
570
571 static void *folder_listing_open(const char *name, int oflag, mode_t mode,
572                                 void *driver_data, size_t *size, int *err)
573 {
574         struct mas_session *mas = driver_data;
575         /* 1024 is the default when there was no MaxListCount sent */
576         uint16_t max = 1024;
577         uint16_t offset = 0;
578
579         if (oflag != O_RDONLY) {
580                 *err = -EBADR;
581                 return NULL;
582         }
583
584         DBG("name = %s", name);
585
586         if (mas->inparams) {
587                 g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT,
588                                                                         &max);
589                 g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET,
590                                                                 &offset);
591         }
592
593         *err = messages_get_folder_listing(mas->backend_data, name, max,
594                                         offset, get_folder_listing_cb, mas);
595
596         mas->buffer = g_string_new("");
597
598         if (*err < 0)
599                 return NULL;
600         else
601                 return mas;
602 }
603
604 static void *msg_listing_open(const char *name, int oflag, mode_t mode,
605                                 void *driver_data, size_t *size, int *err)
606 {
607         struct mas_session *mas = driver_data;
608         struct messages_filter filter = { 0, };
609         /* 1024 is the default when there was no MaxListCount sent */
610         uint16_t max = 1024;
611         uint16_t offset = 0;
612         /* If MAP client does not specify the subject length,
613            then subject_len = 0 and subject should be sent unaltered. */
614         uint8_t subject_len = 0;
615
616         DBG("");
617
618         if (oflag != O_RDONLY) {
619                 *err = -EBADR;
620                 return NULL;
621         }
622
623         if (!mas->inparams)
624                 goto done;
625
626         g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
627         g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
628         g_obex_apparam_get_uint8(mas->inparams, MAP_AP_SUBJECTLENGTH,
629                                                 &subject_len);
630
631         g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
632                                                 &filter.parameter_mask);
633         g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
634                                                 &filter.type);
635         filter.period_begin = g_obex_apparam_get_string(mas->inparams,
636                                                 MAP_AP_FILTERPERIODBEGIN);
637         filter.period_end = g_obex_apparam_get_string(mas->inparams,
638                                                 MAP_AP_FILTERPERIODEND);
639         g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
640                                                 &filter.read_status);
641         filter.recipient = g_obex_apparam_get_string(mas->inparams,
642                                                 MAP_AP_FILTERRECIPIENT);
643         filter.originator = g_obex_apparam_get_string(mas->inparams,
644                                                 MAP_AP_FILTERORIGINATOR);
645         g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
646                                                 &filter.priority);
647
648 done:
649         *err = messages_get_messages_listing(mas->backend_data, name, max,
650                         offset, subject_len, &filter,
651                         get_messages_listing_cb, mas);
652
653         mas->buffer = g_string_new("");
654
655         if (*err < 0)
656                 return NULL;
657         else
658                 return mas;
659 }
660
661 static void *message_open(const char *name, int oflag, mode_t mode,
662                                 void *driver_data, size_t *size, int *err)
663 {
664         struct mas_session *mas = driver_data;
665
666         DBG("");
667
668 #ifdef __TIZEN_PATCH__
669         if (oflag != O_RDONLY) {
670                 DBG("Message pushing invoked \n");
671
672                 DBG("name = %s", name);
673                 uint8_t transparent = 0;
674                 uint8_t retry = 1;
675                 uint8_t charset;
676
677                 g_obex_apparam_get_uint8(mas->inparams, MAP_AP_TRANSPARENT,
678                                                                 &transparent);
679                 DBG("transparent = %d \n", transparent);
680                 g_obex_apparam_get_uint8(mas->inparams, MAP_AP_RETRY, &retry);
681                 DBG("retry = %d \n", retry);
682
683                 if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_CHARSET,
684                                                                 &charset)) {
685                         *err = -EBADR;
686                         return NULL;
687                 }
688                 mas->headers_sent = FALSE;
689
690                 *err = messages_push_message(mas->backend_data, name,
691                                                 transparent, retry, charset,
692                                                 put_message_cb, mas);
693         } else {
694                 uint8_t fraction_request = 0;
695                 uint8_t attachment;
696                 uint8_t charset;
697
698                 if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_ATTACHMENT,
699                                                                 &attachment)) {
700                         *err = -EBADR;
701                         return NULL;
702                 }
703
704                 if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_CHARSET,
705                                                                 &charset)) {
706                         *err = -EBADR;
707                         return NULL;
708                 }
709
710                 if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FRACTIONREQUEST,
711                                                                 &fraction_request))
712                         mas->ap_sent = TRUE;
713
714                 *err = messages_get_message(mas->backend_data, name, attachment,
715                                                 charset, fraction_request,
716                                                 get_message_cb, mas);
717         }
718 #else
719         if (oflag != O_RDONLY) {
720                 DBG("Message pushing unsupported");
721                 *err = -ENOSYS;
722
723                 return NULL;
724         }
725
726         *err = messages_get_message(mas->backend_data, name, 0,
727                         get_message_cb, mas);
728 #endif
729
730         mas->buffer = g_string_new("");
731
732         if (*err < 0)
733                 return NULL;
734         else
735                 return mas;
736 }
737
738 #ifdef __TIZEN_PATCH__
739 static ssize_t message_write(void *object, const void *buf, size_t count)
740 {
741         DBG("");
742         struct mas_session *mas = object;
743
744         if (mas->finished)
745                 return 0;
746
747         g_string_append_len(mas->buffer, buf, count);
748
749         DBG("count = %d \n", count);
750
751         if (g_strrstr(mas->buffer->str, "END:BMSG\r\n")) {
752                 DBG("BMsg received. \n");
753
754         messages_push_message_data(mas->backend_data,
755                                         mas->buffer->str, NULL);
756         }
757
758         return count;
759 }
760 #endif
761
762 static void *message_update_open(const char *name, int oflag, mode_t mode,
763                                         void *driver_data, size_t *size,
764                                         int *err)
765 {
766         struct mas_session *mas = driver_data;
767
768         DBG("");
769
770         if (oflag == O_RDONLY) {
771                 *err = -EBADR;
772                 return NULL;
773         }
774
775         *err = messages_update_inbox(mas->backend_data, set_status_cb, mas);
776         if (*err < 0)
777                 return NULL;
778         else
779                 return mas;
780 }
781
782 static void *message_set_status_open(const char *name, int oflag, mode_t mode,
783                                         void *driver_data, size_t *size,
784                                         int *err)
785
786 {
787         struct mas_session *mas = driver_data;
788         uint8_t indicator;
789         uint8_t value;
790
791         DBG("");
792
793         if (oflag == O_RDONLY) {
794                 *err = -EBADR;
795                 return NULL;
796         }
797
798         if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
799                                                                 &indicator)) {
800                 *err = -EBADR;
801                 return NULL;
802         }
803
804         if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
805                                                                 &value)) {
806                 *err = -EBADR;
807                 return NULL;
808         }
809
810         if (indicator == READ_STATUS_REQ)
811                 *err = messages_set_read(mas->backend_data, name, value,
812                                                         set_status_cb, mas);
813         else if (indicator == DELETE_STATUS_REQ)
814                 *err = messages_set_delete(mas->backend_data, name, value,
815                                                         set_status_cb, mas);
816         else
817                 *err = -EBADR;
818
819         if (*err < 0)
820                 return NULL;
821
822         return mas;
823 }
824
825 #ifdef __TIZEN_PATCH__
826 static int notification_registration_close(void *obj)
827 {
828         struct mas_session *mas = obj;
829
830         DBG("");
831
832         messages_set_notification_registration(mas->backend_data,
833                         mas->remote_addr, mas->notification_status,
834                         NULL);
835
836         reset_request(mas);
837
838         return 0;
839 }
840
841 static ssize_t put_next_header(void *object, void *buf, size_t mtu,
842                                                         uint8_t *hi)
843 {
844         struct mas_session *mas = object;
845         size_t len;
846
847         DBG("");
848         if (mas->headers_sent)
849                 return 0;
850
851         if (mas->response_handle)
852                 DBG("mas->response_handle %s\n", mas->response_handle);
853         else
854                 return 0;
855
856         *hi = G_OBEX_HDR_NAME;
857
858         len = strlen(mas->response_handle);
859
860         DBG("len %d\n", len);
861         DBG("mas->response_handle %s\n", mas->response_handle);
862
863         memcpy(buf, mas->response_handle, len);
864
865         mas->headers_sent = TRUE;
866
867         return len;
868 }
869 #endif
870
871
872 static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
873                                                                 uint8_t *hi)
874 {
875         struct mas_session *mas = object;
876
877         DBG("");
878
879         if (mas->buffer->len == 0 && !mas->finished)
880                 return -EAGAIN;
881
882         *hi = G_OBEX_HDR_APPARAM;
883
884         if (mas->ap_sent)
885                 return 0;
886
887         mas->ap_sent = TRUE;
888         if (!mas->outparams)
889                 return 0;
890
891         return g_obex_apparam_encode(mas->outparams, buf, mtu);
892 }
893
894 static void *any_open(const char *name, int oflag, mode_t mode,
895                                 void *driver_data, size_t *size, int *err)
896 {
897         DBG("");
898
899         *err = -ENOSYS;
900
901         return NULL;
902 }
903
904 static ssize_t any_write(void *object, const void *buf, size_t count)
905 {
906         DBG("");
907
908         return count;
909 }
910
911 static ssize_t any_read(void *obj, void *buf, size_t count)
912 {
913         struct mas_session *mas = obj;
914         ssize_t len;
915
916         DBG("");
917
918         len = string_read(mas->buffer, buf, count);
919
920         if (len == 0 && !mas->finished)
921                 return -EAGAIN;
922
923         return len;
924 }
925
926 static int any_close(void *obj)
927 {
928         struct mas_session *mas = obj;
929
930         DBG("");
931
932         if (!mas->finished)
933                 messages_abort(mas->backend_data);
934
935         reset_request(mas);
936
937         return 0;
938 }
939
940 static void *notification_registration_open(const char *name, int oflag,
941                                                 mode_t mode, void *driver_data,
942                                                 size_t *size, int *err)
943 {
944         struct mas_session *mas = driver_data;
945         uint8_t status;
946
947         DBG("");
948
949         if (O_RDONLY) {
950                 *err = -EBADR;
951                 return NULL;
952         }
953
954         if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_NOTIFICATIONSTATUS,
955                                                                 &status)) {
956                 *err = -EBADR;
957                 return NULL;
958         }
959
960         mas->notification_status = status;
961         mas->finished = TRUE;
962         *err = 0;
963
964         return mas;
965 }
966
967 static struct obex_service_driver mas = {
968         .name = "Message Access server",
969         .service = OBEX_MAS,
970         .target = MAS_TARGET,
971         .target_size = TARGET_SIZE,
972         .connect = mas_connect,
973         .get = mas_get,
974         .put = mas_put,
975         .setpath = mas_setpath,
976         .disconnect = mas_disconnect,
977 };
978
979 static struct obex_mime_type_driver mime_map = {
980         .target = MAS_TARGET,
981         .target_size = TARGET_SIZE,
982         .mimetype = NULL,
983         .open = any_open,
984         .close = any_close,
985         .read = any_read,
986         .write = any_write,
987 };
988
989 static struct obex_mime_type_driver mime_message = {
990         .target = MAS_TARGET,
991         .target_size = TARGET_SIZE,
992         .mimetype = "x-bt/message",
993         .open = message_open,
994         .close = any_close,
995         .read = any_read,
996 #ifdef __TIZEN_PATCH__
997         .write = message_write,
998         .get_next_header = put_next_header
999 #else
1000         .write = any_write,
1001 #endif
1002 };
1003
1004 static struct obex_mime_type_driver mime_folder_listing = {
1005         .target = MAS_TARGET,
1006         .target_size = TARGET_SIZE,
1007         .mimetype = "x-obex/folder-listing",
1008         .get_next_header = any_get_next_header,
1009         .open = folder_listing_open,
1010         .close = any_close,
1011         .read = any_read,
1012         .write = any_write,
1013 };
1014
1015 static struct obex_mime_type_driver mime_msg_listing = {
1016         .target = MAS_TARGET,
1017         .target_size = TARGET_SIZE,
1018         .mimetype = "x-bt/MAP-msg-listing",
1019         .get_next_header = any_get_next_header,
1020         .open = msg_listing_open,
1021         .close = any_close,
1022         .read = any_read,
1023         .write = any_write,
1024 };
1025
1026 static struct obex_mime_type_driver mime_notification_registration = {
1027         .target = MAS_TARGET,
1028         .target_size = TARGET_SIZE,
1029         .mimetype = "x-bt/MAP-NotificationRegistration",
1030         .open = notification_registration_open,
1031 #ifdef __TIZEN_PATCH__
1032         .close = notification_registration_close,
1033 #else
1034         .close = any_close,
1035 #endif
1036         .read = any_read,
1037         .write = any_write,
1038 };
1039
1040 static struct obex_mime_type_driver mime_message_status = {
1041         .target = MAS_TARGET,
1042         .target_size = TARGET_SIZE,
1043         .mimetype = "x-bt/messageStatus",
1044         .open = message_set_status_open,
1045         .close = any_close,
1046         .read = any_read,
1047         .write = any_write,
1048 };
1049
1050 static struct obex_mime_type_driver mime_message_update = {
1051         .target = MAS_TARGET,
1052         .target_size = TARGET_SIZE,
1053         .mimetype = "x-bt/MAP-messageUpdate",
1054         .open = message_update_open,
1055         .close = any_close,
1056         .read = any_read,
1057         .write = any_write,
1058 };
1059
1060 static struct obex_mime_type_driver *map_drivers[] = {
1061         &mime_map,
1062         &mime_message,
1063         &mime_folder_listing,
1064         &mime_msg_listing,
1065         &mime_notification_registration,
1066         &mime_message_status,
1067         &mime_message_update,
1068         NULL
1069 };
1070
1071 static int mas_init(void)
1072 {
1073         int err;
1074         int i;
1075
1076         err = messages_init();
1077         if (err < 0)
1078                 return err;
1079
1080         for (i = 0; map_drivers[i] != NULL; ++i) {
1081                 err = obex_mime_type_driver_register(map_drivers[i]);
1082                 if (err < 0)
1083                         goto failed;
1084         }
1085
1086         err = obex_service_driver_register(&mas);
1087         if (err < 0)
1088                 goto failed;
1089
1090         return 0;
1091
1092 failed:
1093         for (--i; i >= 0; --i)
1094                 obex_mime_type_driver_unregister(map_drivers[i]);
1095
1096         messages_exit();
1097
1098         return err;
1099 }
1100
1101 static void mas_exit(void)
1102 {
1103         int i;
1104
1105         obex_service_driver_unregister(&mas);
1106
1107         for (i = 0; map_drivers[i] != NULL; ++i)
1108                 obex_mime_type_driver_unregister(map_drivers[i]);
1109
1110         messages_exit();
1111 }
1112
1113 OBEX_PLUGIN_DEFINE(mas, mas_init, mas_exit)