upload tizen1.0 source
[profile/ivi/obexd.git] / plugins / phonebook-tizen.c
1 /*
2  * OBEX Server
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Hocheol Seo <hocheol.seo@samsung.com>
7  *               Girishashok Joshi <girish.joshi@samsung.com>
8  *               Chanyeol Park <chanyeol.park@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *              http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <dirent.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <glib.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40
41 #include "log.h"
42 #include "phonebook.h"
43
44 #include <dbus/dbus.h>
45 #define QUERY_GET_PHONEBOOK_SIZE        "GetPhonebookSize"
46
47 #define QUERY_GET_PHONEBOOK                     "GetPhonebook"
48 #define QUERY_GET_CALLS                         "GetCalls"
49
50 #define QUERY_GET_PHONEBOOK_LIST        "GetPhonebookList"
51 #define QUERY_GET_CALLS_LIST            "GetCallsList"
52
53 #define QUERY_GET_PHONEBOOK_ENTRY       "GetPhonebookEntry"
54 #define QUERY_GET_CALLS_ENTRY           "GetCallsEntry"
55
56 #define QUERY_CALL_TYPE_INCOMING        "incoming"
57 #define QUERY_CALL_TYPE_OUTGOING        "outgoing"
58 #define QUERY_CALL_TYPE_MISSED          "missed"
59 #define QUERY_CALL_TYPE_COMBINED        "combined"
60
61 struct phonebook_tizen_data {
62         phonebook_cb cb;
63         DBusPendingCallNotifyFunction reply_cb;
64         void *user_data;
65         const struct apparam_field *params;
66
67         phonebook_entry_cb entry_cb;
68         phonebook_cache_ready_cb ready_cb;
69
70         const char *id;
71         char *req_name;
72 };
73
74 static void get_phonebook_reply(DBusPendingCall *call, void *user_data);
75 static void get_phonebook_size_reply(DBusPendingCall *call, void *user_data);
76 static void get_phonebook_list_reply(DBusPendingCall *call, void *user_data);
77 static void get_phonebook_entry_reply(DBusPendingCall *call, void *user_data);
78 int get_phonebook_data(const char *query, const char *call_type,
79                                 struct phonebook_tizen_data *s_data);
80 static gboolean get_sim_phonebook_reply(void *user_data);
81
82 static gboolean folder_is_valid(const char *folder)
83 {
84         if (folder == NULL)
85                 return FALSE;
86
87         if (g_str_equal(folder, "/"))
88                 return TRUE;
89         else if (g_str_equal(folder, "/telecom"))
90                 return TRUE;
91         else if (g_str_equal(folder, "/telecom/pb"))
92                 return TRUE;
93         else if (g_str_equal(folder, "/telecom/ich"))
94                 return TRUE;
95         else if (g_str_equal(folder, "/telecom/och"))
96                 return TRUE;
97         else if (g_str_equal(folder, "/telecom/mch"))
98                 return TRUE;
99         else if (g_str_equal(folder, "/telecom/cch"))
100                 return TRUE;
101
102         return FALSE;
103 }
104
105 int phonebook_init(void)
106 {
107         return 0;
108 }
109
110 void phonebook_exit(void)
111 {
112
113 }
114
115 char *phonebook_set_folder(const char *current_folder,
116                 const char *new_folder, uint8_t flags, int *err)
117 {
118         char *tmp1, *tmp2, *base, *path = NULL;
119         gboolean root, child;
120         int ret = 0;
121         int len;
122
123         root = (g_strcmp0("/", current_folder) == 0);
124         child = (new_folder && strlen(new_folder) != 0);
125
126         switch (flags) {
127                 case 0x02:
128                         /* Go back to root */
129                         if (!child) {
130                                 path = g_strdup("/");
131                                 goto done;
132                         }
133
134                         path = g_build_filename(current_folder, new_folder, NULL);
135                         break;
136                 case 0x03:
137                         /* Go up 1 level */
138                         if (root) {
139                                 /* Already root */
140                                 path = g_strdup("/");
141                                 goto done;
142                         }
143
144                         /*
145                          * Removing one level of the current folder. Current folder
146                          * contains AT LEAST one level since it is not at root folder.
147                          * Use glib utility functions to handle invalid chars in the
148                          * folder path properly.
149                          */
150                         tmp1 = g_path_get_basename(current_folder);
151                         tmp2 = g_strrstr(current_folder, tmp1);
152                         len = tmp2 - (current_folder + 1);
153
154                         g_free(tmp1);
155
156                         if (len == 0)
157                                 base = g_strdup("/");
158                         else
159                                 base = g_strndup(current_folder, len);
160
161                         /* Return: one level only */
162                         if (!child) {
163                                 path = base;
164                                 goto done;
165                         }
166
167                         path = g_build_filename(base, new_folder, NULL);
168                         g_free(base);
169
170                         break;
171                 default:
172                         ret = -EBADR;
173                         break;
174         }
175
176 done:
177         if (path && !folder_is_valid(path))
178                 ret = -ENOENT;
179
180         if (ret < 0) {
181                 g_free(path);
182                 path = NULL;
183         }
184
185         if (err)
186                 *err = ret;
187
188         return path;
189 }
190
191 void phonebook_req_finalize(void *request)
192 {
193         struct phonebook_tizen_data *data = request;
194
195         DBG("");
196
197         if (!data)
198                 return;
199
200         g_free(data->req_name);
201         g_free(data);
202 }
203
204 void *phonebook_pull(const char *name, const struct apparam_field *params,
205                                 phonebook_cb cb, void *user_data, int *err)
206 {
207         struct phonebook_tizen_data *data;
208
209         DBG("name %s", name);
210
211         if (!g_str_has_suffix(name, ".vcf")) {
212                 DBG("invaild request");
213                 if (err)
214                         *err = -EBADR;
215                 return NULL;
216         }
217
218         data = g_new0(struct phonebook_tizen_data, 1);
219         data->params = params;
220         data->user_data = user_data;
221         data->cb = cb;
222         data->req_name = g_strdup(name);
223
224         if (err)
225                 *err = 0;
226
227         return data;
228 }
229
230 int phonebook_pull_read(void *request)
231 {
232         struct phonebook_tizen_data *s_data = request;
233         const char *query;
234         const char *call_type = NULL;
235
236         DBG("name %s", s_data->req_name);
237
238         s_data->reply_cb = get_phonebook_reply;
239
240         if (g_strcmp0(s_data->req_name, "/telecom/ich.vcf") == 0) {
241                 call_type = QUERY_CALL_TYPE_INCOMING;
242                 query = QUERY_GET_CALLS;
243         } else if (g_strcmp0(s_data->req_name, "/telecom/och.vcf") == 0) {
244                 call_type = QUERY_CALL_TYPE_OUTGOING;
245                 query = QUERY_GET_CALLS;
246         } else if (g_strcmp0(s_data->req_name, "/telecom/mch.vcf") == 0) {
247                 call_type = QUERY_CALL_TYPE_MISSED;
248                 query = QUERY_GET_CALLS;
249         } else if (g_strcmp0(s_data->req_name, "/telecom/cch.vcf") == 0) {
250                 call_type = QUERY_CALL_TYPE_COMBINED;
251                 query = QUERY_GET_CALLS;
252         } else if (g_strcmp0(s_data->req_name, "/SIM1/telecom/pb.vcf") == 0) {
253                 g_idle_add(get_sim_phonebook_reply, s_data);
254                 return 0;
255         } else if (s_data->params->maxlistcount == 0) {
256                 query = QUERY_GET_PHONEBOOK_SIZE;
257                 s_data->reply_cb = get_phonebook_size_reply;
258         } else {
259                 query = QUERY_GET_PHONEBOOK;
260         }
261
262         get_phonebook_data(query, call_type, s_data);
263
264         return 0;
265 }
266
267 void *phonebook_get_entry(const char *folder, const char *id,
268                         const struct apparam_field *params, phonebook_cb cb,
269                         void *user_data, int *err)
270 {
271         struct phonebook_tizen_data *s_data;
272         DBusPendingCallNotifyFunction reply_cb;
273         const char *query;
274
275         DBG("folder %s id %s", folder, id);
276
277         if (g_strcmp0(folder, "/telecom/pb") == 0) {
278                 query = QUERY_GET_PHONEBOOK_ENTRY;
279         } else {
280                 query = QUERY_GET_CALLS_ENTRY;
281         }
282
283         reply_cb = get_phonebook_entry_reply;
284
285         s_data = g_new0(struct phonebook_tizen_data, 1);
286         s_data->params = params;
287         s_data->user_data = user_data;
288         s_data->cb = cb;
289         s_data->reply_cb = reply_cb;
290         s_data->id = id;
291
292         get_phonebook_data(query, NULL, s_data);
293
294         if (err)
295                 *err = 0;
296
297         return NULL;
298 }
299
300 void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
301                 phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
302 {
303         struct phonebook_tizen_data *s_data;
304         DBusPendingCallNotifyFunction reply_cb;
305         const char *query;
306         const char *call_type = NULL;
307
308         DBG("name %s", name);
309
310         if (g_strcmp0(name, "/telecom/pb") == 0) {
311                 query = QUERY_GET_PHONEBOOK_LIST;
312         } else if (g_strcmp0(name, "/telecom/ich") == 0) {
313                 call_type = QUERY_CALL_TYPE_INCOMING;
314                 query = QUERY_GET_CALLS_LIST;
315         } else if (g_strcmp0(name, "/telecom/och") == 0) {
316                 call_type = QUERY_CALL_TYPE_OUTGOING;
317                 query = QUERY_GET_CALLS_LIST;
318         } else if (g_strcmp0(name, "/telecom/mch") == 0) {
319                 call_type = QUERY_CALL_TYPE_MISSED;
320                 query = QUERY_GET_CALLS_LIST;
321         } else if (g_strcmp0(name, "/telecom/cch") == 0) {
322                 call_type = QUERY_CALL_TYPE_COMBINED;
323                 query = QUERY_GET_CALLS_LIST;
324         } else {
325                 if (err)
326                         *err = -ENOENT;
327                 return NULL;
328         }
329
330         reply_cb = get_phonebook_list_reply;
331
332         s_data = g_new0(struct phonebook_tizen_data, 1);
333         s_data->user_data = user_data;
334         s_data->entry_cb = entry_cb;
335         s_data->ready_cb = ready_cb;
336         s_data->reply_cb = reply_cb;
337         s_data->params = NULL;
338
339         get_phonebook_data(query, call_type, s_data);
340
341         if (err)
342                 *err = 0;
343
344         return NULL;
345 }
346
347 static void get_phonebook_reply(DBusPendingCall *call, void *user_data)
348 {
349         DBusMessage *reply = dbus_pending_call_steal_reply(call);
350         DBusMessageIter iter, element;
351         struct phonebook_tizen_data *s_data = user_data;
352         DBusError derr;
353         uint32_t phonebook_size = 0;
354         GString *buffer;
355         int lastpart = 1;
356
357         DBG("");
358
359         buffer = g_string_new("");
360
361         dbus_error_init(&derr);
362         if (dbus_set_error_from_message(&derr, reply)) {
363                 error("Replied with an error: %s, %s", derr.name, derr.message);
364                 dbus_error_free(&derr);
365         } else {
366                 dbus_message_iter_init(reply, &iter);
367
368                 if (dbus_message_iter_get_arg_type(&iter) ==
369                                                         DBUS_TYPE_INT32) {
370                         dbus_message_iter_get_basic(&iter, &lastpart);
371                         dbus_message_iter_next(&iter);
372                 }
373
374                 dbus_message_iter_recurse(&iter, &element);
375
376                 while(dbus_message_iter_get_arg_type(&element) !=
377                                                         DBUS_TYPE_INVALID) {
378                         char *arg;
379
380                         if (dbus_message_iter_get_arg_type(&element) !=
381                                                         DBUS_TYPE_STRING) {
382                                 DBG("element is not a string");
383                                 dbus_message_iter_next(&element);
384                                 continue;
385                         }
386
387                         dbus_message_iter_get_basic(&element, &arg);
388
389                         g_string_append(buffer, arg);
390
391                         dbus_message_iter_next(&element);
392
393                         phonebook_size++;
394                 }
395
396                 DBG("phonebooksize : %d\n", phonebook_size);
397         }
398
399         s_data->cb(buffer->str, buffer->len, phonebook_size, 0, lastpart,
400                                                         s_data->user_data);
401
402         g_string_free(buffer, TRUE);
403
404         dbus_message_unref(reply);
405 }
406
407 static void get_phonebook_size_reply(DBusPendingCall *call, void *user_data)
408 {
409         DBusMessage *reply = dbus_pending_call_steal_reply(call);
410         struct phonebook_tizen_data *s_data = user_data;
411         DBusError derr;
412         uint32_t phonebook_size;
413
414         DBG("");
415
416         dbus_error_init(&derr);
417         if (dbus_set_error_from_message(&derr, reply)) {
418                 error("Replied with an error: %s, %s", derr.name, derr.message);
419                 dbus_error_free(&derr);
420                 phonebook_size = 0;
421         } else {
422                 dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32,
423                                         &phonebook_size, DBUS_TYPE_INVALID);
424                 DBG("phonebooksize:%d\n", phonebook_size);
425         }
426
427         s_data->cb(NULL, 0, phonebook_size, 0, TRUE, s_data->user_data);
428
429         dbus_message_unref(reply);
430 }
431
432 static void get_phonebook_list_reply(DBusPendingCall *call, void *user_data)
433 {
434         DBusMessage *reply = dbus_pending_call_steal_reply(call);
435         DBusMessageIter iter, iter_struct, entry;
436         struct phonebook_tizen_data *s_data = user_data;
437         DBusError derr;
438         uint32_t handle = 0;
439         const char *name = NULL;
440         const char *tel = NULL;
441         char id[10];
442
443         DBG("");
444
445         dbus_error_init(&derr);
446         if (dbus_set_error_from_message(&derr, reply)) {
447                 error("Replied with an error: %s, %s", derr.name, derr.message);
448                 dbus_error_free(&derr);
449         } else {
450
451                 dbus_message_iter_init(reply, &iter);
452
453                 dbus_message_iter_recurse(&iter, &iter_struct);
454
455                 while (dbus_message_iter_get_arg_type(&iter_struct) ==
456                                                         DBUS_TYPE_STRUCT) {
457                         dbus_message_iter_recurse(&iter_struct, &entry);
458
459                         dbus_message_iter_get_basic(&entry, &name);
460                         dbus_message_iter_next(&entry);
461                         dbus_message_iter_get_basic(&entry, &tel);
462                         dbus_message_iter_next(&entry);
463                         dbus_message_iter_get_basic(&entry, &handle);
464
465                         //DBG("[handle:%d name:%s tel:%s]\n", handle, name, tel);
466
467                         snprintf(id, sizeof(id), "%d.vcf", handle);
468
469                         s_data->entry_cb(id, handle, name, NULL, tel,
470                                                         s_data->user_data);
471
472                         dbus_message_iter_next(&iter_struct);
473                 }
474         }
475
476         s_data->ready_cb(s_data->user_data);
477
478         dbus_message_unref(reply);
479 }
480
481 static void get_phonebook_entry_reply(DBusPendingCall *call, void *user_data)
482 {
483         DBusMessage *reply = dbus_pending_call_steal_reply(call);
484         struct phonebook_tizen_data *s_data = user_data;
485         DBusError derr;
486         const char *phonebook_entry;
487
488         DBG("");
489
490         dbus_error_init(&derr);
491         if (dbus_set_error_from_message(&derr, reply)) {
492                 error("Replied with an error: %s, %s", derr.name, derr.message);
493                 dbus_error_free(&derr);
494         } else {
495                 dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING,
496                                         &phonebook_entry, DBUS_TYPE_INVALID);
497                 DBG("phonebook_entry:[%s]\n", phonebook_entry);
498         }
499
500         s_data->cb(phonebook_entry, strlen(phonebook_entry), 1, 0, TRUE,
501                                                         s_data->user_data);
502
503         dbus_message_unref(reply);
504 }
505
506 int get_phonebook_data(const char *query, const char *call_type,
507                                 struct phonebook_tizen_data *s_data)
508 {
509         DBusConnection *conn;
510         DBusPendingCall *call;
511         DBusMessage *message;
512
513         DBG("call_type:%s", call_type);
514
515         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
516         if (!conn) {
517                 error("Can't get on session bus");
518                 return -1;
519         }
520
521         message = dbus_message_new_method_call("org.bluez.pb_agent",
522                                                         "/org/bluez/pb_agent",
523                                                         "org.bluez.PbAgent",
524                                                         query);
525         if (!message) {
526                 error("Can't allocate new message");
527                 return -1;
528         }
529
530         if (s_data->id) {
531                 DBG("phonebook_get_entry");
532                 dbus_message_append_args(message, DBUS_TYPE_STRING, &s_data->id,
533                                                         DBUS_TYPE_INVALID);
534         } else if (s_data->params) {
535                 DBG("phonebook_pull_read");
536                 if (call_type)
537                         dbus_message_append_args(message, DBUS_TYPE_UINT16,
538                                                 &s_data->params->maxlistcount,
539                                                 DBUS_TYPE_UINT16,
540                                                 &s_data->params->liststartoffset,
541                                                 DBUS_TYPE_STRING, &call_type,
542                                                 DBUS_TYPE_INVALID);
543                 else
544                         dbus_message_append_args(message, DBUS_TYPE_UINT16,
545                                                 &s_data->params->maxlistcount,
546                                                 DBUS_TYPE_UINT16,
547                                                 &s_data->params->liststartoffset,
548                                                 DBUS_TYPE_INVALID);
549
550         } else if (call_type) {
551                 DBG("phonebook_create_cache");
552                 dbus_message_append_args(message, DBUS_TYPE_STRING, &call_type,
553                                                         DBUS_TYPE_INVALID);
554         }
555
556         if (dbus_connection_send_with_reply(conn, message, &call,
557                                                         -1) == FALSE) {
558                 error("Could not send dbus message");
559                 dbus_message_unref(message);
560                 return -1;
561         }
562
563         dbus_pending_call_set_notify(call, s_data->reply_cb, s_data, NULL);
564         dbus_message_unref(message);
565
566         //dbus_connection_unref(conn);
567
568         return 0;
569 }
570
571 static gboolean get_sim_phonebook_reply(void *user_data)
572 {
573         struct phonebook_tizen_data *s_data = user_data;
574         uint32_t phonebook_size = 0;
575         int lastpart = 1;
576
577         DBG("");
578
579         /* We don't support phonebook of SIM
580          * Send dummy data */
581         s_data->cb(NULL, 0, phonebook_size, 0, lastpart, s_data->user_data);
582
583         return FALSE;
584 }
585