Merge branch 'master' into tizen_2.1
[platform/core/connectivity/bluetooth-agent.git] / pb-agent / bluetooth_pb_agent.c
1 /*
2  * bluetooth-agent
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <glib.h>
26 #include <dbus/dbus-glib.h>
27
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32
33 #include <contacts.h>
34
35 #include <TapiUtility.h>
36 #include <ITapiSim.h>
37
38 #include "bluetooth_pb_agent.h"
39 #include "bluetooth_pb_vcard.h"
40
41 #define BLUETOOTH_PB_AGENT_TIMEOUT 600
42
43 static gchar *bluetooth_pb_agent_folder_list[] = {
44         "/telecom/pb",
45         "/telecom/ich",
46         "/telecom/och",
47         "/telecom/mch",
48         "/telecom/cch",
49         NULL
50 };
51
52 typedef enum {
53         TELECOM_PB = 0,
54         TELECOM_ICH,
55         TELECOM_OCH,
56         TELECOM_MCH,
57         TELECOM_CCH,
58         TELECOM_NONE
59 } PhoneBookType;
60
61 typedef struct {
62         GObject parent;
63
64         DBusGConnection *bus;
65         DBusGProxy *proxy;
66
67         TapiHandle *tapi_handle;
68         gchar *tel_number;
69
70         GHashTable *contact_list;
71
72         guint timeout_id;
73
74         PhoneBookType pb_type;
75 } BluetoothPbAgent;
76
77 typedef struct {
78         GObjectClass parent;
79
80         void (*clear) (BluetoothPbAgent *agent);
81 } BluetoothPbAgentClass;
82
83 enum {
84         CLEAR,
85         LAST_SIGNAL
86 };
87
88 GType bluetooth_pb_agent_get_type(void);
89
90 #define BLUETOOTH_PB_TYPE_AGENT (bluetooth_pb_agent_get_type())
91
92 #define BLUETOOTH_PB_AGENT(object) \
93         (G_TYPE_CHECK_INSTANCE_CAST((object), \
94         BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgent))
95 #define BLUETOOTH_PB_AGENT_CLASS(klass) \
96         (G_TYPE_CHECK_CLASS_CAST((klass), \
97         BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgentClass))
98 #define BLUETOOTH_IS_PB_AGENT(object) \
99         (G_TYPE_CHECK_INSTANCE_TYPE((object), \
100         BLUETOOTH_PB_TYPE_AGENT))
101 #define BLUETOOTH_IS_PB_AGENT_CLASS(klass) \
102         (G_TYPE_CHECK_CLASS_TYPE((klass), \
103         BLUETOOTH_PB_TYPE_AGENT))
104 #define BLUETOOTH_PB_AGENT_GET_CLASS(obj) \
105         (G_TYPE_INSTANCE_GET_CLASS((obj), \
106         BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgentClass))
107
108 G_DEFINE_TYPE(BluetoothPbAgent, bluetooth_pb_agent, G_TYPE_OBJECT)
109
110 #define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct("GValueArray", G_TYPE_STRING, \
111                                                         G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
112
113 static guint signals[LAST_SIGNAL] = { 0 };
114
115 static GMainLoop *mainloop = NULL;
116
117 static void bluetooth_pb_agent_finalize(GObject *obj);
118
119 static void bluetooth_pb_agent_clear(BluetoothPbAgent *agent);
120
121 /* Dbus messages */
122 static gboolean bluetooth_pb_get_phonebook_folder_list(BluetoothPbAgent *agent,
123                                                 const gchar ***folder_list,
124                                                 GError **error);
125
126 static gboolean bluetooth_pb_get_phonebook(BluetoothPbAgent *agent,
127                                         const char *name,
128                                         guint64 filter,
129                                         guint8 format,
130                                         guint16 max_list_count,
131                                         guint16 list_start_offset,
132                                         DBusGMethodInvocation *context);
133
134 static gboolean bluetooth_pb_get_phonebook_size(BluetoothPbAgent *agent,
135                                                 const char *name,
136                                                 DBusGMethodInvocation *context);
137
138 static gboolean bluetooth_pb_get_phonebook_list(BluetoothPbAgent *agent,
139                                                 const char *name,
140                                                 DBusGMethodInvocation *context);
141
142 static gboolean bluetooth_pb_get_phonebook_entry(BluetoothPbAgent *agent,
143                                                 const gchar *folder,
144                                                 const gchar *id,
145                                                 guint64 filter,
146                                                 guint8 format,
147                                                 DBusGMethodInvocation *context);
148
149 static gboolean bluetooth_pb_get_phonebook_size_at(BluetoothPbAgent *agent,
150                                         const gchar *command,
151                                         DBusGMethodInvocation *context);
152
153 static gboolean bluetooth_pb_get_phonebook_entries_at(BluetoothPbAgent *agent,
154                                         const gchar *command,
155                                         gint32 start_index,
156                                         gint32 end_index,
157                                         DBusGMethodInvocation *context);
158
159 static gboolean bluetooth_pb_get_phonebook_entries_find_at(BluetoothPbAgent *agent,
160                                                         const gchar *command,
161                                                         const gchar *find_text,
162                                                         DBusGMethodInvocation *context);
163
164 static gboolean bluetooth_pb_get_total_object_count(BluetoothPbAgent *agent,
165                                                 gchar *path,
166                                                 DBusGMethodInvocation *context);
167
168 static gboolean bluetooth_pb_add_contact (BluetoothPbAgent *agent,
169                                         const char *filename,
170                                         GError **error);
171
172 static gboolean bluetooth_pb_destroy_agent(BluetoothPbAgent *agent,
173                                         DBusGMethodInvocation *context);
174
175 static void __bluetooth_pb_dbus_return_error(DBusGMethodInvocation *context,
176                                         gint code,
177                                         const gchar *message);
178
179 static PhoneBookType __bluetooth_pb_get_pb_type(const char *name);
180
181 static PhoneBookType __bluetooth_pb_get_storage_pb_type(const char *name);
182
183 static gint __bluetooth_pb_phone_log_filter_append(contacts_filter_h filter,
184                                                 gint *match,
185                                                 gint size);
186
187 static contacts_query_h __bluetooth_pb_query_phone_log(gint *match,
188                                                 gint size);
189
190 static contacts_query_h __bluetooth_pb_query_person(void);
191
192 static contacts_query_h __bluetooth_pb_query_person_number(void);
193
194 static contacts_query_h __bluetooth_pb_query_phone_log_incoming(void);
195
196 static contacts_query_h __bluetooth_pb_query_phone_log_outgoing(void);
197
198 static contacts_query_h __bluetooth_pb_query_phone_log_missed(void);
199
200 static contacts_query_h __bluetooth_pb_query_phone_log_combined(void);
201
202 static gboolean __bluetooth_pb_get_count(PhoneBookType pb_type,
203                                 guint *count);
204
205 static gboolean __bluetooth_pb_get_count_new_missed_call(guint *count);
206
207 static const char *__bluetooth_pb_phone_log_get_log_type(contacts_record_h record);
208
209 static void __bluetooth_pb_get_vcards(BluetoothPbAgent *agent,
210                                 PhoneBookType pb_type,
211                                 guint64 filter,
212                                 guint8 format,
213                                 guint16 max_list_count,
214                                 guint16 list_start_offset,
215                                 GPtrArray *vcards);
216
217 static void __bluetooth_pb_get_contact_list(BluetoothPbAgent *agent,
218                                         contacts_query_h query,
219                                         GPtrArray *ptr_array);
220
221 static void __bluetooth_pb_get_phone_log_list(BluetoothPbAgent *agent,
222                                         contacts_query_h query,
223                                         GPtrArray *ptr_array);
224
225 static void __bluetooth_pb_get_list(BluetoothPbAgent *agent,
226                                 PhoneBookType pb_type,
227                                 GPtrArray *ptr_array);
228
229 static void __bluetooth_pb_get_contact_list_number(BluetoothPbAgent *agent,
230                                                 contacts_query_h query,
231                                                 gint start_index,
232                                                 gint end_index,
233                                                 GPtrArray *ptr_array);
234
235 static void __bluetooth_pb_get_phone_log_list_number(BluetoothPbAgent *agent,
236                                                 contacts_query_h query,
237                                                 gint start_index,
238                                                 gint end_index,
239                                                 GPtrArray *ptr_array);
240
241 static void __bluetooth_pb_get_list_number(BluetoothPbAgent *agent,
242                                                 PhoneBookType pb_type,
243                                                 gint start_index,
244                                                 gint end_index,
245                                                 GPtrArray *ptr_array);
246
247 static void __bluetooth_pb_get_contact_list_name(BluetoothPbAgent *agent,
248                                                 contacts_query_h query,
249                                                 const gchar *find_text,
250                                                 GPtrArray *ptr_array);
251
252 static void __bluetooth_pb_get_phone_log_list_name(BluetoothPbAgent *agent,
253                                                 contacts_query_h query,
254                                                 const gchar *find_text,
255                                                 GPtrArray *ptr_array);
256
257 static void __bluetooth_pb_get_list_name(BluetoothPbAgent *agent,
258                                         PhoneBookType pb_type,
259                                         const gchar *find_text,
260                                         GPtrArray *ptr_array);
261
262 static void __bluetooth_pb_list_hash_reset(BluetoothPbAgent *agent);
263
264 static gboolean __bluetooth_pb_list_hash_insert(BluetoothPbAgent *agent,
265                                                 gint handle,
266                                                 gint id);
267
268 static gint __bluetooth_pb_list_hash_lookup_id(BluetoothPbAgent *agent,
269                                         gint handle);
270
271 static void __bluetooth_pb_list_ptr_array_add(GPtrArray *ptr_array,
272                                                 const gchar *name,
273                                                 const gchar *number,
274                                                 gint handle);
275
276 static void __bluetooth_pb_list_ptr_array_free(gpointer data);
277
278 static void __bluetooth_pb_agent_signal_handler(int signum);
279
280 static void __bluetooth_pb_contact_changed(const gchar *view_uri,
281                                         void *user_data);
282
283 static void __bluetooth_pb_agent_timeout_add_seconds(BluetoothPbAgent *agent);
284
285 static gboolean __bluetooth_pb_agent_timeout_calback(gpointer user_data);
286
287 static void __bluetooth_pb_tel_callback(TapiHandle *handle,
288                                         int result,
289                                         void *data,
290                                         void *user_data);
291
292 static void __bluetooth_pb_agent_dbus_init(BluetoothPbAgent *agent);
293
294 #include "bluetooth_pb_agent_glue.h"
295
296 static void bluetooth_pb_agent_init(BluetoothPbAgent *agent)
297 {
298         agent->bus = NULL;
299         agent->proxy = NULL;
300
301         agent->tapi_handle = NULL;
302         agent->tel_number = NULL;
303
304         agent->contact_list = NULL;
305         agent->timeout_id = 0;
306
307         agent->pb_type = TELECOM_NONE;
308 }
309
310 static void bluetooth_pb_agent_class_init(BluetoothPbAgentClass *klass)
311 {
312         GObjectClass *object_class = (GObjectClass *) klass;
313
314         klass->clear = bluetooth_pb_agent_clear;
315
316         object_class->finalize = bluetooth_pb_agent_finalize;
317
318         signals[CLEAR] = g_signal_new("clear",
319                         G_TYPE_FROM_CLASS(klass),
320                         G_SIGNAL_RUN_LAST,
321                         G_STRUCT_OFFSET(BluetoothPbAgentClass, clear),
322                         NULL, NULL,
323                         g_cclosure_marshal_VOID__VOID,
324                         G_TYPE_NONE, 0);
325
326         dbus_g_object_type_install_info(BLUETOOTH_PB_TYPE_AGENT,
327                                         &dbus_glib_bluetooth_pb_object_info);
328 }
329
330 static void bluetooth_pb_agent_finalize(GObject *obj)
331 {
332         BluetoothPbAgent *agent  = BLUETOOTH_PB_AGENT(obj);
333
334         DBG("+\n");
335
336         if (agent->tapi_handle) {
337                 tel_deinit(agent->tapi_handle);
338                 agent->tapi_handle = NULL;
339         }
340
341         if (agent->tel_number) {
342                 g_free(agent->tel_number);
343                 agent->tel_number = NULL;
344         }
345
346         if(agent->timeout_id) {
347                 g_source_remove(agent->timeout_id);
348                 agent->timeout_id = 0;
349         }
350
351         if (agent->contact_list) {
352                 g_hash_table_destroy(agent->contact_list);
353                 agent->contact_list = NULL;
354         }
355
356         if (agent->proxy) {
357                 g_object_unref(agent->proxy);
358                 agent->proxy = NULL;
359         }
360
361         if (agent->bus) {
362                 dbus_g_connection_unref(agent->bus);
363                 agent->bus = NULL;
364         }
365
366
367         G_OBJECT_CLASS(bluetooth_pb_agent_parent_class)->finalize(obj);
368 }
369
370 static void bluetooth_pb_agent_clear(BluetoothPbAgent *agent)
371 {
372         DBG("+\n");
373
374         if (agent->contact_list) {
375                 g_hash_table_destroy(agent->contact_list);
376                 agent->contact_list = NULL;
377         }
378
379         agent->pb_type = TELECOM_NONE;
380 }
381
382 static gboolean bluetooth_pb_get_phonebook_folder_list(BluetoothPbAgent *agent,
383                                                 const gchar ***folder_list,
384                                                 GError **error)
385 {
386         gint size;
387         gint i;
388         gchar **folder;
389
390         size = G_N_ELEMENTS(bluetooth_pb_agent_folder_list);
391         folder = g_new0(gchar *, size);
392
393         for (i = 0; i < size; i++)
394                 folder[i] = g_strdup(bluetooth_pb_agent_folder_list[i]);
395
396         *folder_list = (const gchar **)folder;
397
398         return TRUE;
399 }
400
401 static gboolean bluetooth_pb_get_phonebook(BluetoothPbAgent *agent,
402                                         const char *name,
403                                         guint64 filter,
404                                         guint8 format,
405                                         guint16 max_list_count,
406                                         guint16 list_start_offset,
407                                         DBusGMethodInvocation *context)
408 {
409         PhoneBookType pb_type = TELECOM_NONE;
410         GPtrArray *vcards = NULL;
411         gchar **vcards_str = NULL;
412
413         guint new_missed_call = 0;
414
415         DBG("name: %s filter: %lld format: %d max_list_count: %d list_start_offset: %d\n",
416                         name, filter, format, max_list_count, list_start_offset);
417
418         __bluetooth_pb_agent_timeout_add_seconds(agent);
419
420         pb_type = __bluetooth_pb_get_pb_type(name);
421
422         if (pb_type == TELECOM_NONE) {
423                 __bluetooth_pb_dbus_return_error(context,
424                                         G_FILE_ERROR_INVAL,
425                                         "unsupported name defined");
426                 return FALSE;
427         }
428
429         vcards = g_ptr_array_new();
430
431         if (max_list_count > 0) {
432                 __bluetooth_pb_get_vcards(agent, pb_type,
433                                 filter, format,
434                                 max_list_count, list_start_offset,
435                                 vcards);
436
437         }
438
439         g_ptr_array_add(vcards, NULL);
440
441         vcards_str = (gchar **) g_ptr_array_free(vcards, FALSE);
442
443         dbus_g_method_return(context, vcards_str, new_missed_call);
444
445         g_strfreev(vcards_str);
446
447         return TRUE;
448 }
449
450 static gboolean bluetooth_pb_get_phonebook_size(BluetoothPbAgent *agent,
451                                                 const char *name,
452                                                 DBusGMethodInvocation *context)
453 {
454         PhoneBookType pb_type = TELECOM_NONE;
455
456         guint new_missed_call = 0;
457         guint count = 0;
458
459         DBG("name: %s\n", name);
460
461         __bluetooth_pb_agent_timeout_add_seconds(agent);
462
463         pb_type = __bluetooth_pb_get_pb_type(name);
464
465         if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) {
466                 __bluetooth_pb_dbus_return_error(context,
467                                         G_FILE_ERROR_INVAL,
468                                         "unsupported name defined");
469                 return FALSE;
470         }
471
472         /* for owner */
473         if (pb_type == TELECOM_PB)
474                 count++;
475
476         __bluetooth_pb_get_count_new_missed_call(&new_missed_call);
477
478         dbus_g_method_return(context, count, new_missed_call);
479
480         return TRUE;
481 }
482
483
484 static gboolean bluetooth_pb_get_phonebook_list(BluetoothPbAgent *agent,
485                                                 const char *name,
486                                                 DBusGMethodInvocation *context)
487 {
488         PhoneBookType pb_type = TELECOM_NONE;
489
490         GPtrArray *ptr_array;
491
492         DBG("name: %s\n", name);
493
494         __bluetooth_pb_agent_timeout_add_seconds(agent);
495
496         pb_type = __bluetooth_pb_get_pb_type(name);
497
498         if (pb_type == TELECOM_NONE) {
499                 __bluetooth_pb_dbus_return_error(context,
500                                         G_FILE_ERROR_INVAL,
501                                         "unsupported name defined");
502                 return FALSE;
503         }
504
505         ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free);
506
507         __bluetooth_pb_get_list(agent, pb_type, ptr_array);
508
509         dbus_g_method_return(context, ptr_array);
510
511         if (ptr_array)
512                 g_ptr_array_free(ptr_array, TRUE);
513
514         return TRUE;
515 }
516
517
518 static gboolean bluetooth_pb_get_phonebook_entry(BluetoothPbAgent *agent,
519                                                 const gchar *folder,
520                                                 const gchar *id,
521                                                 guint64 filter,
522                                                 guint8 format,
523                                                 DBusGMethodInvocation *context)
524 {
525         PhoneBookType pb_type = TELECOM_NONE;
526
527         gint handle = 0;
528         gint cid = -1;
529         gchar *str = NULL;
530
531         const gchar *attr = NULL;
532
533         DBG("folder: %s id: %s filter: %ld format: %d\n",
534                         folder, id, filter, format);
535
536         __bluetooth_pb_agent_timeout_add_seconds(agent);
537
538         if (!g_str_has_suffix(id, ".vcf")) {
539                 __bluetooth_pb_dbus_return_error(context,
540                                         G_FILE_ERROR_INVAL,
541                                         "invalid vcf file");
542                 return FALSE;
543         }
544
545         handle = (gint)g_ascii_strtoll(id, NULL, 10);
546
547         pb_type = __bluetooth_pb_get_pb_type(folder);
548
549         if (pb_type == TELECOM_NONE) {
550                 __bluetooth_pb_dbus_return_error(context,
551                                 G_FILE_ERROR_INVAL,
552                                 "unsupported name defined");
553                 return FALSE;
554         }
555
556         /* create index cache */
557         __bluetooth_pb_get_list(agent, pb_type, NULL);
558
559         cid = __bluetooth_pb_list_hash_lookup_id(agent, handle);
560
561         switch(pb_type) {
562         case TELECOM_PB:
563                 if (handle == 0) {
564                         str = _bluetooth_pb_vcard_contact_owner(agent->tel_number,
565                                                                 filter, format);
566                 } else {
567                         str = _bluetooth_pb_vcard_contact(cid, filter, format);
568                 }
569                 break;
570         case TELECOM_ICH:
571                 str = _bluetooth_pb_vcard_call(cid, filter, format, "RECEIVED");
572                 break;
573         case TELECOM_OCH:
574                 str = _bluetooth_pb_vcard_call(cid, filter, format, "DIALED");
575                 break;
576         case TELECOM_MCH:
577                 str = _bluetooth_pb_vcard_call(cid, filter, format, "MISSED");
578                 break;
579         case TELECOM_CCH: {
580                 contacts_record_h record = NULL;
581
582                 gint status;
583
584                 status = contacts_db_get_record(_contacts_phone_log._uri,
585                                 cid, &record);
586
587                 if (status != CONTACTS_ERROR_NONE)
588                         break;
589
590                 attr = __bluetooth_pb_phone_log_get_log_type(record);
591                 str = _bluetooth_pb_vcard_call(cid, filter, format, attr);
592
593                 contacts_record_destroy(record, TRUE);
594                 break;
595         }
596         default:
597                 __bluetooth_pb_dbus_return_error(context,
598                                         G_FILE_ERROR_INVAL,
599                                         "unsupported name defined");
600                 return FALSE;
601         }
602
603         dbus_g_method_return(context, str);
604         g_free(str);
605
606         return TRUE;
607 }
608
609 static gboolean bluetooth_pb_get_phonebook_size_at(BluetoothPbAgent *agent,
610                                         const gchar *command,
611                                         DBusGMethodInvocation *context)
612 {
613         PhoneBookType pb_type = TELECOM_NONE;
614         guint count = 0;
615
616         DBG("command: %s\n", command);
617
618         __bluetooth_pb_agent_timeout_add_seconds(agent);
619
620         pb_type = __bluetooth_pb_get_storage_pb_type(command);
621
622         if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) {
623                 __bluetooth_pb_dbus_return_error(context,
624                                         G_FILE_ERROR_INVAL,
625                                         "unsupported name defined");
626                 return FALSE;
627         }
628
629         dbus_g_method_return(context, count);
630
631         return TRUE;
632 }
633
634 static gboolean bluetooth_pb_get_phonebook_entries_at(BluetoothPbAgent *agent,
635                                         const gchar *command,
636                                         gint start_index,
637                                         gint end_index,
638                                         DBusGMethodInvocation *context)
639 {
640         PhoneBookType pb_type = TELECOM_NONE;
641
642         GPtrArray *ptr_array = NULL;
643
644         DBG("command: %s, start_index: %d, end_index: %d\n",
645                         command, start_index, end_index);
646
647         __bluetooth_pb_agent_timeout_add_seconds(agent);
648
649         pb_type = __bluetooth_pb_get_storage_pb_type(command);
650
651         if (pb_type == TELECOM_NONE || pb_type == TELECOM_CCH) {
652                 __bluetooth_pb_dbus_return_error(context,
653                                         G_FILE_ERROR_INVAL,
654                                         "unsupported name defined");
655                 return FALSE;
656         }
657
658         ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free);
659
660         __bluetooth_pb_get_list_number(agent, pb_type,
661                         start_index, end_index,
662                         ptr_array);
663
664         dbus_g_method_return(context, ptr_array);
665
666         if (ptr_array)
667                 g_ptr_array_free(ptr_array, TRUE);
668
669         return TRUE;
670 }
671
672 static gboolean bluetooth_pb_get_phonebook_entries_find_at(BluetoothPbAgent *agent,
673                                                         const gchar *command,
674                                                         const gchar *find_text,
675                                                         DBusGMethodInvocation *context)
676 {
677         PhoneBookType pb_type = TELECOM_NONE;
678
679         GPtrArray *ptr_array = NULL;
680
681         DBG("command: %s, find text: %s\n", command, find_text);
682
683         __bluetooth_pb_agent_timeout_add_seconds(agent);
684
685         pb_type = __bluetooth_pb_get_storage_pb_type(command);
686
687         if (pb_type == TELECOM_NONE || pb_type == TELECOM_CCH) {
688                 __bluetooth_pb_dbus_return_error(context,
689                                         G_FILE_ERROR_INVAL,
690                                         "unsupported name defined");
691                 return FALSE;
692         }
693
694         ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free);
695
696         __bluetooth_pb_get_list_name(agent, pb_type,
697                         find_text, ptr_array);
698
699         dbus_g_method_return(context, ptr_array);
700
701         if (ptr_array)
702                 g_ptr_array_free(ptr_array, TRUE);
703
704         return TRUE;
705 }
706
707 static gboolean bluetooth_pb_get_total_object_count(BluetoothPbAgent *agent,
708                                         gchar *path, DBusGMethodInvocation *context)
709 {
710         guint count = 0;
711         PhoneBookType pb_type = TELECOM_NONE;
712
713         DBG("%s() %d\n", __FUNCTION__, __LINE__);
714
715         __bluetooth_pb_agent_timeout_add_seconds(agent);
716
717         pb_type = __bluetooth_pb_get_storage_pb_type(path);
718
719         if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) {
720                 __bluetooth_pb_dbus_return_error(context,
721                                         G_FILE_ERROR_INVAL,
722                                         "unsupported name defined");
723                 return FALSE;
724         }
725
726         dbus_g_method_return(context, count);
727
728         DBG("%s() %d\n", __FUNCTION__, __LINE__);
729
730         return TRUE;
731 }
732
733
734 #if 0
735 static int __bluetooth_pb_agent_read_file(const char *file_path, char **stream)
736 {
737         FILE *fp = NULL;
738         int read_len = -1;
739         int received_file_size = 0;
740         struct stat file_attr;
741
742         if (file_path == NULL || stream == NULL) {
743                 DBG("Invalid data \n");
744                 return -1;
745         }
746
747         DBG("file_path = %s\n", file_path);
748
749         if ((fp = fopen(file_path, "r+")) == NULL) {
750                 DBG("Cannot open %s\n", file_path);
751                 return -1;
752         }
753
754         if (fstat(fileno(fp), &file_attr) == 0) {
755                 received_file_size = file_attr.st_size;
756                 DBG("file_attr.st_size = %d, size = %d\n", file_attr.st_size, received_file_size);
757
758                 if (received_file_size <= 0) {
759                         DBG("Some problem in the file size [%s]  \n", file_path);
760                         fclose(fp);
761                         fp = NULL;
762                         return -1;
763                 }
764
765                 *stream = (char *)malloc(sizeof(char) * received_file_size);
766                 if (NULL == *stream) {
767                         fclose(fp);
768                         fp = NULL;
769                         return -1;
770                 }
771         } else {
772                 DBG("Some problem in the file [%s]  \n", file_path);
773                 fclose(fp);
774                 fp = NULL;
775                 return -1;
776         }
777
778         read_len = fread(*stream, 1, received_file_size, fp);
779
780         if (read_len == 0) {
781                 if (fp != NULL) {
782                         fclose(fp);
783                         fp = NULL;
784                 }
785                 DBG("Cannot open %s\n", file_path);
786                 return -1;
787         }
788
789         if (fp != NULL) {
790                 fclose(fp);
791                 fp = NULL;
792         }
793         return 0;
794 }
795 #endif
796
797 static gboolean bluetooth_pb_add_contact(BluetoothPbAgent *agent, const char *filename,
798                                          GError **error)
799 {
800         /* Contact API is changed, Temporary blocked */
801 #if 0
802         CTSstruct *contact_record = NULL;
803         GSList *numbers_list = NULL, *cursor;
804         int is_success = 0;
805         int is_duplicated = 0;
806         int err = 0;
807         char *stream = NULL;
808
809         DBG("file_path = %s\n", filename);
810
811         err = contacts_svc_connect();
812         DBG("contact_db_service_connect fucntion call [error] = %d \n", err);
813
814         err = __bluetooth_pb_agent_read_file(filename, &stream);
815
816         if (err != 0) {
817                 contacts_svc_disconnect();
818                 DBG("contacts_svc_disconnect fucntion call [error] = %d \n", err);
819
820                 if (NULL != stream) {
821                         free(stream);
822                         stream = NULL;
823                 }
824                 return FALSE;
825         }
826
827         is_success = contacts_svc_get_contact_from_vcard((const void *)stream, &contact_record);
828
829         DBG("contacts_svc_get_contact_from_vcard fucntion call [is_success] = %d \n", is_success);
830
831         if (0 == is_success) {
832                 contacts_svc_struct_get_list(contact_record, CTS_CF_NUMBER_LIST, &numbers_list);
833                 cursor = numbers_list;
834
835                 for (; cursor; cursor = g_slist_next(cursor)) {
836                         if (contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER,
837                                                         contacts_svc_value_get_str(cursor->data,
838                                                                 CTS_NUM_VAL_NUMBER_STR)) > 0) {
839                                 DBG("is_duplicated\n");
840                                 is_duplicated = TRUE;
841                         }
842                 }
843
844                 if (is_duplicated == FALSE) {
845                         contacts_svc_insert_contact(0, contact_record);
846                 }
847         } else {
848                 DBG("Fail \n");
849         }
850
851         err = contacts_svc_disconnect();
852         DBG("contacts_svc_disconnect fucntion call [error] = %d \n", err);
853
854         if (NULL != stream) {
855                 free(stream);
856                 stream = NULL;
857         }
858 #endif
859
860         return TRUE;
861 }
862
863 static void __bluetooth_pb_dbus_return_error(DBusGMethodInvocation *context,
864                                         gint code,
865                                         const gchar *message)
866 {
867         GQuark quark;
868         GError *error = NULL;
869
870         quark = g_type_qname(bluetooth_pb_agent_get_type());
871         error = g_error_new_literal(quark, code, message);
872
873         DBG("%s\n", message);
874
875         dbus_g_method_return_error(context, error);
876         g_error_free(error);
877 }
878
879 static PhoneBookType __bluetooth_pb_get_pb_type(const char *name)
880 {
881         gchar *suffix = ".vcf";
882         gint len;
883         gint size;
884         gint i;
885
886         if (name == NULL)
887                 return TELECOM_NONE;
888
889         len = strlen(name);
890
891         if (g_str_has_suffix(name, suffix))
892                 len -= strlen(suffix);
893
894         size = G_N_ELEMENTS(bluetooth_pb_agent_folder_list) - 1;
895         for (i = 0; i < size; i++) {
896                 if (strncmp(name, bluetooth_pb_agent_folder_list[i], len) == 0)
897                         return i;
898         }
899
900         return TELECOM_NONE;
901 }
902
903 static PhoneBookType __bluetooth_pb_get_storage_pb_type(const char *name)
904 {
905         if (name == NULL)
906                 return TELECOM_NONE;
907
908         if (g_strcmp0(name, "\"ME\"") == 0 )
909                 return TELECOM_PB;
910
911         if (g_strcmp0(name, "\"RC\"") == 0)
912                 return TELECOM_ICH;
913
914         if (g_strcmp0(name, "\"DC\"") == 0)
915                 return TELECOM_OCH;
916
917         if (g_strcmp0(name, "\"MC\"") == 0)
918                 return TELECOM_MCH;
919
920         return TELECOM_NONE;
921 }
922
923 static gint __bluetooth_pb_phone_log_filter_append(contacts_filter_h filter,
924                                                 gint *match,
925                                                 gint size)
926 {
927         gint i;
928         gint status;
929
930         for (i = 0; i < size; i++) {
931
932                 if ( i > 0) {
933                         status = contacts_filter_add_operator(filter,
934                                         CONTACTS_FILTER_OPERATOR_OR);
935
936                         if (status != CONTACTS_ERROR_NONE)
937                                 return status;
938                 }
939
940                 status = contacts_filter_add_int(filter,
941                                 _contacts_phone_log.log_type,
942                                 CONTACTS_MATCH_EQUAL,
943                                 match[i]);
944
945                 if (status != CONTACTS_ERROR_NONE)
946                         return status;
947         }
948
949         return CONTACTS_ERROR_NONE;
950 }
951
952 static contacts_query_h __bluetooth_pb_query_phone_log(gint *match,
953                                                 gint size)
954 {
955         contacts_query_h query = NULL;
956         contacts_filter_h filter = NULL;
957
958         gint status;
959
960         status = contacts_query_create(_contacts_phone_log._uri,
961                                 &query);
962
963         if (status != CONTACTS_ERROR_NONE)
964                 return NULL;
965
966         status = contacts_filter_create(_contacts_phone_log._uri, &filter);
967
968         if (status != CONTACTS_ERROR_NONE) {
969                 contacts_query_destroy(query);
970                 return NULL;
971         }
972
973         status = __bluetooth_pb_phone_log_filter_append(filter, match, size);
974
975         if (status != CONTACTS_ERROR_NONE) {
976                 contacts_filter_destroy(filter);
977                 contacts_query_destroy(query);
978                 return NULL;
979         }
980
981         status = contacts_query_set_filter(query, filter);
982
983         if (status != CONTACTS_ERROR_NONE) {
984                 contacts_filter_destroy(filter);
985                 contacts_query_destroy(query);
986                 return NULL;
987         }
988
989         status = contacts_query_set_sort(query,
990                         _contacts_phone_log.log_time,
991                         false);
992
993         if (status != CONTACTS_ERROR_NONE) {
994                 contacts_filter_destroy(filter);
995                 contacts_query_destroy(query);
996                 return NULL;
997         }
998
999         contacts_filter_destroy(filter);
1000
1001         return query;
1002 }
1003
1004 static contacts_query_h __bluetooth_pb_query_person(void)
1005 {
1006         contacts_query_h query = NULL;
1007
1008         gint status;
1009
1010         status = contacts_query_create(_contacts_person._uri,
1011                         &query);
1012
1013         if (status != CONTACTS_ERROR_NONE)
1014                 return NULL;
1015
1016         return query;
1017 }
1018
1019 static contacts_query_h __bluetooth_pb_query_person_number(void)
1020 {
1021         contacts_query_h query = NULL;
1022
1023         gint status;
1024
1025         status = contacts_query_create(_contacts_person_number._uri,
1026                                 &query);
1027
1028         if (status != CONTACTS_ERROR_NONE)
1029                 return NULL;
1030
1031         return query;
1032 }
1033
1034 static contacts_query_h __bluetooth_pb_query_phone_log_incoming(void)
1035 {
1036         gint size = 2;
1037         gint match[] = {
1038                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING,
1039                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING
1040         };
1041
1042         return __bluetooth_pb_query_phone_log(match, size);
1043 }
1044
1045 static contacts_query_h __bluetooth_pb_query_phone_log_outgoing(void)
1046 {
1047         gint size = 2;
1048         gint match[] = {
1049                 CONTACTS_PLOG_TYPE_VOICE_OUTGOING,
1050                 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING
1051         };
1052
1053         return __bluetooth_pb_query_phone_log(match, size);
1054
1055 }
1056
1057 static contacts_query_h __bluetooth_pb_query_phone_log_missed(void)
1058 {
1059         gint size = 4;
1060         gint match[] = {
1061                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
1062                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN,
1063                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN,
1064                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN
1065         };
1066
1067         return __bluetooth_pb_query_phone_log(match, size);
1068 }
1069
1070 static contacts_query_h __bluetooth_pb_query_phone_log_combined(void)
1071 {
1072         gint size = 8;
1073         gint match[] = {
1074                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING,
1075                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING,
1076                 CONTACTS_PLOG_TYPE_VOICE_OUTGOING,
1077                 CONTACTS_PLOG_TYPE_VIDEO_OUTGOING,
1078                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
1079                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN,
1080                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN,
1081                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN
1082         };
1083
1084         return __bluetooth_pb_query_phone_log(match, size);
1085 }
1086
1087 static gboolean __bluetooth_pb_get_count(PhoneBookType pb_type,
1088                                 guint *count)
1089 {
1090         contacts_query_h query = NULL;
1091
1092         gint status;
1093         gint signed_count;
1094
1095         switch (pb_type) {
1096         case TELECOM_PB:
1097                 query = __bluetooth_pb_query_person();
1098                 break;
1099         case TELECOM_ICH:
1100                 query = __bluetooth_pb_query_phone_log_incoming();
1101                 break;
1102         case TELECOM_OCH:
1103                 query = __bluetooth_pb_query_phone_log_outgoing();
1104                 break;
1105         case TELECOM_MCH:
1106                 query = __bluetooth_pb_query_phone_log_missed();
1107                 break;
1108         case TELECOM_CCH:
1109                 query = __bluetooth_pb_query_phone_log_combined();
1110                 break;
1111         default:
1112                 return FALSE;
1113         }
1114
1115         if (query == NULL)
1116                 return FALSE;
1117
1118         status = contacts_db_get_count_with_query(query, &signed_count);
1119
1120         if (status != CONTACTS_ERROR_NONE) {
1121                 contacts_query_destroy(query);
1122                 return FALSE;
1123         }
1124
1125         contacts_query_destroy(query);
1126
1127         if (signed_count < 0)
1128                 signed_count = 0;
1129
1130         *count = (gint) signed_count;
1131
1132         return TRUE;
1133 }
1134
1135 static gboolean __bluetooth_pb_get_count_new_missed_call(guint *count)
1136 {
1137         contacts_query_h query = NULL;
1138
1139         gint status;
1140         gint signed_count;
1141
1142         gint size = 2;
1143         gint match[] = {
1144                 CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
1145                 CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN
1146         };
1147
1148         query = __bluetooth_pb_query_phone_log(match, size);
1149
1150         if (query == NULL)
1151                 return FALSE;
1152
1153         status = contacts_db_get_count_with_query(query, &signed_count);
1154
1155         if (status != CONTACTS_ERROR_NONE) {
1156                 contacts_query_destroy(query);
1157                 return FALSE;
1158         }
1159
1160         contacts_query_destroy(query);
1161
1162         if (signed_count < 0)
1163                 signed_count = 0;
1164
1165         *count = (guint)signed_count;
1166
1167         return TRUE;
1168 }
1169
1170 static const char *__bluetooth_pb_phone_log_get_log_type(contacts_record_h record)
1171 {
1172         gint status;
1173         gint log_type;
1174
1175         status = contacts_record_get_int(record,
1176                         _contacts_phone_log.log_type,
1177                         &log_type);
1178
1179         if (status != CONTACTS_ERROR_NONE)
1180                 return NULL;
1181
1182         switch (log_type) {
1183         case CONTACTS_PLOG_TYPE_VOICE_INCOMMING:
1184         case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING:
1185                 return "RECEIVED";
1186         case CONTACTS_PLOG_TYPE_VOICE_OUTGOING:
1187         case CONTACTS_PLOG_TYPE_VIDEO_OUTGOING:
1188                 return "DIALED";
1189         case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN:
1190         case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN:
1191         case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN:
1192         case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN:
1193                 return "MISSED";
1194         default:
1195                 return NULL;
1196         }
1197 }
1198
1199 static void __bluetooth_pb_get_vcards(BluetoothPbAgent *agent,
1200                                 PhoneBookType pb_type,
1201                                 guint64 filter,
1202                                 guint8 format,
1203                                 guint16 max_list_count,
1204                                 guint16 list_start_offset,
1205                                 GPtrArray *vcards)
1206 {
1207         contacts_list_h record_list = NULL;
1208         contacts_query_h query = NULL;
1209
1210         gint status;
1211
1212         gint limit;
1213         gint offset;
1214
1215         guint property_id = 0;
1216
1217         const char *attr = NULL;
1218
1219         gboolean get_log = FALSE;
1220
1221         /* contact offset is n - 1 of PBAP */
1222         offset = (gint)list_start_offset - 1;
1223
1224         if ( max_list_count >= 65535)
1225                 limit = -1;     /* contact limit -1 means unrestricted */
1226         else
1227                 limit = (gint)max_list_count;
1228
1229         switch (pb_type) {
1230         case TELECOM_PB:
1231                 /* for owner */
1232                 if (list_start_offset == 0) {
1233                         char *vcard;
1234
1235                         vcard = _bluetooth_pb_vcard_contact_owner(agent->tel_number,
1236                                                                 filter, format);
1237                         if (vcard)
1238                                 g_ptr_array_add(vcards, vcard);
1239
1240                         offset = 0;
1241
1242                         if (limit > 0)
1243                                 limit--;
1244                 }
1245
1246                 query = __bluetooth_pb_query_person();
1247                 property_id = _contacts_person.id;
1248                 break;
1249         case TELECOM_ICH:
1250                 query = __bluetooth_pb_query_phone_log_incoming();
1251                 property_id = _contacts_phone_log.id;
1252                 attr = "RECEIVED";
1253                 break;
1254         case TELECOM_OCH:
1255                 query = __bluetooth_pb_query_phone_log_outgoing();
1256                 property_id = _contacts_phone_log.id;
1257                 attr = "DIALED";
1258                 break;
1259         case TELECOM_MCH:
1260                 query = __bluetooth_pb_query_phone_log_missed();
1261                 property_id = _contacts_phone_log.id;
1262                 attr = "MISSED";
1263                 break;
1264         case TELECOM_CCH:
1265                 query = __bluetooth_pb_query_phone_log_combined();
1266                 property_id = _contacts_phone_log.id;
1267                 get_log = TRUE;
1268                 break;
1269         default:
1270                 return;
1271         }
1272
1273         status = contacts_db_get_records_with_query(query, offset, limit, &record_list);
1274
1275         if (status != CONTACTS_ERROR_NONE) {
1276                 contacts_list_destroy(record_list, TRUE);
1277                 contacts_query_destroy(query);
1278                 return;
1279         }
1280
1281         status = contacts_list_first(record_list);
1282
1283         if (status != CONTACTS_ERROR_NONE) {
1284                 contacts_list_destroy(record_list, TRUE);
1285                 contacts_query_destroy(query);
1286                 return;
1287         }
1288
1289         do {
1290                 contacts_record_h record;
1291
1292                 gint id;
1293
1294                 gchar *vcard = NULL;
1295
1296                 record = NULL;
1297                 status = contacts_list_get_current_record_p(record_list, &record);
1298
1299                 if (status != CONTACTS_ERROR_NONE)
1300                         continue;
1301                 id = 0;
1302                 status = contacts_record_get_int(record, property_id, &id);
1303
1304                 if (status != CONTACTS_ERROR_NONE)
1305                         continue;
1306
1307                 if (property_id == _contacts_person.id)
1308                         vcard = _bluetooth_pb_vcard_contact(id, filter, format);
1309                 else {
1310                         if (get_log)
1311                                 attr = __bluetooth_pb_phone_log_get_log_type(record);
1312
1313                         vcard = _bluetooth_pb_vcard_call(id, filter, format, attr);
1314                 }
1315
1316                 if (vcard)
1317                         g_ptr_array_add(vcards, vcard);
1318
1319         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1320
1321         contacts_list_destroy(record_list, TRUE);
1322         contacts_query_destroy(query);
1323 }
1324
1325 static void __bluetooth_pb_get_contact_list(BluetoothPbAgent *agent,
1326                                         contacts_query_h query,
1327                                         GPtrArray *ptr_array)
1328 {
1329         contacts_list_h record_list = NULL;
1330
1331         gint status;
1332         int i = 1;
1333
1334         /* Add owner */
1335         if (ptr_array) {
1336                 gchar *tmp;
1337                 gchar *name;
1338
1339                 tmp = _bluetooth_pb_owner_name();
1340                 name = g_strdup_printf("%s;;;;", tmp);
1341                 g_free(tmp);
1342
1343                 __bluetooth_pb_list_ptr_array_add(ptr_array,
1344                                 name, agent->tel_number, 0);
1345
1346                 g_free(name);
1347         }
1348
1349         status = contacts_db_get_records_with_query(query,
1350                         -1, -1, &record_list);
1351
1352         if (status != CONTACTS_ERROR_NONE) {
1353                 contacts_list_destroy(record_list, TRUE);
1354                 return;
1355         }
1356
1357         status = contacts_list_first(record_list);
1358
1359         if (status != CONTACTS_ERROR_NONE) {
1360                 contacts_list_destroy(record_list, TRUE);
1361                 contacts_query_destroy(query);
1362                 return;
1363         }
1364
1365         __bluetooth_pb_list_hash_reset(agent);
1366
1367         do {
1368                 contacts_record_h record;
1369
1370                 gint id;
1371
1372                 record = NULL;
1373                 status = contacts_list_get_current_record_p(record_list,
1374                                 &record);
1375
1376                 if (status != CONTACTS_ERROR_NONE)
1377                         continue;
1378
1379                 id = 0;
1380                 status = contacts_record_get_int(record,
1381                                 _contacts_person.id,
1382                                 &id);
1383
1384                 if (status != CONTACTS_ERROR_NONE)
1385                         continue;
1386
1387                 __bluetooth_pb_list_hash_insert(agent, i, id);
1388
1389                 /* create list */
1390                 if (ptr_array) {
1391                         gchar *name;
1392                         gchar *number;
1393
1394                         name = _bluetooth_pb_name_from_person_id(id);
1395                         number = _bluetooth_pb_number_from_person_id(id);
1396
1397                         __bluetooth_pb_list_ptr_array_add(ptr_array,
1398                                         name, number, i);
1399
1400                         g_free(name);
1401                         g_free(number);
1402                 }
1403
1404                 i++;
1405
1406         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1407
1408         contacts_list_destroy(record_list, TRUE);
1409 }
1410
1411 static void __bluetooth_pb_get_phone_log_list(BluetoothPbAgent *agent,
1412                                         contacts_query_h query,
1413                                         GPtrArray *ptr_array)
1414 {
1415         contacts_list_h record_list = NULL;
1416
1417         gint status;
1418         int i = 1;
1419
1420         status = contacts_db_get_records_with_query(query,
1421                         -1, -1, &record_list);
1422
1423         if (status != CONTACTS_ERROR_NONE) {
1424                 contacts_list_destroy(record_list, TRUE);
1425                 return;
1426         }
1427
1428         status = contacts_list_first(record_list);
1429
1430         if (status != CONTACTS_ERROR_NONE) {
1431                 contacts_list_destroy(record_list, TRUE);
1432                 contacts_query_destroy(query);
1433                 return;
1434         }
1435
1436         __bluetooth_pb_list_hash_reset(agent);
1437
1438         do {
1439                 contacts_record_h record;
1440
1441                 gint id;
1442
1443                 record = NULL;
1444                 status = contacts_list_get_current_record_p(record_list,
1445                                 &record);
1446
1447                 if (status != CONTACTS_ERROR_NONE)
1448                         continue;
1449
1450                 id = 0;
1451                 status = contacts_record_get_int(record,
1452                                 _contacts_phone_log.id,
1453                                 &id);
1454
1455                 if (status != CONTACTS_ERROR_NONE)
1456                         continue;
1457
1458                 __bluetooth_pb_list_hash_insert(agent, i, id);
1459
1460                 /* create list */
1461                 if (ptr_array) {
1462                         gchar *name;
1463                         gchar *number;
1464
1465                         name = _bluetooth_pb_name_from_phonelog_id(id);
1466
1467                         number = NULL;
1468                         contacts_record_get_str_p(record,
1469                                         _contacts_phone_log.address,
1470                                         &number);
1471
1472                         __bluetooth_pb_list_ptr_array_add(ptr_array,
1473                                         name, number, i);
1474
1475                         g_free(name);
1476                 }
1477
1478                 i++;
1479
1480         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1481
1482         contacts_list_destroy(record_list, TRUE);
1483 }
1484
1485
1486 static void __bluetooth_pb_get_list(BluetoothPbAgent *agent,
1487                                 PhoneBookType pb_type,
1488                                 GPtrArray *ptr_array)
1489 {
1490         contacts_query_h query;
1491
1492         /* no requires refresh cache */
1493         if (ptr_array == NULL && agent->pb_type == pb_type)
1494                 return;
1495
1496         switch (pb_type) {
1497         case TELECOM_PB:
1498                 query = __bluetooth_pb_query_person();
1499                 __bluetooth_pb_get_contact_list(agent, query, ptr_array);
1500                 break;
1501         case TELECOM_ICH:
1502                 query = __bluetooth_pb_query_phone_log_incoming();
1503                 __bluetooth_pb_get_phone_log_list(agent, query, ptr_array);
1504                 break;
1505         case TELECOM_OCH:
1506                 query = __bluetooth_pb_query_phone_log_outgoing();
1507                 __bluetooth_pb_get_phone_log_list(agent, query, ptr_array);
1508                 break;
1509         case TELECOM_MCH:
1510                 query = __bluetooth_pb_query_phone_log_missed();
1511                 __bluetooth_pb_get_phone_log_list(agent, query, ptr_array);
1512                 break;
1513         case TELECOM_CCH:
1514                 query = __bluetooth_pb_query_phone_log_combined();
1515                 __bluetooth_pb_get_phone_log_list(agent, query, ptr_array);
1516                 break;
1517         default:
1518                 return;
1519         }
1520
1521         agent->pb_type = pb_type;
1522
1523         if (query)
1524                 contacts_query_destroy(query);
1525 }
1526
1527 static void __bluetooth_pb_get_contact_list_number(BluetoothPbAgent *agent,
1528                                                 contacts_query_h query,
1529                                                 gint start_index,
1530                                                 gint end_index,
1531                                                 GPtrArray *ptr_array)
1532 {
1533         contacts_list_h record_list = NULL;
1534
1535         gint status;
1536
1537         gint i;
1538
1539         gint from;
1540         gint to;
1541         gint offset;
1542
1543         from = start_index;
1544         to = end_index;
1545
1546         if (from < 1)
1547                 from = 1;
1548
1549         if (to < 1)
1550                 to = 1;
1551
1552         offset = to - from + 1;
1553         if (offset <= 0)
1554                 return;
1555
1556         i = from;
1557
1558         status = contacts_db_get_records_with_query(query,
1559                         from - 1 , offset,
1560                         &record_list);
1561
1562         if (status != CONTACTS_ERROR_NONE) {
1563                 contacts_list_destroy(record_list, TRUE);
1564                 return;
1565         }
1566
1567         status = contacts_list_first(record_list);
1568
1569         if (status != CONTACTS_ERROR_NONE) {
1570                 contacts_list_destroy(record_list, TRUE);
1571                 return;
1572         }
1573
1574         do {
1575                 contacts_record_h record;
1576
1577                 gchar *display_name;
1578                 gchar *number;
1579
1580                 record = NULL;
1581                 status = contacts_list_get_current_record_p(record_list,
1582                                 &record);
1583
1584                 if (status != CONTACTS_ERROR_NONE)
1585                         continue;
1586
1587                 display_name = NULL;
1588                 number = NULL;
1589
1590                 contacts_record_get_str_p(record,
1591                                 _contacts_person_number.display_name,
1592                                 &display_name);
1593                 contacts_record_get_str_p(record,
1594                                 _contacts_person_number.number,
1595                                 &number);
1596
1597                 __bluetooth_pb_list_ptr_array_add(ptr_array,
1598                                 display_name, number, i);
1599
1600                 i++;
1601         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1602
1603         contacts_list_destroy(record_list, TRUE);
1604 }
1605
1606 static void __bluetooth_pb_get_phone_log_list_number(BluetoothPbAgent *agent,
1607                                                 contacts_query_h query,
1608                                                 gint start_index,
1609                                                 gint end_index,
1610                                                 GPtrArray *ptr_array)
1611 {
1612         contacts_list_h record_list = NULL;
1613
1614         gint status;
1615
1616         gint i;
1617
1618         gint from;
1619         gint to;
1620         gint offset;
1621
1622         from = start_index;
1623         to = end_index;
1624
1625         if (from < 1)
1626                 from = 1;
1627
1628         if (to < 1)
1629                 to = 1;
1630
1631         offset = to - from + 1;
1632         if (offset <= 0)
1633                 return;
1634
1635         i = from;
1636
1637         status = contacts_db_get_records_with_query(query,
1638                         from - 1 , offset,
1639                         &record_list);
1640
1641         if (status != CONTACTS_ERROR_NONE) {
1642                 contacts_list_destroy(record_list, TRUE);
1643                 return;
1644         }
1645
1646         status = contacts_list_first(record_list);
1647         if (status != CONTACTS_ERROR_NONE) {
1648                 contacts_list_destroy(record_list, TRUE);
1649                 return;
1650         }
1651
1652         do {
1653                 contacts_record_h record = NULL;
1654
1655                 gint id;
1656
1657                 gchar *display_name;
1658                 gchar *number;
1659
1660                 record = NULL;
1661                 status = contacts_list_get_current_record_p(record_list,
1662                                 &record);
1663
1664                 if (status != CONTACTS_ERROR_NONE)
1665                         continue;
1666
1667                 id = 0;
1668                 status = contacts_record_get_int(record,
1669                                 _contacts_phone_log.id,
1670                                 &id);
1671
1672                 display_name = _bluetooth_pb_fn_from_phonelog_id(id);
1673
1674                 number = NULL;
1675                 contacts_record_get_str_p(record,
1676                                 _contacts_phone_log.address,
1677                                 &number);
1678
1679
1680                 __bluetooth_pb_list_ptr_array_add(ptr_array,
1681                                 display_name, number, i);
1682
1683                 i++;
1684
1685                 g_free(display_name);
1686
1687         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1688
1689         contacts_list_destroy(record_list, TRUE);
1690 }
1691
1692 static void __bluetooth_pb_get_list_number(BluetoothPbAgent *agent,
1693                                                 PhoneBookType pb_type,
1694                                                 gint start_index,
1695                                                 gint end_index,
1696                                                 GPtrArray *ptr_array)
1697 {
1698         contacts_query_h query;
1699
1700         switch (pb_type) {
1701         case TELECOM_PB:
1702                 query = __bluetooth_pb_query_person_number();
1703                 __bluetooth_pb_get_contact_list_number(agent, query,
1704                                 start_index, end_index, ptr_array);
1705                 break;
1706         case TELECOM_ICH:
1707                 query = __bluetooth_pb_query_phone_log_incoming();
1708                 __bluetooth_pb_get_phone_log_list_number(agent, query,
1709                                 start_index, end_index, ptr_array);
1710                 break;
1711         case TELECOM_OCH:
1712                 query = __bluetooth_pb_query_phone_log_outgoing();
1713                 __bluetooth_pb_get_phone_log_list_number(agent, query,
1714                                 start_index, end_index, ptr_array);
1715                 break;
1716         case TELECOM_MCH:
1717                 query = __bluetooth_pb_query_phone_log_missed();
1718                 __bluetooth_pb_get_phone_log_list_number(agent, query,
1719                                 start_index, end_index, ptr_array);
1720                 break;
1721         case TELECOM_CCH:
1722                 query = __bluetooth_pb_query_phone_log_combined();
1723                 __bluetooth_pb_get_phone_log_list_number(agent, query,
1724                                 start_index, end_index, ptr_array);
1725                 break;
1726         default:
1727                 return;
1728         }
1729
1730         if (query)
1731                 contacts_query_destroy(query);
1732 }
1733
1734 static void __bluetooth_pb_get_contact_list_name(BluetoothPbAgent *agent,
1735                                                 contacts_query_h query,
1736                                                 const gchar *find_text,
1737                                                 GPtrArray *ptr_array)
1738 {
1739         contacts_list_h record_list = NULL;
1740
1741         gint status;
1742         gint i = 1;
1743
1744         status = contacts_db_get_records_with_query(query,
1745                         -1, -1, &record_list);
1746
1747         if (status != CONTACTS_ERROR_NONE) {
1748                 contacts_list_destroy(record_list, TRUE);
1749                 return;
1750         }
1751
1752         status = contacts_list_first(record_list);
1753
1754         if (status != CONTACTS_ERROR_NONE) {
1755                 contacts_list_destroy(record_list, TRUE);
1756                 return;
1757         }
1758
1759         do {
1760                 contacts_record_h record;
1761
1762                 gchar *display_name;
1763
1764                 record = NULL;
1765                 status = contacts_list_get_current_record_p(record_list,
1766                                 &record);
1767
1768                 if (status != CONTACTS_ERROR_NONE)
1769                         continue;
1770
1771                 display_name = NULL;
1772                 contacts_record_get_str_p(record,
1773                                 _contacts_person_number.display_name,
1774                                 &display_name);
1775
1776                 if (g_str_has_prefix(display_name, find_text)) {
1777                         gchar *number;
1778
1779                         number = NULL;
1780                         contacts_record_get_str_p(record,
1781                                         _contacts_person_number.number,
1782                                         &number);
1783
1784                         __bluetooth_pb_list_ptr_array_add(ptr_array,
1785                                         display_name, number, i);
1786                 }
1787
1788                 i++;
1789         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1790         contacts_list_destroy(record_list, TRUE);
1791 }
1792
1793 static void __bluetooth_pb_get_phone_log_list_name(BluetoothPbAgent *agent,
1794                                                 contacts_query_h query,
1795                                                 const gchar *find_text,
1796                                                 GPtrArray *ptr_array)
1797 {
1798         contacts_list_h record_list = NULL;
1799
1800         gint status;
1801
1802         gint i = 1;
1803
1804         status = contacts_db_get_records_with_query(query,
1805                         -1, -1,
1806                         &record_list);
1807
1808         if (status != CONTACTS_ERROR_NONE) {
1809                 contacts_list_destroy(record_list, TRUE);
1810                 return;
1811         }
1812
1813         status = contacts_list_first(record_list);
1814
1815         if (status != CONTACTS_ERROR_NONE) {
1816                 contacts_list_destroy(record_list, TRUE);
1817                 return;
1818         }
1819
1820         do {
1821                 contacts_record_h record = NULL;
1822
1823                 gint id;
1824
1825                 gchar *display_name;
1826
1827                 record = NULL;
1828                 status = contacts_list_get_current_record_p(record_list,
1829                                 &record);
1830
1831                 if (status != CONTACTS_ERROR_NONE)
1832                         continue;
1833
1834                 id = 0;
1835                 status = contacts_record_get_int(record,
1836                                 _contacts_phone_log.id,
1837                                 &id);
1838
1839                 display_name = _bluetooth_pb_fn_from_phonelog_id(id);
1840
1841                 if (g_str_has_prefix(display_name, find_text)) {
1842                         gchar *number = NULL;
1843
1844                         number = NULL;
1845                         contacts_record_get_str_p(record,
1846                                         _contacts_phone_log.address,
1847                                         &number);
1848
1849                         __bluetooth_pb_list_ptr_array_add(ptr_array,
1850                                         display_name, number, i);
1851                 }
1852
1853                 i++;
1854
1855                 g_free(display_name);
1856
1857         } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
1858
1859         contacts_list_destroy(record_list, TRUE);
1860 }
1861
1862 static void __bluetooth_pb_get_list_name(BluetoothPbAgent *agent,
1863                                         PhoneBookType pb_type,
1864                                         const gchar *find_text,
1865                                         GPtrArray *ptr_array)
1866 {
1867         contacts_query_h query;
1868
1869         switch (pb_type) {
1870         case TELECOM_PB:
1871                 query = __bluetooth_pb_query_person_number();
1872                 __bluetooth_pb_get_contact_list_name(agent, query,
1873                                 find_text, ptr_array);
1874                 break;
1875         case TELECOM_ICH:
1876                 query = __bluetooth_pb_query_phone_log_incoming();
1877                 __bluetooth_pb_get_phone_log_list_name(agent, query,
1878                                 find_text, ptr_array);
1879                 break;
1880         case TELECOM_OCH:
1881                 query = __bluetooth_pb_query_phone_log_outgoing();
1882                 __bluetooth_pb_get_phone_log_list_name(agent, query,
1883                                 find_text, ptr_array);
1884                 break;
1885         case TELECOM_MCH:
1886                 query = __bluetooth_pb_query_phone_log_missed();
1887                 __bluetooth_pb_get_phone_log_list_name(agent, query,
1888                                 find_text, ptr_array);
1889                 break;
1890         case TELECOM_CCH:
1891                 query = __bluetooth_pb_query_phone_log_combined();
1892                 __bluetooth_pb_get_phone_log_list_name(agent, query,
1893                                 find_text, ptr_array);
1894                 break;
1895         default:
1896                 return;
1897         }
1898
1899         if (query)
1900                 contacts_query_destroy(query);
1901 }
1902
1903 static void __bluetooth_pb_list_hash_reset(BluetoothPbAgent *agent)
1904 {
1905         if(agent->contact_list)
1906                 g_hash_table_destroy(agent->contact_list);
1907
1908         agent->contact_list = g_hash_table_new(g_direct_hash, g_direct_equal);
1909 }
1910
1911 static gboolean __bluetooth_pb_list_hash_insert(BluetoothPbAgent *agent,
1912                                                 gint handle,
1913                                                 gint id)
1914 {
1915         if (agent->contact_list == NULL)
1916                 return FALSE;
1917
1918         g_hash_table_insert(agent->contact_list,
1919                         GINT_TO_POINTER(handle), GINT_TO_POINTER(id));
1920
1921         return TRUE;
1922 }
1923
1924 static gint __bluetooth_pb_list_hash_lookup_id(BluetoothPbAgent *agent,
1925                                         gint handle)
1926 {
1927         gint id;
1928
1929         if (agent->contact_list == NULL)
1930                 return 0;
1931
1932         id = GPOINTER_TO_INT(g_hash_table_lookup(agent->contact_list,
1933                                 GINT_TO_POINTER(handle)));
1934
1935         return id;
1936 }
1937
1938 static void __bluetooth_pb_list_ptr_array_add(GPtrArray *ptr_array,
1939                                                 const gchar *name,
1940                                                 const gchar *number,
1941                                                 gint handle)
1942 {
1943         GValue value = { 0, };
1944
1945         g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT);
1946         g_value_take_boxed(&value,
1947                         dbus_g_type_specialized_construct(DBUS_STRUCT_STRING_STRING_UINT));
1948
1949         dbus_g_type_struct_set(&value,
1950                                 0, g_strdup(name),
1951                                 1, g_strdup(number),
1952                                 2, handle,
1953                                 G_MAXUINT);
1954
1955         g_ptr_array_add(ptr_array, g_value_get_boxed(&value));
1956 }
1957
1958 static void __bluetooth_pb_list_ptr_array_free(gpointer data)
1959 {
1960         GValue value = { 0, };
1961
1962         gchar *name = NULL;
1963         gchar *number = NULL;
1964
1965         if(data == NULL)
1966                 return;
1967
1968         g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT);
1969         g_value_set_boxed(&value, data);
1970
1971         dbus_g_type_struct_get(&value,
1972                         0, &name,
1973                         1, &number,
1974                         G_MAXUINT);
1975
1976         g_free(name);
1977         g_free(number);
1978 }
1979
1980 static void __bluetooth_pb_agent_signal_handler(int signum)
1981 {
1982         if (mainloop) {
1983                 g_main_loop_quit(mainloop);
1984         } else {
1985                 DBG("Terminate Bluetooth PBAP agent");
1986                 exit(0);
1987         }
1988 }
1989
1990
1991 static void __bluetooth_pb_contact_changed(const gchar *view_uri,
1992                                         void *user_data)
1993 {
1994         BluetoothPbAgent *agent;
1995
1996         g_return_if_fail(BLUETOOTH_IS_PB_AGENT(user_data));
1997         agent = BLUETOOTH_PB_AGENT(user_data);
1998
1999         g_signal_emit(agent, signals[CLEAR], 0);
2000         g_object_unref(agent);
2001 }
2002
2003 static void __bluetooth_pb_agent_timeout_add_seconds(BluetoothPbAgent *agent)
2004 {
2005         g_return_if_fail(BLUETOOTH_IS_PB_AGENT(agent));
2006
2007         if(agent->timeout_id)
2008                 g_source_remove(agent->timeout_id);
2009
2010         agent->timeout_id = g_timeout_add_seconds(BLUETOOTH_PB_AGENT_TIMEOUT,
2011                                 __bluetooth_pb_agent_timeout_calback,
2012                                 agent);
2013 }
2014
2015 static gboolean __bluetooth_pb_agent_timeout_calback(gpointer user_data)
2016 {
2017         BluetoothPbAgent *agent;
2018
2019         g_return_val_if_fail(BLUETOOTH_IS_PB_AGENT(user_data), FALSE);
2020
2021         agent = BLUETOOTH_PB_AGENT(user_data);
2022         agent->timeout_id = 0;
2023
2024         if (mainloop)
2025                 g_main_loop_quit(mainloop);
2026
2027         return FALSE;
2028 }
2029
2030 static void __bluetooth_pb_tel_callback(TapiHandle *handle,
2031                                         int result,
2032                                         void *data,
2033                                         void *user_data)
2034 {
2035         BluetoothPbAgent *agent;
2036         TelSimMsisdnList_t *number;
2037
2038         g_return_if_fail(BLUETOOTH_IS_PB_AGENT(user_data));
2039
2040         agent = BLUETOOTH_PB_AGENT(user_data);
2041
2042         __bluetooth_pb_agent_dbus_init(agent);
2043
2044         number = (TelSimMsisdnList_t *)data;
2045         agent->tel_number = g_strdup(number->list[0].num);
2046
2047         tel_deinit(agent->tapi_handle);
2048         agent->tapi_handle = NULL;
2049 }
2050
2051 static void __bluetooth_pb_agent_dbus_init(BluetoothPbAgent *agent)
2052 {
2053         guint result = 0;
2054         GError *error = NULL;
2055
2056         agent->bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
2057
2058         if (error != NULL) {
2059                 DBG("Couldn't connect to system bus[%s]\n", error->message);
2060                 g_error_free(error);
2061                 return;
2062         }
2063
2064         agent->proxy = dbus_g_proxy_new_for_name(agent->bus,
2065                         DBUS_SERVICE_DBUS,
2066                         DBUS_PATH_DBUS,
2067                         DBUS_INTERFACE_DBUS);
2068
2069         if (agent->proxy == NULL) {
2070                 DBG("Failed to get a proxy for D-Bus\n");
2071                 return;
2072         }
2073
2074         if (!dbus_g_proxy_call(agent->proxy,
2075                                 "RequestName", &error,
2076                                 G_TYPE_STRING, BT_PB_SERVICE_NAME,
2077                                 G_TYPE_UINT, 0,
2078                                 G_TYPE_INVALID,
2079                                 G_TYPE_UINT, &result,
2080                                 G_TYPE_INVALID)) {
2081                 if (error != NULL) {
2082                         DBG("RequestName RPC failed[%s]\n", error->message);
2083                         g_error_free(error);
2084                 }
2085
2086                 g_object_unref(agent->proxy);
2087                 agent->proxy = NULL;
2088
2089                 return;
2090         }
2091         DBG("result : %d %d\n", result, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
2092         if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
2093                 DBG("Failed to get the primary well-known name.\n");
2094
2095                 g_object_unref(agent->proxy);
2096                 agent->proxy = NULL;
2097
2098                 return;
2099         }
2100
2101         g_object_unref(agent->proxy);
2102         agent->proxy = NULL;
2103
2104         dbus_g_connection_register_g_object(agent->bus,
2105                         BT_PB_SERVICE_OBJECT_PATH,
2106                         G_OBJECT(agent));
2107 }
2108
2109 static gboolean bluetooth_pb_destroy_agent(BluetoothPbAgent *agent,
2110                                         DBusGMethodInvocation *context)
2111 {
2112         g_main_loop_quit(mainloop);
2113 }
2114
2115 int main(void)
2116 {
2117         BluetoothPbAgent *agent;
2118
2119         gint ret = EXIT_SUCCESS;
2120         gint tapi_result;
2121
2122         struct sigaction sa;
2123         DBG("Starting Bluetooth PBAP agent");
2124
2125         g_type_init();
2126
2127         mainloop = g_main_loop_new(NULL, FALSE);
2128         if (mainloop == NULL) {
2129                 DBG("Couldn't create GMainLoop\n");
2130                 return EXIT_FAILURE;
2131         }
2132
2133         agent = g_object_new(BLUETOOTH_PB_TYPE_AGENT, NULL);
2134
2135         /* connect contact */
2136         if (contacts_connect2() != CONTACTS_ERROR_NONE) {
2137                 DBG("Can not connect contacts server\n");
2138                 g_object_unref(agent);
2139                 return EXIT_FAILURE;
2140         }
2141
2142         if (contacts_db_add_changed_cb(_contacts_event._uri,
2143                         __bluetooth_pb_contact_changed,
2144                         g_object_ref(agent)) != CONTACTS_ERROR_NONE) {
2145                 DBG("Can not add changed callback");
2146         }
2147
2148         /* set signal */
2149         memset(&sa, 0, sizeof(sa));
2150         sa.sa_handler = __bluetooth_pb_agent_signal_handler;
2151         sigaction(SIGTERM, &sa, NULL);
2152         sigaction(SIGINT, &sa, NULL);
2153
2154         /* init tapi */
2155         agent->tapi_handle = tel_init(NULL);
2156         tapi_result = tel_get_sim_msisdn(agent->tapi_handle,
2157                         __bluetooth_pb_tel_callback, agent);
2158
2159         if (tapi_result != TAPI_API_SUCCESS) {
2160                 __bluetooth_pb_agent_dbus_init(agent);
2161         }
2162
2163
2164         __bluetooth_pb_agent_timeout_add_seconds(agent);
2165
2166         g_main_loop_run(mainloop);
2167
2168         if (contacts_db_remove_changed_cb(_contacts_event._uri,
2169                         __bluetooth_pb_contact_changed,
2170                         g_object_ref(agent)) != CONTACTS_ERROR_NONE) {
2171                 DBG("Cannot remove changed callback");
2172         }
2173
2174         g_object_unref(agent);
2175
2176         if (contacts_disconnect2() != CONTACTS_ERROR_NONE)
2177                 DBG("contacts_disconnect2 failed \n");
2178
2179         g_signal_emit(agent, signals[CLEAR], 0);
2180
2181         g_object_unref(agent);
2182
2183         DBG("Terminate Bluetooth PBAP agent");
2184         return ret;
2185 }