4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Girishashok Joshi <girish.joshi@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
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
14 * http://www.apache.org/licenses/LICENSE-2.0
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.
32 #include "vconf-keys.h"
34 #include <sys/types.h>
37 /*Messaging Header Files*/
39 #include "msg_storage.h"
40 #include "msg_storage_types.h"
41 #include "msg_transport.h"
42 #include "msg_transport_types.h"
43 #include "msg_types.h"
46 #include <TapiUtility.h>
47 #include <ITapiNetText.h>
48 #include <bluetooth_map_agent.h>
49 #include <bluetooth_map_email.h>
50 #include <bluetooth_map_sms.h>
51 #include <map_bmessage.h>
53 #define OBEX_CLIENT_SERVICE "org.bluez.obex"
54 #define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1"
55 #define OBEX_CLIENT_PATH "/org/bluez/obex"
56 #define MNS_CLIENT_INTERFACE "org.openobex.MessageNotification"
58 #define BT_MAP_NEW_MESSAGE "NewMessage"
59 #define BT_MAP_STATUS_CB "sent status callback"
60 #define BT_MAP_MSG_CB "sms message callback"
61 #define BT_MNS_OBJECT_PATH "/org/bluez/mns"
62 #define BT_MNS_INTERFACE "org.bluez.mns"
63 #define BT_MAP_SENT_FOLDER_NAME "SENT"
64 #define BT_MAP_MSG_TEMPLATE "TEMPLATE"
65 #define BT_MAP_DELETED_FOLDER_NAME "DELETED"
66 #define BT_MAP_MSG_INFO_MAX 256
67 #define BT_MAP_MSG_HANDLE_MAX 21
68 #define BT_MAP_TIMESTAMP_MAX_LEN 16
69 #define BT_MAP_MSG_BODY_MAX 1024
70 #define BT_MSG_UPDATE 0
71 #define BT_MSG_DELETE 1
74 static TapiHandle *g_tapi_handle;
75 static TelSmsAddressInfo_t *g_sca_info;
77 GSList *id_list = NULL;
78 guint64 current_push_map_id;
80 msg_send_option_t opt;
83 SMS_TON_UNKNOWN = 0, /* unknown */
84 SMS_TON_INTERNATIONAL = 1, /* international number */
85 SMS_TON_NATIONAL = 2, /* national number */
86 SMS_TON_NETWORK_SPECIFIC = 3, /* network specific number */
87 SMS_TON_DEDICATED_ACCESS = 4, /* subscriber number */
88 SMS_TON_ALPHA_NUMERIC = 5, /* alphanumeric, GSM 7-bit default */
89 SMS_TON_ABBREVIATED_NUMBER = 6, /* abbreviated number */
90 SMS_TON_RESERVED_FOR_EXT = 7 /* reserved for extension */
91 } bt_sim_type_of_num_t;
99 /* Store supported folders in SMS and EMAIL */
100 gboolean folders_supported[FOLDER_COUNT][MSG_TYPES] = { {FALSE, FALSE}, };
102 GMainLoop *g_mainloop;
103 static char *g_mns_path;
104 static GDBusConnection *map_dbus_conn;
105 static GDBusProxy *g_mns_proxy;
107 static const gchar map_agent_introspection_xml[] =
109 " <interface name='org.bluez.MapAgent'>"
110 " <method name='GetFolderTree'>"
111 " <arg type='a(s)' name='folder_list' direction='out'/>"
113 " <method name='GetMessageList'>"
114 " <arg type='s' name='folder_name'/>"
115 " <arg type='q' name='max'/>"
116 " <arg type='q' name='offset'/>"
117 " <arg type='y' name='subject_len'/>"
118 " <arg type='a{sv}' name='filters'/>"
119 " <arg type='b' name='newmessage' direction='out'/>"
120 " <arg type='t' name='count' direction='out'/>"
121 " <arg type='a(ssssssssssbsbbbbs)' name='msg_list' direction='out'/>"
123 " <method name='GetMessage'>"
124 " <arg type='s' name='message_name'/>"
125 " <arg type='b' name='attach'/>"
126 " <arg type='b' name='transcode'/>"
127 " <arg type='b' name='first_request'/>"
128 " <arg type='b' name='fraction_deliver' direction='out'/>"
129 " <arg type='s' name='msg_body' direction='out'/>"
131 " <method name='PushMessage'>"
132 " <arg type='b' name='save_copy'/>"
133 " <arg type='b' name='retry_send'/>"
134 " <arg type='b' name='native'/>"
135 " <arg type='s' name='folder_name'/>"
136 " <arg type='t' name='handle' direction='out'/>"
138 " <method name='PushMessageData'>"
139 " <arg type='s' name='bmsg'/>"
141 " <method name='UpdateMessage'>"
142 " <arg type='u' name='update_err' direction='out'/>"
144 " <method name='SetReadStatus'>"
145 " <arg type='s' name='handle'/>"
146 " <arg type='b' name='read_status'/>"
147 " <arg type='u' name='update_err' direction='out'/>"
149 " <method name='SetDeleteStatus'>"
150 " <arg type='s' name='handle'/>"
151 " <arg type='b' name='delete_status'/>"
152 " <arg type='u' name='update_err' direction='out'/>"
154 " <method name='NotiRegistration'>"
155 " <arg type='s' name='remote_addr'/>"
156 " <arg type='b' name='status'/>"
157 " <arg type='u' name='update_err' direction='out'/>"
159 " <method name='DestroyAgent'>"
164 /* Method Prototypes */
165 static GVariant *__bt_map_get_folder_tree(GError **err);
166 static GVariant *__bt_map_get_message_list(char *folder_name, guint16 max,
167 guint16 offset, guint8 subject_len,
168 map_msg_filter_t *filter, GError **err);
169 static GVariant *__bt_map_get_message(char *message_name, gboolean attach,
170 gboolean transcode, gboolean first_request, GError **err);
171 static GVariant *__bt_map_push_message(gboolean save_copy, gboolean retry_send,
172 gboolean native, char *folder_name, GError **err);
173 static GVariant *__bt_map_push_message_data(char *bmseg, GError **err);
174 static GVariant *__bt_map_update_message(GError **err);
175 static GVariant *__bt_map_set_read_status(char *handle, gboolean read_status, GError **err);
176 static GVariant *__bt_map_set_delete_status(char *handle, gboolean delete_status, GError **err);
177 static void __bt_map_noti_registration(char *remote_addr, gboolean status);
178 static void __bt_map_destroy_agent(void);
180 /* LCOV_EXCL_START */
181 /* Create GError from error code and error message */
182 static GError *__bt_map_error(int error_code, char *error_message)
184 return g_error_new(g_quark_from_string("MAP Agent"),
185 error_code, "MAP Agent Error: %s", error_message);
188 static map_msg_filter_t __bt_map_get_filters(GVariant *filters)
190 map_msg_filter_t filter = { 0, };
195 g_variant_iter_init(&iter, filters);
196 while (g_variant_iter_loop(&iter, "{sv}", &key, &value)) {
197 if (!g_strcmp0(key, "ParameterMask")) {
198 filter.parameter_mask = g_variant_get_uint32(value);
199 DBG("ParameterMask :%u", filter.parameter_mask);
200 } else if (!g_strcmp0(key, "FilterMessageType")) {
201 filter.type = g_variant_get_byte(value);
202 DBG("FilterMessageType :%u", filter.type);
203 } else if (!g_strcmp0(key, "FilterPeriodBegin")) {
204 g_variant_get(value, "s", &filter.period_begin);
205 DBG("FilterPeriodBegin :%s", filter.period_begin);
206 } else if (!g_strcmp0(key, "FilterPeriodEnd")) {
207 g_variant_get(value, "s", &filter.period_end);
208 DBG("FilterPeriodEnd :%s", filter.period_end);
209 } else if (!g_strcmp0(key, "FilterReadStatus")) {
210 filter.read_status = g_variant_get_byte(value);
211 DBG("FilterReadStatus :%u", filter.read_status);
212 } else if (!g_strcmp0(key, "FilterRecipient")) {
213 g_variant_get(value, "s", &filter.recipient);
214 DBG("FilterRecipient :%s", filter.recipient);
215 } else if (!g_strcmp0(key, "FilterOriginator")) {
216 g_variant_get(value, "s", &filter.originator);
217 DBG("FilterOriginator :%s", filter.originator);
218 } else if (!g_strcmp0(key, "FilterPriority")) {
219 filter.priority = g_variant_get_byte(value);
220 DBG("FilterPriority :%u", filter.priority);
227 static void __bt_map_agent_method(GDBusConnection *connection,
229 const gchar *object_path,
230 const gchar *interface_name,
231 const gchar *method_name,
232 GVariant *parameters,
233 GDBusMethodInvocation *invocation,
238 INFO("method %s", method_name);
239 INFO("object_path %s", object_path);
242 if (g_strcmp0(method_name, "GetFolderTree") == 0) {
243 GVariant *folder_list = NULL;
245 folder_list = __bt_map_get_folder_tree(&err);
249 g_dbus_method_invocation_return_value(invocation, folder_list);
250 } else if (g_strcmp0(method_name, "GetMessageList") == 0) {
251 GVariant *message_list = NULL;
256 GVariant *filters = NULL;
257 map_msg_filter_t filter = { 0, };
259 g_variant_get(parameters, "(&sqqy@a{sv})", &folder_name,
260 &max, &offset, &subject_len, &filters);
262 DBG("MAX:%d Offset:%d SubjectLen:%d", max, offset, subject_len);
263 if (subject_len == 0)
264 subject_len = BT_MAP_SUBJECT_MAX_LEN;
266 filter = __bt_map_get_filters(filters);
267 message_list = __bt_map_get_message_list(folder_name, max,
268 offset, subject_len, &filter, &err);
273 g_dbus_method_invocation_return_value(invocation, message_list);
274 } else if (g_strcmp0(method_name, "GetMessage") == 0) {
275 GVariant *message = NULL;
279 gboolean first_request;
281 g_variant_get(parameters, "(&sbbb)", &message_name,
282 &attach, &transcode, &first_request);
284 message = __bt_map_get_message(message_name, attach,
285 transcode, first_request, &err);
289 g_dbus_method_invocation_return_value(invocation, message);
290 } else if (g_strcmp0(method_name, "PushMessage") == 0) {
291 GVariant *handle = NULL;
297 g_variant_get(parameters, "(bbb&s)", &save_copy,
298 &retry_send, &native, &folder_name);
300 handle = __bt_map_push_message(save_copy, retry_send,
301 native, folder_name, &err);
305 g_dbus_method_invocation_return_value(invocation, handle);
306 } else if (g_strcmp0(method_name, "PushMessageData") == 0) {
309 g_variant_get(parameters, "(&s)", &bmseg);
311 __bt_map_push_message_data(bmseg, &err);
315 g_dbus_method_invocation_return_value(invocation, NULL);
316 } else if (g_strcmp0(method_name, "UpdateMessage") == 0) {
317 GVariant *update = NULL;
319 update = __bt_map_update_message(&err);
323 g_dbus_method_invocation_return_value(invocation, update);
324 } else if (g_strcmp0(method_name, "SetReadStatus") == 0) {
326 gboolean read_status;
328 g_variant_get(parameters, "(&sb)", &handle, &read_status);
330 __bt_map_set_read_status(handle, read_status, &err);
334 g_dbus_method_invocation_return_value(invocation, NULL);
335 } else if (g_strcmp0(method_name, "SetDeleteStatus") == 0) {
337 gboolean delete_status;
339 g_variant_get(parameters, "(&sb)", &handle, &delete_status);
341 __bt_map_set_delete_status(handle, delete_status, &err);
345 g_dbus_method_invocation_return_value(invocation, NULL);
346 } else if (g_strcmp0(method_name, "NotiRegistration") == 0) {
349 g_variant_get(parameters, "(&sb)", &remote_addr, &status);
351 __bt_map_noti_registration(remote_addr, status);
352 g_dbus_method_invocation_return_value(invocation, NULL);
353 } else if (g_strcmp0(method_name, "DestroyAgent") == 0) {
354 g_dbus_method_invocation_return_value(invocation, NULL);
355 __bt_map_destroy_agent();
362 g_dbus_method_invocation_return_gerror(invocation, err);
367 static const GDBusInterfaceVTable method_table = {
368 __bt_map_agent_method,
373 static GDBusConnection *__bt_map_get_gdbus_connection(void)
380 return map_dbus_conn;
382 map_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
383 if (!map_dbus_conn) {
385 ERR("Unable to connect to dbus: %s", err->message);
392 return map_dbus_conn;
396 gboolean is_mns_connected(void)
401 return TRUE; /* LCOV_EXCL_LINE */
404 guint64 _bt_validate_uid(int uid, int msg_type)
407 struct id_info *info;
408 GSList *list = id_list;
413 if (info && info->uid == uid && info->msg_type == msg_type) {
414 DBG("UID = %d, MessageType=%d", uid, msg_type);
418 list = g_slist_next(list); /* LCOV_EXCL_LINE */
425 guint64 _bt_add_id(int uid, int msg_type)
428 static guint64 map_id;
429 struct id_info *info;
432 DBG("Add id: %d, MsgType:%d", uid, msg_type);
433 test = _bt_validate_uid(uid, msg_type);
434 DBG("test: %llu\n", (unsigned long long int)test);
438 info = g_new0(struct id_info, 1);
442 info->map_id = map_id;
444 info->msg_type = msg_type;
445 DBG("map_id = %llu, uid = %d, MsgType=%d", (unsigned long long int)info->map_id, info->uid, msg_type);
447 id_list = g_slist_append(id_list, info);
453 /* LCOV_EXCL_START */
454 static struct id_info *__bt_get_id(guint64 map_id)
457 struct id_info *info;
458 GSList *list = id_list;
463 if (info->map_id == map_id)
466 list = g_slist_next(list);
473 static struct id_info *__bt_get_uid(gchar *handle)
477 struct id_info *handle_info;
482 map_id = g_ascii_strtoull(handle, NULL, 16);
486 handle_info = __bt_get_id(map_id);
493 int _bt_update_id(guint64 map_id, int new_uid, int msg_type)
496 struct id_info *info;
497 GSList *list = id_list;
500 /* LCOV_EXCL_START */
503 if (info->map_id == map_id) {
505 info->msg_type = msg_type;
509 list = g_slist_next(list);
517 /* LCOV_EXCL_START */
518 static void __bt_remove_list(GSList *id_list)
524 DBG("Removing id list\n");
525 g_slist_free_full(id_list, g_free);
530 gboolean _bt_verify_sender(message_info_t *msg_info, char *sender)
535 if (!g_strcmp0(sender, "*"))
538 if (g_strrstr(msg_info->sender_name, sender) ||
539 g_strrstr(msg_info->sender_addressing, sender))
545 gboolean _bt_verify_receiver(message_info_t *msg_info, char *receiver)
550 if (!g_strcmp0(receiver, "*"))
553 if (g_strrstr(msg_info->recipient_name, receiver) ||
554 g_strrstr(msg_info->recipient_addressing, receiver))
560 gboolean _bt_verify_read_status(message_info_t *msg_info, guint8 read_status)
562 if (read_status == FILTER_READ_STATUS_ALL ||
563 ((read_status == FILTER_READ_STATUS_UNREAD) && msg_info->read == FALSE) ||
564 ((read_status == FILTER_READ_STATUS_READ) && msg_info->read == TRUE))
570 gboolean _bt_filter_priority(message_info_t *msg_info, guint8 priority)
572 if (priority == FILTER_PRIORITY_ALL ||
573 ((priority == FILTER_PRIORITY_HIGH) && msg_info->priority == TRUE) ||
574 ((priority == FILTER_PRIORITY_LOW) && msg_info->priority == FALSE))
580 void _get_msg_timestamp(time_t *ltime, char *timestamp)
583 struct tm local_time;
588 if (!localtime_r(ltime, &local_time))
591 year = local_time.tm_year + 1900; /* years since 1900 */
592 month = local_time.tm_mon + 1; /* months since January */
593 buf_len = snprintf(timestamp, 16, "%04hu%02hu%02huT%02hu%02hu%02hu",(unsigned short int)year, (unsigned short int)month,
594 (unsigned short int)local_time.tm_mday, (unsigned short int)local_time.tm_hour,
595 (unsigned short int)local_time.tm_min, (unsigned short int)local_time.tm_sec);
598 ERR("Encoding error occured in snprintf");
603 /* LCOV_EXCL_START */
604 time_t _get_time_t_from_timestamp(char *timestamp)
606 struct tm local_time;
611 int ymd; /* year, month, day */
612 int hms; /* hour, min, sec */
615 ymd = strtol(timestamp, &ptr, 10);
616 hms = strtol(ptr + 1, &ptr2, 10);
618 /* Initialize local_time */
619 memset(&local_time, 0, sizeof(struct tm));
621 /* parse year, month, day */
622 local_time.tm_mday = ymd % 100;
623 ymd = (ymd - local_time.tm_mday) / 100;
625 year = (ymd - month) / 100;
627 /* parse hour, minute, sec */
628 local_time.tm_sec = hms % 100;
629 hms = (hms - local_time.tm_sec) / 100;
630 local_time.tm_min = hms % 100;
631 local_time.tm_hour = (hms - local_time.tm_min) / 100;
633 local_time.tm_year = year - 1900;
634 local_time.tm_mon = month - 1;
636 int_time = mktime(&local_time);
641 gboolean _bt_verify_time(message_info_t *msg_info, map_msg_filter_t *filter)
643 struct tm local_time = { 0, };
647 /* Set 19710101T000000 as Start Date */
648 local_time.tm_year = 1971 - 1900;
649 local_time.tm_mon = 0;
650 local_time.tm_mday = 1;
651 start = mktime(&local_time);
653 /* Set 20380101T000000 as End Date */
654 local_time.tm_year = 2038 - 1900;
655 local_time.tm_mon = 0;
656 local_time.tm_mday = 1;
657 end = mktime(&local_time);
659 if (filter->period_begin)
660 start = _get_time_t_from_timestamp(filter->period_begin);
662 if (filter->period_end)
663 end = _get_time_t_from_timestamp(filter->period_end);
665 if (msg_info->time >= start && msg_info->time <= end)
671 #define SET_TON_NPI(dest, ton, npi) { \
673 dest |= (ton & 0x07) << 4; \
674 dest |= npi & 0x0F; \
677 /* LCOV_EXCL_START */
678 static int __bt_ascii_to_upper(int ch)
680 return (('a' <= (ch) && (ch) <= 'z') ? ((ch) - ('a'-'A')) : (ch));
683 static int __bt_sms_pack_gsm_code(gchar *p_out, const char *data, int in_len)
690 for (pos = 0, i = 0; i < in_len; pos++, i++) {
691 /* pack the low bits */
692 p_out[pos] = data[i] >> shift;
694 if (i + 1 < in_len) {
695 /* pack the high bits using the low bits
696 of the next character */
697 p_out[pos] |= data[i+1] << (7 - shift);
712 static void __bt_sms_conv_digit_to_bcd(gchar *p_bcd, char *p_digits, int digit_len)
718 unsigned char higher;
721 if (p_bcd == NULL || p_digits == NULL)
724 /* 0123456789 -> 1032547698 */
725 for (i = 0, j = 0; i < digit_len; i = i + 2, j++) {
726 if (p_digits[i] == '*')
728 else if (p_digits[i] == '#')
730 else if (__bt_ascii_to_upper(p_digits[i]) == 'P')
733 digit = (int) (p_digits[i] - '0');
735 lower = digit & 0x0F;
737 if (digit_len != i + 1) {
738 if (p_digits[i+1] == '*')
740 else if (p_digits[i+1] == '#')
742 else if (__bt_ascii_to_upper(p_digits[i+1]) == 'P')
745 digit = (int) (p_digits[i+1] - '0');
747 higher = digit & 0x0F;
752 p_bcd[j] = (higher << 4) | lower;
757 static int __bt_sms_encode_addr(gchar *addr_field, char *dial_num,
758 int dial_num_len, int ton, int npi)
763 if (dial_num == NULL || addr_field == NULL)
766 if (dial_num[0] == '+') {
769 ton = SMS_TON_INTERNATIONAL;
772 if (ton != SMS_TON_ALPHA_NUMERIC) {
773 /* Origination address length address length */
774 addr_field[index++] = (unsigned char)dial_num_len;
776 addr_field[index] = (unsigned char)
777 (((dial_num_len * 7 + 7) / 8) * 2);
779 if (((dial_num_len * 7) % 8) <= 4)
785 SET_TON_NPI(addr_field[index], ton, npi);
786 index++; /* SET_TON_NPI */
788 if (ton != SMS_TON_ALPHA_NUMERIC) {
789 __bt_sms_conv_digit_to_bcd(&addr_field[index],
790 (char *)dial_num, dial_num_len);
792 if (dial_num_len % 2)
793 index += (dial_num_len / 2) + 1;
795 index += dial_num_len / 2;
797 index += __bt_sms_pack_gsm_code(&addr_field[index],
798 dial_num, (int)dial_num_len);
805 static int __bt_sms_encode_time(gchar *addr_field, time_t *tm)
813 if (!localtime_r(tm, <ime))
816 year = ltime.tm_year + 1900; /* years since 1900 */
818 month = ltime.tm_mon + 1; /* months since January */
820 addr_field[index++] = ((year % 10) << 4) + (year / 10);
821 addr_field[index++] = ((month % 10) << 4) + (month / 10);
822 addr_field[index++] = ((ltime.tm_mday % 10) << 4) +
823 (ltime.tm_mday / 10);
824 addr_field[index++] = ((ltime.tm_hour % 10) << 4) +
825 (ltime.tm_hour / 10);
826 addr_field[index++] = ((ltime.tm_min % 10) << 4) + (ltime.tm_min / 10);
827 addr_field[index++] = ((ltime.tm_sec % 10) << 4) + (ltime.tm_sec / 10);
828 addr_field[index] = 0x00;
834 gchar *_bt_get_sms_pdu_from_msg_data(gchar *number,
835 char *msg, time_t tm,
839 gchar packet[TAPI_NETTEXT_MSG_SIZE_MAX] = {0,};
842 packet[index] = 0x00; /* Since SCA is unknown for stored messages */
845 /* TP-MTI : Type of message */
846 packet[index] = 0x00; /* SMS-DELIVER PDU */
848 /* TP-MMS bit is set to 1 as we support only SMS */
849 packet[index] |= 0x04;
852 /* TP-OA : Mobile originating address */
853 index += __bt_sms_encode_addr(packet+index,
854 number, strlen(number),
855 g_sca_info->Ton, g_sca_info->Npi);
857 /* TP-PID : Since we use only SMS so set to 0 */
858 packet[index++] = 0x00;
860 /* TP-DCS : Data Coding Scheme, default value set */
861 packet[index++] = 0x00;
863 /* TP-SCTS : Message timestamp */
864 index += __bt_sms_encode_time(packet+index, &tm);
866 /* TP-UDL : Message body length */
867 packet[index++] = strlen(msg);
869 /* TP-UD : Message body */
870 index += __bt_sms_pack_gsm_code(packet + index, msg, strlen(msg));
872 *msg_pdu_len = index;
875 return g_memdup(packet, index);
878 static void __bt_get_sms_sca(TapiHandle *handle, int result, void *data,
882 TelSmsAddressInfo_t *scaInfo = data;
884 DBG("__bt_get_sms_sca 0x%x", result);
887 g_sca_info = g_malloc0(sizeof(TelSmsAddressInfo_t));
890 g_sca_info->DialNumLen = 0;
894 g_sca_info = g_malloc0(sizeof(TelSmsAddressInfo_t));
895 g_sca_info->Ton = scaInfo->Ton;
896 g_sca_info->Npi = scaInfo->Npi;
897 g_sca_info->DialNumLen = scaInfo->DialNumLen;
902 void _bt_message_info_free(gpointer data)
905 message_info_t *msg_info = (message_info_t *)data;
906 g_free(msg_info->handle);
907 g_free(msg_info->subject);
908 g_free(msg_info->datetime);
909 g_free(msg_info->sender_name);
910 g_free(msg_info->sender_addressing);
911 g_free(msg_info->replyto_addressing);
912 g_free(msg_info->recipient_name);
913 g_free(msg_info->recipient_addressing);
914 g_free(msg_info->type);
915 g_free(msg_info->reception_status);
916 g_free(msg_info->size);
917 g_free(msg_info->attachment_size);
922 /* LCOV_EXCL_START */
923 static gboolean __bluetooth_map_start_service()
929 sms = _bt_map_start_sms_service();
930 email = _bt_map_start_email_service();
939 static gboolean __bt_validate_utf8(char **text)
942 if (g_utf8_validate(*text, -1, NULL))
945 /* LCOV_EXCL_START */
951 gboolean _bt_validate_msg_data(message_info_t *msg_info)
954 if (msg_info == NULL)
957 if (msg_info->subject)
958 return __bt_validate_utf8(&msg_info->subject);
960 if (msg_info->sender_name)
961 return __bt_validate_utf8(&msg_info->sender_name);
963 /* LCOV_EXCL_START */
964 if (msg_info->sender_addressing)
965 return __bt_validate_utf8(&msg_info->sender_addressing);
967 if (msg_info->replyto_addressing)
968 return __bt_validate_utf8(&msg_info->replyto_addressing);
970 if (msg_info->recipient_name)
971 return __bt_validate_utf8(&msg_info->recipient_name);
973 if (msg_info->recipient_addressing)
974 return __bt_validate_utf8(&msg_info->recipient_addressing);
981 /* LCOV_EXCL_START */
982 static void __bt_mns_client_connect(char *address)
985 GDBusConnection *connection;
986 GVariantBuilder builder;
990 GError *error = NULL;
991 const char *session_path;
994 DBG_SECURE("MNS Client already connected to %s", address);
998 connection = __bt_map_get_gdbus_connection();
999 if (connection == NULL) {
1000 DBG("Could not get GDBus Connection");
1004 g_mns_proxy = g_dbus_proxy_new_sync(connection,
1005 G_DBUS_PROXY_FLAGS_NONE, NULL,
1006 OBEX_CLIENT_SERVICE, OBEX_CLIENT_PATH,
1007 OBEX_CLIENT_INTERFACE, NULL, &error);
1010 ERR("Failed to get a proxy for D-Bus");
1015 g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
1016 g_variant_builder_add(&builder, "{sv}", "Target",
1017 g_variant_new("s", "MNS"));
1018 args = g_variant_builder_end(&builder);
1020 param = g_variant_new("(s@a{sv})", address, args);
1022 value = g_dbus_proxy_call_sync(g_mns_proxy,
1023 "CreateSession", param, G_DBUS_CALL_FLAGS_NONE, -1,
1025 if (value == NULL) {
1026 /* dBUS-RPC is failed */
1027 ERR("dBUS-RPC is failed");
1028 if (error != NULL) {
1029 /* dBUS gives error cause */
1030 ERR("D-Bus API failure: errCode[%x], message[%s]",
1031 error->code, error->message);
1033 g_clear_error(&error);
1035 g_object_unref(g_mns_proxy);
1040 g_variant_get(value, "(&o)", &session_path);
1041 g_mns_path = g_strdup(session_path);
1042 DBG("g_mns_path = %s\n", g_mns_path);
1044 g_variant_unref(value);
1048 static void __bt_mns_client_disconnect()
1051 GError *error = NULL;
1055 ERR("No proxy to disconnect");
1059 value = g_dbus_proxy_call_sync(g_mns_proxy,
1060 "RemoveSession", g_variant_new("(o)", g_mns_path),
1061 G_DBUS_CALL_FLAGS_NONE, -1,
1064 if (value == NULL) {
1065 /* dBUS-RPC is failed */
1066 ERR("dBUS-RPC is failed: Could not remove MAP session");
1067 if (error != NULL) {
1068 /* dBUS gives error cause */
1069 ERR("D-Bus API failure: errCode[%x], message[%s]",
1070 error->code, error->message);
1072 g_clear_error(&error);
1080 g_object_unref(g_mns_proxy);
1083 g_variant_unref(value);
1086 /* LCOV_EXCL_STOP */
1088 void _bt_mns_client_event_notify(gchar *event, guint64 handle,
1089 gchar *folder, gchar *old_folder,
1093 GError *error = NULL;
1094 GDBusProxy *mns_proxy;
1095 GDBusConnection *connection = NULL;
1099 ERR("No client proxy");
1103 /* LCOV_EXCL_START */
1104 connection = __bt_map_get_gdbus_connection();
1105 if (connection == NULL) {
1106 DBG("Could not get GDBus Connection");
1110 mns_proxy = g_dbus_proxy_new_sync(connection,
1111 G_DBUS_PROXY_FLAGS_NONE, NULL,
1112 OBEX_CLIENT_SERVICE, g_mns_path,
1113 MNS_CLIENT_INTERFACE, NULL, &error);
1114 if (mns_proxy == NULL) {
1115 ERR("Failed to get a proxy for D-Bus\n");
1119 value = g_dbus_proxy_call_sync(mns_proxy, "SendEvent",
1120 g_variant_new("(stsss)", event, handle, folder, old_folder, msg_type),
1121 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1122 if (value == NULL) {
1123 /* dBUS-RPC is failed */
1124 ERR("dBUS-RPC is failed: SendEvent failed");
1125 if (error != NULL) {
1126 /* dBUS gives error cause */
1127 ERR("D-Bus API failure: errCode[%x], message[%s]",
1128 error->code, error->message);
1130 g_clear_error(&error);
1132 g_object_unref(mns_proxy);
1136 g_variant_unref(value);
1137 g_object_unref(mns_proxy);
1139 /* LCOV_EXCL_STOP */
1142 /* LCOV_EXCL_START */
1143 static gchar *__bt_get_map_folder(int folder)
1147 return g_strdup("INBOX");
1149 return g_strdup("SENT");
1151 return g_strdup("OUTBOX");
1153 return g_strdup("DRAFT");
1154 case BT_MSG_DELETED:
1155 return g_strdup("DELETED");
1160 static GList *_bt_map_merge_sorted(GSList *sms_list, GSList *email_list)
1163 message_info_t *sms;
1164 message_info_t *email;
1166 /* **********************Note from glib documentation**************************
1167 * g_list_append() has to traverse the entire list to find the end, which
1168 * is inefficient when adding multiple elements. A common idiom to avoid the
1169 * inefficiency is to use g_list_prepend() and reverse the list with
1170 * g_list_reverse() when all elements have been added.
1171 * ***************************************************************************/
1173 while (sms_list && email_list) {
1174 sms = sms_list->data;
1175 email = email_list->data;
1177 if (sms->time > email->time) {
1178 list = g_list_prepend(list, sms);
1179 sms_list = g_slist_next(sms_list);
1181 list = g_list_prepend(list, email);
1182 email_list = g_slist_next(email_list);
1187 sms = sms_list->data;
1188 list = g_list_prepend(list, sms);
1189 sms_list = g_slist_next(sms_list);
1191 while (email_list) {
1192 email = email_list->data;
1193 list = g_list_prepend(list, email);
1194 email_list = g_slist_next(email_list);
1197 list = g_list_reverse(list);
1201 static GVariant *__bt_map_get_folder_tree(GError **err)
1203 GVariant *folder_list = NULL;
1204 GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)"));
1206 gboolean sms_ret = TRUE;
1207 gboolean email_ret = TRUE;
1209 sms_ret = _bt_map_sms_get_supported_folders(folders_supported);
1210 email_ret = _bt_map_email_get_supported_folders(folders_supported);
1212 if (sms_ret || email_ret) {
1213 for (i = 0; i < 5; i++) {
1214 if (folders_supported[i][BT_MSG_SOURCE_SMS] ||
1215 folders_supported[i][BT_MSG_SOURCE_EMAIL]) {
1216 g_variant_builder_add(builder, "(s)", __bt_get_map_folder(i));
1220 folder_list = g_variant_new("(a(s))", builder);
1222 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1226 g_variant_builder_unref(builder);
1230 static GVariant *__bt_map_get_message_list(char *folder_name, guint16 max,
1231 guint16 offset, guint8 subject_len,
1232 map_msg_filter_t *filter, GError **err)
1235 GVariant *message_list = NULL;
1236 GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssssssssssbsbbbbs)"));
1237 GSList *sms_list = NULL;
1238 GSList *email_list = NULL;
1239 gboolean sms_ret = TRUE;
1240 gboolean email_ret = TRUE;
1242 guint64 count_sms = 0;
1243 guint64 count_email = 0;
1244 gboolean newmsg = FALSE;
1245 char *folder = NULL;
1247 DBG("Folder:%s Max:%d", folder_name, max);
1251 /* In case of parent folders send empty message listing */
1253 if (g_ascii_strncasecmp(folder_name, "/telecom/msg/", strlen("/telecom/msg/")))
1257 folder = strrchr(folder_name, '/');
1259 folder = folder_name;
1262 DBG("Filter Type: %d", filter->type);
1263 if ((filter->type & FILTER_TYPE_SMS_GSM) == 0) { /* Check if SMS is requested */
1264 if (!g_ascii_strncasecmp(folder, "SENT", strlen("SENT"))) {
1265 /* Failed Sent SMS are stored in OUTBOX.
1266 * Hence, Fetch both SENT and OUTBOX */
1267 gboolean sent_ret = _bt_map_get_sms_message_list("SENT",
1268 max + offset, subject_len, filter,
1269 &sms_list, &count_sms, &newmsg);
1270 gboolean outbox_ret = _bt_map_get_sms_message_list("OUTBOX",
1271 max + offset, subject_len, filter,
1272 &sms_list, &count_sms, &newmsg);
1273 sms_ret = (sent_ret || outbox_ret);
1275 sms_ret = _bt_map_get_sms_message_list(folder,
1276 max + offset, subject_len, filter,
1277 &sms_list, &count_sms, &newmsg);
1281 if ((filter->type & FILTER_TYPE_EMAIL) == 0) { /* Check if EMAIL is requested */
1282 email_ret = _bt_map_get_email_list(folder,
1283 max + offset, subject_len, filter,
1284 &email_list, &count_email, &newmsg);
1287 if (sms_ret || email_ret) {
1288 GList *list = _bt_map_merge_sorted(sms_list, email_list);
1291 message_info_t *msg_info = NULL;
1293 g_slist_free(sms_list);
1294 g_slist_free(email_list);
1296 count = count_sms + count_email;
1298 pos = g_list_nth(list, offset);
1299 for (i = offset; pos && i < max + offset; i++) {
1300 msg_info = pos->data;
1301 g_variant_builder_add(builder, "(ssssssssssbsbbbbs)",
1305 msg_info->sender_name,
1306 msg_info->sender_addressing,
1307 msg_info->recipient_name,
1308 msg_info->recipient_addressing,
1311 msg_info->reception_status,
1313 msg_info->attachment_size,
1318 msg_info->replyto_addressing);
1320 pos = g_list_next(pos);
1323 message_list = g_variant_new("(bta(ssssssssssbsbbbbs))",
1324 newmsg, count, builder);
1325 g_variant_builder_unref(builder);
1326 g_list_free_full(list, _bt_message_info_free);
1328 return message_list;
1332 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1334 g_variant_builder_unref(builder);
1339 static GVariant *__bt_map_get_message(char *message_name, gboolean attach,
1340 gboolean transcode, gboolean first_request, GError **err)
1343 GVariant *message = NULL;
1346 gchar *bmseg = NULL;
1348 struct id_info *handle_info = __bt_get_uid(message_name);
1349 if (handle_info == NULL)
1352 message_id = handle_info->uid;
1353 if (handle_info->msg_type == BT_MAP_ID_SMS)
1354 val_ret = _bt_map_get_sms_message(message_id, attach, transcode, first_request, &bmseg);
1356 val_ret = _bt_map_get_email_message(message_id, attach, transcode, first_request, &bmseg);
1359 message = g_variant_new("(bs)", FALSE, bmseg);
1365 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1371 static GVariant *__bt_map_push_message(gboolean save_copy, gboolean retry_send,
1372 gboolean native, char *folder_name, GError **err)
1377 DBG_SECURE("folder_name = %s\n", folder_name);
1379 handle = _bt_add_id(-1, BT_MAP_ID_SMS);
1380 current_push_map_id = handle;
1381 push_folder = g_strdup(folder_name);
1383 /* FALSE : Keep messages in Sent folder */
1384 /* TRUE : don't keep messages in sent folder */
1385 opt.save_copy = save_copy;
1386 DBG("opt.save_copy = %d\n", opt.save_copy);
1388 /* FALSE : don't retry */
1390 opt.retry_send = retry_send;
1391 DBG("opt.retry_send = %d\n", opt.retry_send);
1393 /* FALSE : native */
1395 opt.native = native;
1396 DBG("opt.native = %d\n", opt.native);
1398 return g_variant_new("(t)", handle);
1402 static GVariant *__bt_map_push_message_data(char *bmseg, GError **err)
1405 gboolean ret = FALSE;
1407 DBG_SECURE("BMSG: %s", bmseg);
1409 struct bmsg_data *bmsg_info = NULL;
1411 bmsg_info = bmsg_parse(bmseg);
1413 if (!g_ascii_strcasecmp(bmsg_info->type, "SMS_GSM"))
1414 ret = _bt_map_push_sms_data(bmsg_info, &opt, push_folder);
1415 else if (!g_ascii_strcasecmp(bmsg_info->type, "EMAIL"))
1416 ret = _bt_map_push_email_data(bmsg_info, &opt, push_folder);
1418 bmsg_free_bmsg(bmsg_info);
1421 g_free(push_folder);
1424 INFO("Message Successfully Sent or Saved");
1428 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1430 ERR("Error in sending or saving Message");
1434 /* Dummy Implementation */
1435 static GVariant *__bt_map_update_message(GError **err)
1437 return g_variant_new("(b)", TRUE);
1440 static GVariant *__bt_map_set_read_status(char *handle, gboolean read_status, GError **err)
1446 struct id_info *handle_info = __bt_get_uid(handle);
1447 if (handle_info == NULL)
1450 msg_id = handle_info->uid;
1451 DBG("msg_id = %d, read_status = %d\n", msg_id, read_status);
1452 if (handle_info->msg_type == BT_MAP_ID_SMS)
1453 val_ret = _bt_map_sms_set_read_status(msg_id, read_status);
1455 val_ret = _bt_map_set_email_read_status(msg_id, read_status);
1463 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1469 static GVariant *__bt_map_set_delete_status(char *handle, gboolean delete_status, GError **err)
1475 struct id_info *handle_info = __bt_get_uid(handle);
1476 if (handle_info == NULL)
1479 msg_id = handle_info->uid;
1480 if (handle_info->msg_type == BT_MAP_ID_SMS)
1481 val_ret = _bt_map_set_sms_delete_status(msg_id, delete_status);
1483 val_ret = _bt_map_set_email_delete_status(msg_id, delete_status);
1491 *err = __bt_map_error(BT_MAP_AGENT_ERROR_INTERNAL,
1497 static void __bt_map_noti_registration(char *remote_addr, gboolean status)
1500 DBG_SECURE("remote_addr = %s \n", remote_addr);
1503 __bt_mns_client_connect(remote_addr);
1505 __bt_mns_client_disconnect();
1508 static void __bt_map_destroy_agent(void)
1510 g_main_loop_quit(g_mainloop);
1513 static GDBusNodeInfo *__bt_map_create_method_node_info
1514 (const gchar *introspection_data)
1517 GDBusNodeInfo *node_info = NULL;
1519 if (introspection_data == NULL)
1522 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
1525 ERR("Unable to create node: %s", err->message);
1526 g_clear_error(&err);
1531 static gboolean __bt_map_dbus_init(void)
1535 GDBusNodeInfo *node_info;
1536 GError *error = NULL;
1537 GDBusConnection *gdbus_conn = __bt_map_get_gdbus_connection();
1539 if (gdbus_conn == NULL) {
1540 ERR("Error in creating the gdbus connection");
1544 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
1545 BT_MAP_SERVICE_NAME,
1546 G_BUS_NAME_OWNER_FLAGS_NONE,
1549 DBG("owner_id is [%d]", owner_id);
1551 node_info = __bt_map_create_method_node_info(
1552 map_agent_introspection_xml);
1553 if (node_info == NULL)
1556 map_id = g_dbus_connection_register_object(gdbus_conn, BT_MAP_SERVICE_OBJECT_PATH,
1557 node_info->interfaces[0],
1559 NULL, NULL, &error);
1561 g_dbus_node_info_unref(node_info);
1564 ERR("Failed to register: %s", error->message);
1565 g_error_free(error);
1576 DBG("Starting Bluetooth MAP agent");
1580 g_mainloop = g_main_loop_new(NULL, FALSE);
1582 if (g_mainloop == NULL) {
1583 ERR("Couldn't create GMainLoop\n");
1584 return EXIT_FAILURE;
1587 if (__bt_map_dbus_init() == FALSE)
1590 if (__bluetooth_map_start_service() == FALSE)
1593 g_tapi_handle = tel_init(NULL);
1597 ret = tel_get_sms_sca(g_tapi_handle, 0, __bt_get_sms_sca, NULL);
1598 if (ret != TAPI_API_SUCCESS) {
1599 ERR("TAPI err = %d", ret);
1603 g_main_loop_run(g_mainloop);
1607 __bt_remove_list(id_list);
1609 tel_deinit(g_tapi_handle);
1612 __bt_mns_client_disconnect();
1615 g_object_unref(map_dbus_conn);
1617 _bt_map_stop_sms_service();
1618 _bt_map_stop_email_service();
1620 DBG("Bluetooth MAP agent Terminated successfully\n");
1622 return EXIT_FAILURE;
1624 /* LCOV_EXCL_STOP */