/* * Copyright 2012 Samsung Electronics Co., Ltd * * Licensed under the Flora License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://floralicense.org/license * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "message.h" #include #include #include #include #include #include #include "msg-ui-thread-main.h" #include "msg-ui-common-utility.h" static void __msg_ui_popup_warning(Evas_Object *parent, const char *msg); static service_h __msg_ui_parse_sms_uri(service_h service, const char *uri); static service_h __msg_ui_parse_mmsto_uri(service_h service, const char *uri); static service_h __msg_ui_parse_file_uri(service_h service, const char *uri); static service_h __get_service_with_new_msg(struct appdata *ad); static service_h __get_service_with_msg_id(struct appdata *ad, service_h service); void layout_cb(ui_gadget_h ug, enum ug_mode mode, void *priv); void result_cb(ui_gadget_h ug, service_h result, void *priv); void destroy_cb(ui_gadget_h ug, void *priv); struct appdata *gAppData = NULL; static void win_del(void *data, Evas_Object *obj, void *event) { elm_exit(); } static void main_quit_cb(void *data, Evas_Object *obj, void *event_info) { elm_exit(); } static void lang_changed(void *data) { D_ENTER; struct appdata *ad = data; ug_send_event(UG_EVENT_LANG_CHANGE); msg_ui_thread_lang_changed(ad->thread_data); } static void low_battery_cb(void *data) { D_ENTER; ug_send_event(UG_EVENT_LOW_BATTERY); } static void region_changed_cb(void *data) { D_ENTER; ug_send_event(UG_EVENT_REGION_CHANGE); } static void rotation_changed_cb(void *data, Evas_Object *obj, void *event) { D_ENTER; struct appdata *ad = data; int ret = 0; int rot = THREAD_ROTATE_ANGLE_UNKNOWN; int changed_rotation = elm_win_rotation_get(obj); if(changed_rotation != ad->cur_rotation) { D_MSG("current rotation [%d], changed rotation [%d]", ad->cur_rotation, changed_rotation); ad->cur_rotation = changed_rotation; switch (changed_rotation) { case 0: rot = THREAD_ROTATE_ANGLE_PORTRAIT; ret = ug_send_event(UG_EVENT_ROTATE_PORTRAIT); break; case 90: rot = THREAD_ROTATE_ANGLE_LANDSCAPE_UPSIDEDOWN; ret = ug_send_event(UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN); break; case 180: rot = THREAD_ROTATE_ANGLE_PORTRAIT_UPSIDEDOWN; ret = ug_send_event(UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN); break; case 270: rot = THREAD_ROTATE_ANGLE_LANDSCAPE; ret = ug_send_event(UG_EVENT_ROTATE_LANDSCAPE); break; default: rot = THREAD_ROTATE_ANGLE_UNKNOWN; break; } } if (rot >= 0) msg_ui_thread_rotation_set(ad->thread_data, rot); D_LEAVE; } static void _block_clicked_cb(void *data, Evas_Object *obj, void *event_info) { evas_object_del(obj); elm_exit(); } static void __msg_ui_popup_warning(Evas_Object *parent, const char *msg) { D_ENTER; MSG_UI_RET_IF(MSG_UI_LEVEL_ASSERT, parent == NULL || msg == NULL); Evas_Object *layout, *pu; evas_object_show(parent); layout = elm_layout_add(parent); elm_layout_theme_set(layout, "layout", "application", "default"); evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(parent, layout); evas_object_show(layout); pu = elm_popup_add(layout); MSG_UI_RETM_IF(MSG_UI_LEVEL_ASSERT, pu == NULL, "Cannot add popup object\n"); evas_object_size_hint_weight_set(pu, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_smart_callback_add(pu , "block,clicked", _block_clicked_cb, NULL); elm_object_text_set(pu, msg); elm_popup_timeout_set(pu, 2); evas_object_smart_callback_add(pu, "timeout", main_quit_cb, NULL); evas_object_show(pu); D_LEAVE; } static service_h __msg_ui_parse_sms_uri(service_h service, const char *uri) { D_ENTER; char *content = NULL; char *recipient = NULL; char *tmp = NULL; char *body_text = NULL; service_h svc_handle = NULL; if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } char *scheme = g_strdup(uri); if (scheme) { strtok_r(scheme, ":", &content); if (content) { if (g_ascii_isdigit(content[0]) || (content[0] == '+' && g_ascii_isdigit(content[1]))) { recipient = strtok_r(NULL, "?", &content); if (recipient) { D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } if (content) { if (g_str_has_prefix(content, MSG_BUNDLE_VALUE_BODY_URI)) { tmp = strtok_r(NULL, "=", &content); if (content && strlen(content)) { char *unescape_string = g_uri_unescape_string(content, NULL); if (unescape_string) { D_MSG("APPSVC BODY = [%s]", unescape_string); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_BODY, unescape_string); free(unescape_string); } } } } } } g_free(scheme); } else { service_get_extra_data(service, SERVICE_DATA_TO, &recipient); D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } /* Add body text */ service_get_extra_data(service, SERVICE_DATA_TEXT, &body_text); if (body_text) { D_MSG("APPSVC BODY_TEXT = [%s]", body_text); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_BODY, body_text); } D_LEAVE; return svc_handle; } static service_h __msg_ui_parse_mmsto_uri(service_h service, const char *uri) { D_ENTER; char *content = NULL; char *recipient = NULL; char *body_text = NULL; char *subject = NULL; char *attachment = NULL; char *cc = NULL; service_h svc_handle = NULL; if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } char *scheme = g_strdup(uri); if (scheme) { strtok_r(scheme, ":", &content); if (content) { if (g_ascii_isdigit(content[0]) || (content[0] == '+' && g_ascii_isdigit(content[1]))) { recipient = strtok_r(NULL, "?", &content); cc = strtok_r(NULL, "&", &content); if (cc) strtok_r(NULL, "=", &cc); D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } } g_free(scheme); } else { service_get_extra_data(service, SERVICE_DATA_TO, &recipient); D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } /* Add body text */ service_get_extra_data(service, SERVICE_DATA_TEXT, &body_text); if (body_text) { D_MSG("APPSVC BODY_TEXT = [%s]", body_text); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_BODY, body_text); } /* Add subject */ service_get_extra_data(service, SERVICE_DATA_SUBJECT, &subject); if (subject) { D_MSG("APPSVC SUBJECT = [%s]", subject); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_SUBJECT, subject); } /* Add attachment */ service_get_extra_data(service, MSG_BUNDLE_KEY_ATTACHFILE, &attachment); if (attachment) { D_MSG("APPSVC ATTACHMENT = [%s]", attachment); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_ATTACHFILE, attachment); } D_LEAVE; return svc_handle; } static service_h __msg_ui_parse_file_uri(service_h service, const char *uri) { D_ENTER; char *content = NULL; char attachment[DEF_IMG_PATH_LEN] = {0, }; int i = 0; int len = 0; service_h svc_handle = NULL; if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } char *scheme = g_strdup(uri); if (scheme) { strtok_r(scheme, ":", &content); D_MSG("content = [%s]", content); if (content) { len = strlen(content) - 2; if (len <= 0) { D_EMSG("len is less than 0 !!"); service_destroy(svc_handle); g_free(scheme); return NULL; } /* Remove '//' from content string */ for (i = 0; i < len; i++) { attachment[i] = content[i+2]; } if (attachment[0] != '\0') { D_MSG("APPSVC ATTACHMENT = [%s]", attachment); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_ATTACHFILE, attachment); } } g_free(scheme); } else { D_EMSG("scheme is NULL!!"); service_destroy(svc_handle); return NULL; } D_LEAVE; return svc_handle; } static service_h __get_service_app_svc_op(const char *operation, service_h service) { D_ENTER; if (service == NULL || operation == NULL) return NULL; char *uri = NULL; char *recipient = NULL; char *body_text = NULL; char *attachment = NULL; char *subject = NULL; service_h svc_handle = NULL; if (g_strcmp0(operation, SERVICE_OPERATION_SEND) == 0) { service_get_uri(service, &uri); D_MSG("APPSVC URI = [%s]", uri); if (uri) { if (g_str_has_prefix(uri, MSG_BUNDLE_VALUE_MMSTO_URI)) { /* MMS URI */ svc_handle = __msg_ui_parse_mmsto_uri(service, uri); } else if (g_str_has_prefix(uri, MSG_BUNDLE_VALUE_FILE_URI)) { /* file URI */ svc_handle = __msg_ui_parse_file_uri(service, uri); if (svc_handle == NULL) { D_MSG("cb is NULL"); return NULL; } } else if (g_str_has_prefix(uri, "/")) { if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } D_MSG("APPSVC ATTACHMENT = [%s]", uri); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_ATTACHFILE, uri); } else { D_MSG("Not supported URI type"); return NULL; } } else { if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } /* Add recipient number */ service_get_extra_data(service, SERVICE_DATA_TO, &recipient); if (recipient) { D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } /* Add body text */ service_get_extra_data(service, SERVICE_DATA_TEXT, &body_text); if (body_text) { D_MSG("APPSVC BODY_TEXT = [%s]", body_text); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_BODY, body_text); } /* Add subject */ service_get_extra_data(service, SERVICE_DATA_SUBJECT, &subject); if (subject) { D_MSG("APPSVC SUBJECT = [%s]", subject); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_SUBJECT, subject); } /* Add attachment */ service_get_extra_data(service, MSG_BUNDLE_KEY_ATTACHFILE, &attachment); if (attachment) { D_MSG("APPSVC ATTACHMENT = [%s]", attachment); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_ATTACHFILE, attachment); } } service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TYPE, MSG_BUNDLE_VALUE_COMPOSE); } else if (g_strcmp0(operation, SERVICE_OPERATION_SEND_TEXT) == 0) { service_get_uri(service, &uri); D_MSG("APPSVC URI = [%s]", uri); if (uri) { if (g_str_has_prefix(uri, MSG_BUNDLE_VALUE_SMS_URI)) { /* SMS URI */ svc_handle = __msg_ui_parse_sms_uri(service, uri); } else { D_MSG("Not supported mime type"); return NULL; } } else { if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } /* Add body text */ service_get_extra_data(service, SERVICE_DATA_TEXT, &body_text); if (body_text) { D_MSG("APPSVC BODY_TEXT = [%s]", body_text); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_BODY, body_text); } /* Add recipient number */ service_get_extra_data(service, SERVICE_DATA_TO, &recipient); if (recipient) { D_MSG("APPSVC RECIPIENT = [%s]", recipient); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TO, recipient); } } service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TYPE, MSG_BUNDLE_VALUE_COMPOSE); } else if (g_strcmp0(operation, SERVICE_OPERATION_DEFAULT) == 0) { char *key_type = NULL; service_get_extra_data(service, MSG_BUNDLE_KEY_TYPE, &key_type); if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_MSG_ID) == 0) { msg_error_t err = MSG_SUCCESS; msg_struct_t sort_rule_t = msg_create_struct(MSG_STRUCT_SORT_RULE); msg_struct_list_s peerList; bool oneThread = true; msg_set_int_value(sort_rule_t, MSG_SORT_RULE_SORT_TYPE_INT, MSG_SORT_BY_READ_STATUS); msg_set_bool_value(sort_rule_t, MSG_SORT_RULE_ACSCEND_BOOL, false); err = msg_get_thread_view_list(gAppData->msgHandle, sort_rule_t, &peerList); msg_release_struct(&sort_rule_t); if (peerList.nCount > 1) { int unreadCnt = 0; msg_get_int_value(peerList.msg_struct_info[1], MSG_THREAD_UNREAD_COUNT_INT, &unreadCnt); if (unreadCnt > 0) oneThread = false; } msg_release_list_struct(&peerList); if (oneThread == true) svc_handle = __get_service_with_msg_id(gAppData, service); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_REPORT) == 0) { svc_handle = __get_service_with_msg_id(gAppData, service); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_BUBBLE) == 0) { svc_handle = __get_service_with_msg_id(gAppData, service); } } D_LEAVE; return svc_handle; } static service_h __get_service_with_new_msg(struct appdata *ad) { D_ENTER; msg_error_t err = MSG_SUCCESS; msg_struct_list_s peerList; msg_struct_t sort_rule_t = msg_create_struct(MSG_STRUCT_SORT_RULE); service_h svc_handle = NULL; int i = 0; int new_sms_cnt = 0; int new_mms_cnt = 0; int unreadCnt = 0; char buf[DEF_BUF_LEN_L] = {'0',}; char buf_contact[DEF_BUF_LEN] = {'0',}; msg_set_int_value(sort_rule_t, MSG_SORT_RULE_SORT_TYPE_INT, MSG_SORT_BY_THREAD_DATE); msg_set_bool_value(sort_rule_t, MSG_SORT_RULE_ACSCEND_BOOL, false); vconf_get_int(VCONFKEY_MESSAGE_RECV_SMS_STATE, &new_sms_cnt); vconf_get_int(VCONFKEY_MESSAGE_RECV_MMS_STATE, &new_mms_cnt); err = msg_get_thread_view_list(ad->msgHandle, sort_rule_t, &peerList); if (err != MSG_SUCCESS) { msg_release_struct(&sort_rule_t); return NULL; } if (peerList.nCount <= 0) { msg_release_list_struct(&peerList); msg_release_struct(&sort_rule_t); return NULL; } for (i=0; i 0) break; } if(i >= peerList.nCount) { msg_release_list_struct(&peerList); msg_release_struct(&sort_rule_t); return NULL; } msg_get_int_value(peerList.msg_struct_info[i], MSG_THREAD_UNREAD_COUNT_INT, &unreadCnt); if(unreadCnt == new_sms_cnt+new_mms_cnt){ if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); msg_release_list_struct(&peerList); msg_release_struct(&sort_rule_t); return NULL; } msg_struct_list_s *addrList = NULL; int thread_id = 0; int contact_id = 0; char strName[DEF_THREAD_NAME_LEN+1] = {0,}; char strNumber[DEF_THREAD_ADDR_LEN+1] = {0,}; msg_get_int_value(peerList.msg_struct_info[i], MSG_THREAD_ID_INT, &thread_id); msg_get_list_handle(peerList.msg_struct_info[i], MSG_MESSAGE_ADDR_LIST_STRUCT, (void **)&addrList); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_TYPE, MSG_BUNDLE_VALUE_NEW_MSG); snprintf(buf, DEF_BUF_LEN_L, "%d", thread_id); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_ID, buf); msg_get_str_value(peerList.msg_struct_info[i], MSG_THREAD_NAME_STR, strName, DEF_THREAD_NAME_LEN); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_NAME, strName); msg_get_str_value(addrList->msg_struct_info[0], MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, strNumber, DEF_THREAD_ADDR_LEN); msg_get_int_value(addrList->msg_struct_info[0], MSG_ADDRESS_INFO_CONTACT_ID_INT, &contact_id); snprintf(buf_contact, DEF_BUF_LEN, "%d", contact_id); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_ADDRESS, strNumber); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_CONTACT_ID, buf_contact); } msg_release_struct(&sort_rule_t); msg_release_list_struct(&peerList); D_LEAVE; return svc_handle; } static service_h __get_service_with_msg_id(struct appdata *ad, service_h service) { D_ENTER; service_h svc_handle = NULL; if (service_create(&svc_handle) < 0 || svc_handle == NULL) { D_EMSG("service_create() is failed !!"); return NULL; } int msg_id = 0; char *msg_id_str = NULL; service_get_extra_data(service, MSG_BUNDLE_KEY_MSG_ID, &msg_id_str); if (!msg_id_str) { service_destroy(svc_handle); return NULL; } msg_id = atoi(msg_id_str); if (msg_id <= 0) { service_destroy(svc_handle); return NULL; } msg_struct_t msgInfo = msg_create_struct(MSG_STRUCT_MESSAGE_INFO); msg_struct_t sendOpt = msg_create_struct(MSG_STRUCT_SENDOPT); msg_error_t err = MSG_SUCCESS; int thread_id = 0; int contact_id = 0; char buf_thread[DEF_BUF_LEN_S] = {0,}; char buf_storage[DEF_BUF_LEN_S] = {0,}; char buf_contact[DEF_BUF_LEN_S] = {0,}; msg_struct_list_s *addr_list = NULL; char strNumber[DEF_THREAD_ADDR_LEN + 1] = {0,}; char strName[DEF_THREAD_NAME_LEN + 1] = {0,}; err = msg_get_message(ad->msgHandle, (msg_message_id_t)msg_id, msgInfo, sendOpt); if (err != MSG_SUCCESS) { service_destroy(svc_handle); msg_release_struct(&msgInfo); msg_release_struct(&sendOpt); return NULL; } msg_get_int_value(msgInfo, MSG_MESSAGE_THREAD_ID_INT, &thread_id); snprintf(buf_thread, sizeof(buf_thread), "%d", thread_id); msg_get_list_handle(msgInfo, MSG_MESSAGE_ADDR_LIST_STRUCT, (void **)&addr_list); msg_get_str_value(addr_list->msg_struct_info[0], MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, strNumber, DEF_THREAD_ADDR_LEN); msg_get_str_value(addr_list->msg_struct_info[0], MSG_ADDRESS_INFO_DISPLAYNAME_STR, strName, DEF_THREAD_NAME_LEN); msg_get_int_value(addr_list->msg_struct_info[0], MSG_ADDRESS_INFO_CONTACT_ID_INT, &contact_id); snprintf(buf_contact, sizeof(buf_contact), "%d", contact_id); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_ID, buf_thread); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_NAME, strName); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_ADDRESS, strNumber); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_CONTACT_ID, buf_contact); service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_STORAGE_ID, buf_storage); msg_release_struct(&msgInfo); msg_release_struct(&sendOpt); D_LEAVE; return svc_handle; } static Evas_Object* create_win(const char *name) { D_ENTER; Evas_Object *eo; int w, h; eo = elm_win_add(NULL, name, ELM_WIN_BASIC); if (eo) { elm_win_title_set(eo, name); evas_object_smart_callback_add(eo, "delete,request", win_del, NULL); ecore_x_window_size_get(ecore_x_window_root_first_get(), &w, &h); evas_object_resize(eo, w, h); elm_win_conformant_set(eo, EINA_TRUE); } D_LEAVE; return eo; } void layout_cb(ui_gadget_h ug, enum ug_mode mode, void *priv) { D_ENTER; struct appdata *ad; Evas_Object *base; if (!ug || !priv) return; ad = priv; base = ug_get_layout(ug); if (!base){ ug_destroy(ug); return; } switch (mode) { case UG_MODE_FULLVIEW: evas_object_size_hint_weight_set(base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_show(base); break; case UG_MODE_FRAMEVIEW: default: break; } D_LEAVE; } void result_cb(ui_gadget_h ug, service_h result, void *priv) { D_ENTER; MSG_UI_RET_IF(MSG_UI_LEVEL_ERR, !ug || !priv); struct appdata *ad = priv; PMSG_THREAD_DATA pData = (PMSG_THREAD_DATA)ad->thread_data; PMSG_THREAD_LIST_DATA pListData = NULL; char *buf = NULL; char *str_result = NULL; service_get_extra_data(result, MSG_BUNDLE_KEY_RESULT, &str_result); if (pData == NULL) { if (!g_strcmp0(str_result, MSG_BUNDLE_VALUE_DEL_ALL)) msg_ui_destroy_composer_ug(ug, false); elm_exit(); return; } pListData = msg_ui_thread_get_current_list(); if (!g_strcmp0(str_result, MSG_BUNDLE_VALUE_DEL_ALL)) { elm_object_focus_set(pListData->genlist, EINA_TRUE); msg_ui_destroy_composer_ug(ug, false); if (pListData) { int del_id = 0; service_get_extra_data(result, MSG_BUNDLE_KEY_MSG_ID, &buf); if (buf && pListData->app_data_type != THREAD_LIST_APP_DATA_CONV) { del_id = atoi(buf); buf = NULL; msg_ui_thread_list_msg_item_delete(pListData, del_id); } service_get_extra_data(result, MSG_BUNDLE_KEY_THREAD_ID, &buf); if (buf && pListData->app_data_type != THREAD_LIST_APP_DATA_MSG) { del_id = atoi(buf); buf = NULL; msg_ui_thread_list_item_delete(pListData, del_id); } if (pListData->item_cnt <= 0 && pListData->search_mode == THREAD_SEARCH_ON) msg_ui_thread_cancel_search_mode(pListData); if (pData->isRotate == true) { if (!pData->split_data) { msg_ui_thread_create_split_data(); msg_ui_thread_splitview_launch(pData, pData->split_data); } } else { elm_object_part_content_set(pData->panes, "left", pData->layout_main); elm_object_part_content_unset(pData->panes, "right"); elm_panes_content_left_size_set(pData->panes, 1.0); } pListData->sel_gen_item = NULL; pListData->sel_thread_id = 0; pListData->sel_msg_id = 0; } } else if (!g_strcmp0(str_result, MSG_BUNDLE_VALUE_DEL_BUBBLE)) { service_get_extra_data(result, MSG_BUNDLE_KEY_THREAD_ID, &buf); if (buf && pListData->app_data_type != THREAD_LIST_APP_DATA_MSG) { int thread_id = 0; thread_id = atoi(buf); buf = NULL; msg_ui_thread_list_item_update(pListData, thread_id); } } else if (!g_strcmp0(str_result, MSG_BUNDLE_VALUE_KEYPAD_SHOW)) { pData->keypadIsShown = true; if (pData->isRotate == true) { elm_panes_content_left_size_set(pData->panes, 0.0); elm_object_signal_emit(pData->panes, "elm,panes,unpair", ""); } } else if (!g_strcmp0(str_result, MSG_BUNDLE_VALUE_KEYPAD_HIDE)) { pData->keypadIsShown = false; if (pData->isRotate == true) { elm_panes_content_left_size_set(pData->panes, 0.4); elm_object_signal_emit(pData->panes, "elm,panes,pair", ""); } } else { int update_id = 0; service_get_extra_data(result, MSG_BUNDLE_KEY_MSG_ID, &buf); if (buf && pListData->app_data_type != THREAD_LIST_APP_DATA_CONV) { update_id = atoi(buf); buf = NULL; msg_ui_thread_list_msg_item_update(pListData, update_id); } service_get_extra_data(result, MSG_BUNDLE_KEY_THREAD_ID, &buf); if (buf && pListData->app_data_type != THREAD_LIST_APP_DATA_MSG) { update_id = atoi(buf); buf = NULL; msg_ui_thread_list_item_update(pListData, update_id); } } D_LEAVE; } void destroy_cb(ui_gadget_h ug, void *priv) { D_ENTER; MSG_UI_RET_IF(MSG_UI_LEVEL_ERR, !ug || !priv); struct appdata *ad = (struct appdata *)priv; int ug_type = msg_ui_get_composer_ug_type(ug); PMSG_THREAD_LIST_DATA pListData = msg_ui_thread_get_current_list(); if (ad->layout_main) { PMSG_THREAD_DATA pData = (PMSG_THREAD_DATA)ad->thread_data; if (pListData == NULL) { msg_ui_destroy_composer_ug(ug, false); elm_exit(); return; } if (pData) { pData->keypadIsShown = false; if (ug_type == MSG_COMPOSER_UG_TYPE_VIEWER) { if (pData->isRotate == true) { if (!pData->split_data) { msg_ui_thread_create_split_data(); msg_ui_thread_splitview_launch(pData, pData->split_data); } if (pListData->search_mode == THREAD_SEARCH_ON) msg_ui_thread_cancel_search_mode(pListData); else elm_win_lower(pData->win_main); } else { elm_object_part_content_set(pData->panes, "left", pData->layout_main); elm_object_part_content_unset(pData->panes, "right"); elm_panes_content_left_size_set(pData->panes, 1.0); } } pListData->view_mode = THREAD_NORMAL_VIEW; } msg_ui_destroy_composer_ug(ug, false); } else { msg_ui_destroy_composer_ug(ug, false); elm_exit(); } } int msg_ui_load_composer_ug(service_h svc_handle, MessageComposerUgType ug_type, bool isListItem) { D_ENTER; if (!gAppData) return MSG_UI_RET_ERR; ugdata *composer_data = NULL; ui_gadget_h ug_h = NULL; bool bReset = false; ugdata *exist_data = gAppData->composer_data; PMSG_THREAD_LIST_DATA pListData = msg_ui_thread_get_current_list(); if (ug_type == MSG_COMPOSER_UG_TYPE_VIEWER) { while (exist_data) { if (exist_data->ug_type == MSG_COMPOSER_UG_TYPE_VIEWER) { bReset = true; break; } exist_data = exist_data->next_ug; } if (exist_data && bReset) { ug_send_message(exist_data->ug_h, svc_handle); ug_h = exist_data->ug_h; } else { service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_FROM, MSG_BUNDLE_VALUE_INTERNAL); ug_h = ug_create(NULL, MSG_COMPOSER_UG_NAME, UG_MODE_FRAMEVIEW, svc_handle, &gAppData->cbs); } } else { service_add_extra_data(svc_handle, MSG_BUNDLE_KEY_FROM, MSG_BUNDLE_VALUE_INTERNAL); ug_h = ug_create(NULL, MSG_COMPOSER_UG_NAME, UG_MODE_FULLVIEW, svc_handle, &gAppData->cbs); } if (!ug_h) return MSG_UI_RET_ERR; if (bReset == false) { composer_data = (ugdata *)calloc(1, sizeof(ugdata)); composer_data->ug_h = ug_h; composer_data->ug_type = ug_type; exist_data = gAppData->composer_data; if (exist_data) { while (exist_data) { if (exist_data->next_ug == NULL) { exist_data->next_ug = composer_data; composer_data->prev_ug = exist_data; break; } exist_data = exist_data->next_ug; } } else { gAppData->composer_data = composer_data; } if (pListData && isListItem) { composer_data->sel_gen_item = pListData->sel_gen_item; composer_data->sel_thread_id = pListData->sel_thread_id; composer_data->sel_msg_id = pListData->sel_msg_id; } } else if (exist_data && pListData && isListItem) { exist_data->sel_gen_item = pListData->sel_gen_item; exist_data->sel_thread_id = pListData->sel_thread_id; exist_data->sel_msg_id = pListData->sel_msg_id; } if (ug_type == MSG_COMPOSER_UG_TYPE_VIEWER) { PMSG_THREAD_DATA pData = (PMSG_THREAD_DATA)gAppData->thread_data; Evas_Object * layout = (Evas_Object *)ug_get_layout(ug_h); elm_object_part_content_set(pData->panes, "right", layout); msg_ui_thread_destroy_split_data(pData->split_data); if (pData->isRotate == false) { elm_panes_content_left_size_set(pData->panes, 0.0); evas_object_hide(pData->layout_main); } } D_LEAVE; return MSG_UI_RET_SUCCESS; } Evas_Object *msg_ui_get_main_layout(void) { D_ENTER; if (!gAppData) return NULL; return gAppData->layout_main; } ugdata *msg_ui_get_composer_ug_data(ui_gadget_h ug) { D_ENTER; ugdata *composer_data = NULL; if (!gAppData || !gAppData->composer_data) return NULL; composer_data = gAppData->composer_data; while (composer_data) { if (composer_data->ug_h == ug) return composer_data; composer_data = composer_data->next_ug; } D_LEAVE; return NULL; } Evas_Object *msg_ui_get_composer_ug_viewer_layout(void) { D_ENTER; ugdata *composer_data = NULL; Evas_Object * layout = NULL; if (!gAppData || !gAppData->composer_data) return NULL; composer_data = gAppData->composer_data; while (composer_data) { if (composer_data->ug_type == MSG_COMPOSER_UG_TYPE_VIEWER) { layout = (Evas_Object *)ug_get_layout(composer_data->ug_h); break; } composer_data = composer_data->next_ug; } D_LEAVE; return layout; } void msg_ui_destroy_composer_ug(ui_gadget_h ug, bool bDeleteAll) { D_ENTER; ugdata *composer_data = NULL; PMSG_THREAD_LIST_DATA pListData = NULL; pListData = msg_ui_thread_get_current_list(); composer_data = gAppData->composer_data; if (bDeleteAll) { while (composer_data) { if (composer_data->ug_h) ug_destroy(composer_data->ug_h); free(composer_data); composer_data = composer_data->next_ug; } gAppData->composer_data = NULL; } else { while (composer_data) { if (ug == NULL) break; if (ug == composer_data->ug_h) { if (pListData) { if (pListData->genlist) elm_object_focus_set(pListData->genlist, EINA_TRUE); if ((pListData->sel_thread_id > 0) && (pListData->sel_thread_id == composer_data->sel_thread_id)) { int thread_id = pListData->sel_thread_id; pListData->sel_thread_id = 0; msg_ui_thread_list_item_update(pListData, thread_id); } if ((pListData->sel_msg_id > 0) && (pListData->sel_msg_id == composer_data->sel_msg_id)) { int msg_id = pListData->sel_msg_id; pListData->sel_msg_id = 0; msg_ui_thread_list_msg_item_update(pListData, msg_id); } if (pListData->sel_gen_item == composer_data->sel_gen_item) pListData->sel_gen_item = NULL; msg_ui_thread_set_title_unread_cnt(pListData); } ug_destroy(ug); if (composer_data->prev_ug) { if (composer_data->next_ug) composer_data->prev_ug->next_ug = composer_data->next_ug; else composer_data->prev_ug->next_ug = NULL; } else { gAppData->composer_data = NULL; } free(composer_data); break; } composer_data = composer_data->next_ug; } } D_LEAVE; } int msg_ui_get_composer_ug_type(ui_gadget_h ug) { D_ENTER; ugdata *composer_data = NULL; int ug_type = MSG_COMPOSER_UG_TYPE_NONE; if (!gAppData || !gAppData->composer_data) return MSG_COMPOSER_UG_TYPE_NONE; composer_data = gAppData->composer_data; while (composer_data) { if (composer_data->ug_h == ug) { ug_type = composer_data->ug_type; break; } composer_data = composer_data->next_ug; } D_LEAVE; return ug_type; } static bool app_create(void *data) { /* return TRUE : success, return FALSE : not to run main loop */ D_ENTER; MSG_UI_RETV_IF(MSG_UI_LEVEL_ERR, !data, MSG_UI_RET_ERR); struct appdata *ad = data; Evas_Object *win; sound_manager_error_e snd_err = SOUND_MANAGER_ERROR_NONE; contacts_error_e ct_err = CONTACTS_ERROR_NONE; /* create window */ win = create_win(MESSAGE_PKGNAME); if (win == NULL) return FALSE; ad->win_main = win; ad->bg = elm_bg_add(ad->win_main); evas_object_size_hint_weight_set(ad->bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(ad->win_main, ad->bg); ad->conform = elm_conformant_add(win); if (ad->conform == NULL) return FALSE; evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(win, ad->conform); evas_object_show(ad->conform); snd_err = sound_manager_set_session_type(SOUND_SESSION_TYPE_SHARE); if (snd_err != SOUND_MANAGER_ERROR_NONE) D_MSG("sound_manager_set_session_type is failed, snd_err = [%d]", snd_err); ct_err = contacts_connect2(); if (ct_err != CONTACTS_ERROR_NONE) D_EMSG("contacts_svc_connect2 failed : ct_err = [%d]", ct_err); UG_INIT_EFL(ad->win_main, UG_OPT_INDICATOR_ENABLE); elm_win_indicator_mode_set(ad->win_main, ELM_WIN_INDICATOR_SHOW); if(elm_win_wm_rotation_supported_get(ad->win_main)) { int rotation[4] = {0, 90, 180, 270}; elm_win_wm_rotation_available_rotations_set(ad->win_main, rotation, 4); ad->cur_rotation = elm_win_rotation_get(ad->win_main); D_MSG("current rotation %d", ad->cur_rotation); evas_object_smart_callback_add(ad->win_main, "wm,rotation,changed", rotation_changed_cb, ad); } ad->cbs.layout_cb = layout_cb; ad->cbs.result_cb = result_cb; ad->cbs.destroy_cb = destroy_cb; ad->cbs.priv = (void *)ad; gAppData = ad; // Set global app data pointer; D_LEAVE; return TRUE; } static void app_terminate(void *data) { D_ENTER; MSG_UI_RETM_IF(MSG_UI_LEVEL_ERR, !data, "data is null"); struct appdata *ad = data; msg_error_t err; contacts_error_e ct_err = CONTACTS_ERROR_NONE; ug_destroy_all(); ct_err = contacts_disconnect2(); if (ct_err != CONTACTS_ERROR_NONE) D_EMSG("contacts_svc_disconnect2 failed : ct_err = [%d]", ct_err); if (ad->thread_data) msg_ui_thread_deinit_thread_data(ad->thread_data); if (ad->msgHandle) { err = msg_close_msg_handle(&ad->msgHandle); D_MSG("msg_close_msg_handle, ret = [%d]", err); } D_LEAVE; } static void app_pause(void *data) { D_ENTER; msg_ui_thread_set_app_state(MSG_UI_STATE_PAUSE); ug_pause(); D_LEAVE; } static void app_resume(void *data) { D_ENTER; msg_ui_thread_set_app_state(MSG_UI_STATE_RUNNING); ug_resume(); D_LEAVE; } static void app_service(service_h service, void *data) { D_ENTER; MSG_UI_RETM_IF(MSG_UI_LEVEL_ERR, !data, "data is NULL"); struct appdata *ad = data; service_h svc_handle = NULL; msg_error_t err = MSG_SUCCESS; msg_handle_t msgHandle = NULL; bool isDefaultView = false; char *operation = NULL; char *cvalue = NULL; int ret = SYSTEM_INFO_ERROR_NONE; ret = system_info_get_value_string(SYSTEM_INFO_KEY_MODEL, &cvalue); if (ret == SYSTEM_INFO_ERROR_NONE && cvalue != NULL) { if (g_strcmp0(cvalue, "Emulator") == 0) { D_MSG("Not support in Emulator !!"); g_free(cvalue); cvalue = NULL; service_h reply; int ret = service_create(&reply); if (ret != SERVICE_ERROR_NONE) { D_EMSG("service_create() is failed : ret = %d", ret); } else { service_reply_to_launch_request(reply, service, SERVICE_RESULT_CANCELED); service_destroy(reply); } /* Exit application because it is not supported in Emulator. */ elm_exit(); return; } } if (cvalue) { g_free(cvalue); cvalue = NULL; } ug_resume(); if (!ad->msgHandle) { err = msg_open_msg_handle(&msgHandle); if (err != MSG_SUCCESS) { MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "msg_open_msg_handle failed, Error=[%d]\n", err); __msg_ui_popup_warning(ad->win_main, dgettext("sys_string", "IDS_COM_POP_SERVICE_UNAVAILABLE")); return; } ad->msgHandle = msgHandle; } if (service) { service_get_operation(service, &operation); if (operation) { svc_handle = __get_service_app_svc_op(operation, service); } else { char *key_type = NULL; service_get_extra_data(service, MSG_BUNDLE_KEY_TYPE, &key_type); if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_COMPOSE) == 0) { service_clone(&svc_handle, service); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_NEW_MSG) == 0) { svc_handle = __get_service_with_new_msg(ad); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_MSG_ID) == 0) { svc_handle = __get_service_with_msg_id(ad, service); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_REPORT) == 0) { svc_handle = __get_service_with_msg_id(ad, service); } else if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_BUBBLE) == 0) { svc_handle = __get_service_with_msg_id(ad, service); } else { char *mime_type = NULL; service_get_extra_data(service, AUL_K_MIME_TYPE, &mime_type); if (g_strcmp0(mime_type, MSG_BUNDLE_VALUE_SMS_URI) == 0) svc_handle = __msg_ui_parse_sms_uri(service, NULL); else if (g_strcmp0(mime_type, MSG_BUNDLE_VALUE_MMSTO_URI) == 0) svc_handle = __msg_ui_parse_mmsto_uri(service, NULL); else isDefaultView = true; } } if (!svc_handle) { isDefaultView = true; } else { int storge_id = 0; char *buf = NULL; service_get_extra_data(svc_handle, MSG_BUNDLE_KEY_STORAGE_ID, &buf); if (buf != NULL) storge_id = atoi(buf); if (storge_id == MSG_STORAGE_SIM) isDefaultView = true; } } else { isDefaultView = true; } if (isDefaultView) { MSG_UI_DEBUG(MSG_UI_LEVEL_DEBUG, "show DefaultView"); if (ad->composer_data) { ugdata *composer_data = ad->composer_data; while (composer_data) { service_h composer_svc_handle = NULL; if (service_create(&composer_svc_handle) < 0 || composer_svc_handle == NULL) D_EMSG("service_create() is failed !!"); composer_data = composer_data->next_ug; } msg_ui_destroy_composer_ug(NULL, true); } if (!ad->thread_data) ad->thread_data = msg_ui_thread_init_thread_data(ad); if (svc_handle) { /*sim message viewer*/ MSG_UI_DEBUG(MSG_UI_LEVEL_DEBUG, "show sim message viewer"); if (!ad->layout_main) { ad->layout_main = msg_ui_thread_create_layout_main(ad->thread_data); evas_object_size_hint_weight_set(ad->layout_main, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_content_set(ad->conform, ad->layout_main); } else { PMSG_THREAD_DATA pData = (PMSG_THREAD_DATA)ad->thread_data; int i = 0; if (pData->detail_layout) { if (pData->isRotate == true) elm_object_item_del(elm_naviframe_top_item_get(pData->split_data->navi_frame)); else elm_object_item_del(elm_naviframe_top_item_get(pData->navi_frame)); pData->detail_layout = NULL; } for (i = MSG_THREAD_LIST_MAX_COUNT-1; i >= 0; i--) { if (pData->list_data[i] != NULL) { if (pData->list_data[i]->loaded_ug) { ug_destroy(pData->list_data[i]->loaded_ug); pData->list_data[i]->loaded_ug = NULL; } elm_object_item_del(elm_naviframe_top_item_get(pData->navi_frame)); elm_genlist_clear(pData->list_data[i]->genlist); msg_ui_thread_destroy_thread_list_data(pData->list_data[i]); } } if (pData->split_data) msg_ui_thread_destroy_split_data(pData->split_data); } elm_win_conformant_set(ad->win_main, 1); int msg_id = 0; char *buf = NULL; PMSG_APP_THREAD_ADDR_INFO_S* addr_info = NULL; char* strNumber = NULL; char* strName = NULL; service_get_extra_data(service, MSG_BUNDLE_KEY_MSG_ID, &buf); if (buf != NULL) { msg_id = atoi(buf); buf = NULL; } addr_info = (PMSG_APP_THREAD_ADDR_INFO_S *)calloc(1, sizeof(PMSG_APP_THREAD_ADDR_INFO_S)); addr_info[0] = (PMSG_APP_THREAD_ADDR_INFO_S)calloc(1, sizeof(MSG_APP_THREAD_ADDR_INFO_S)); service_get_extra_data(svc_handle, MSG_BUNDLE_KEY_CONTACT_ID, &buf); if (buf != NULL) { addr_info[0]->contact_id = atoi(buf); buf = NULL; } service_get_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_ADDRESS, &strNumber); if (strNumber && strlen(strNumber) > 0) strncpy(addr_info[0]->address, strNumber, DEF_THREAD_ADDR_LEN); else strncpy(addr_info[0]->address, "", DEF_THREAD_ADDR_LEN); service_get_extra_data(svc_handle, MSG_BUNDLE_KEY_THREAD_NAME, &strName); if (strName && strlen(strName) > 0) strncpy(addr_info[0]->display_name, strName, DEF_THREAD_NAME_LEN); else strncpy(addr_info[0]->display_name, "", DEF_THREAD_NAME_LEN); msg_update_read_status(ad->msgHandle, msg_id, true); msg_ui_thread_launch_msg_detail_view(NULL, msg_id, 1, addr_info); free(addr_info[0]); free(addr_info); } else { if (!ad->layout_main) { ad->layout_main = msg_ui_thread_create_layout_main(ad->thread_data); evas_object_size_hint_weight_set(ad->layout_main, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_content_set(ad->conform, ad->layout_main); msg_ui_thread_load_thread_view(ad->thread_data, service); } else { msg_ui_thread_reset_thread_view(ad->thread_data, service); } } } else { MSG_UI_DEBUG(MSG_UI_LEVEL_DEBUG, "show app-service view"); /* If message app is called by app-service to display composer view, * list view should be destroyed because previous screen should be displayed * when user tap back button. */ MessageComposerUgType ug_type = MSG_COMPOSER_UG_TYPE_NONE; if (operation != NULL) { int i = 0; PMSG_THREAD_DATA pData = (PMSG_THREAD_DATA)ad->thread_data; if (g_strcmp0(operation, SERVICE_OPERATION_SEND) == 0 || g_strcmp0(operation, SERVICE_OPERATION_SEND_TEXT) == 0) { if (ad->layout_main) { if (pData) { /* content unset composer */ if (elm_object_part_content_get(pData->panes, "right") != NULL) elm_object_part_content_unset(pData->panes, "right"); for (i = MSG_THREAD_LIST_MAX_COUNT-1; i >= 0; i--) { if (pData->list_data[i] != NULL) { elm_object_item_del(elm_naviframe_top_item_get(pData->navi_frame)); elm_genlist_clear(pData->list_data[i]->genlist); msg_ui_thread_destroy_thread_list_data(pData->list_data[i]); } } if (pData->split_data) msg_ui_thread_destroy_split_data(pData->split_data); } evas_object_del(ad->layout_main); ad->layout_main = NULL; } ug_type = MSG_COMPOSER_UG_TYPE_COMPOSER; } else if (g_strcmp0(operation, SERVICE_OPERATION_DEFAULT) == 0) { char *key_type = NULL; service_get_extra_data(service, MSG_BUNDLE_KEY_TYPE, &key_type); if (g_strcmp0(key_type, MSG_BUNDLE_VALUE_MSG_ID) == 0 || g_strcmp0(key_type, MSG_BUNDLE_VALUE_REPORT) == 0 || g_strcmp0(key_type, MSG_BUNDLE_VALUE_BUBBLE) == 0) { if (ad->layout_main) { if (pData) { /* content unset composer */ if (elm_object_part_content_get(pData->panes, "right") != NULL) elm_object_part_content_unset(pData->panes, "right"); for (i = MSG_THREAD_LIST_MAX_COUNT-1; i >= 0; i--) { if (pData->list_data[i] != NULL) { elm_object_item_del(elm_naviframe_top_item_get(pData->navi_frame)); elm_genlist_clear(pData->list_data[i]->genlist); msg_ui_thread_destroy_thread_list_data(pData->list_data[i]); } } if (pData->split_data) msg_ui_thread_destroy_split_data(pData->split_data); } evas_object_del(ad->layout_main); ad->layout_main = NULL; } ug_type = MSG_COMPOSER_UG_TYPE_VIEWER; } } } if (ad->composer_data) { ugdata *composer_data = ad->composer_data; while (composer_data) { service_h composer_svc_handle = NULL; if (service_create(&composer_svc_handle) < 0 || composer_svc_handle == NULL) D_EMSG("service_create() is failed !!"); composer_data = composer_data->next_ug; } msg_ui_destroy_composer_ug(NULL, true); } ugdata *composer_data = NULL; composer_data = (ugdata*)calloc(1, sizeof(ugdata)); composer_data->ug_h = ug_create(NULL, MSG_COMPOSER_UG_NAME, UG_MODE_FULLVIEW, svc_handle, &ad->cbs); composer_data->ug_type = ug_type; ad->composer_data = composer_data; } if (svc_handle) service_destroy(svc_handle); if (ad->win_main) { evas_object_show(ad->win_main); elm_win_activate(ad->win_main); } if (ad->layout_main == NULL && ad->composer_data == NULL) elm_exit(); D_LEAVE; } int main(int argc, char *argv[]) { D_ENTER; struct appdata ad; memset(&ad, 0x0, sizeof(struct appdata)); app_event_callback_s event_callback; event_callback.create = app_create; event_callback.terminate = app_terminate; event_callback.pause = app_pause; event_callback.resume = app_resume; event_callback.service = app_service; event_callback.low_memory = NULL; event_callback.low_battery = low_battery_cb; event_callback.language_changed = lang_changed; event_callback.device_orientation = NULL; event_callback.region_format_changed = region_changed_cb; D_LEAVE; return app_efl_main(&argc, &argv, &event_callback, &ad); }