3 * Copyright 2012 Samsung Electronics Co., Ltd
5 * Licensed under the Flora License, Version 1.1 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://floralicense.org/license/
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include <Elementary.h>
22 #include <extended-elm.h>
25 #include <memo_string.h>
28 #include <contacts-ug.h>
29 #include <memo_autolink.h>
32 static void _autolink_popup_response_cb(void *data, Evas_Object *obj, void *event_info);
33 /* BEGIN CONVERTE BETWEEN enum anchor_t AND string */
35 static char *_autolink_anchor_type_to_string(enum anchor_t type)
49 /* END CONVERTE BETWEEN enum anchor_t AND string */
51 /* BEGIN POPUP CALLBACK */
53 static void _autolink_send_email_selected_cb(void *data, Evas_Object *obj, void *event_info)
55 struct autolink_data_t *ald = (struct autolink_data_t *)data;
56 service_h service = NULL;
57 service_create(&service);
58 service_add_extra_data(service, "RUN_TYPE", "5");
59 service_add_extra_data(service, "TO", ald->info);
61 ug_launch_common(service, UG_NAME_EMAIL);
62 _autolink_popup_response_cb(ald, ald->popup, NULL);
65 static void _autolink_send_message_selected_cb(void *data, Evas_Object *obj, void *event_info)
67 struct autolink_data_t *ald = (struct autolink_data_t *)data;
69 ug_launch_common_var(UG_NAME_MESSAGE, "TO", ald->info, NULL);
70 _autolink_popup_response_cb(ald, ald->popup, NULL);
73 static void _autolink_vioce_call_selected_cb(void *data, Evas_Object *obj, void *event_info)
75 struct autolink_data_t *ald = (struct autolink_data_t *)data;
76 bundle *bd = bundle_create();
77 char telnum[255] = {0,};
79 appsvc_set_operation(bd, APPSVC_OPERATION_CALL);
80 snprintf(telnum, sizeof(telnum), "tel:%s", ald->info);
81 appsvc_set_uri(bd, telnum);
82 appsvc_run_service(bd, 0, NULL, NULL);
85 _autolink_popup_response_cb(ald, ald->popup, NULL);
88 static void _autolink_video_call_selected_cb(void *data, Evas_Object *obj, void *event_info)
90 struct autolink_data_t *ald = (struct autolink_data_t *)data;
91 service_h service = NULL;
92 service_create(&service);
93 service_add_extra_data(service, "KEY_CALL_TYPE", "mo");
94 service_add_extra_data(service, "KEY_CALL_HANDLE", "1");
95 service_add_extra_data(service, "KEY_CALLING_PARTY_NUMBER", ald->info);
96 service_add_extra_data(service, "KEY_CLI_CAUSE", "-1");
97 service_add_extra_data(service, "KEY_FORWARDED", "-1");
98 service_set_package(service, AUL_NAME_VEDIO_CALL);
99 service_send_launch_request(service, NULL, NULL);
101 service_destroy(service);
102 _autolink_popup_response_cb(ald, ald->popup, NULL);
105 static void _autolink_email_add_to_contact_selected_cb(void *data, Evas_Object *obj,
108 struct autolink_data_t *ald = (struct autolink_data_t *)data;
111 snprintf(buf, sizeof(buf), "%d", CT_UG_REQUEST_ADD_WITH_EMAIL);
113 service_h service = NULL;
114 service_create(&service);
115 service_add_extra_data(service, CT_UG_BUNDLE_TYPE, buf);
116 service_add_extra_data(service, CT_UG_BUNDLE_EMAIL, ald->info);
118 ug_launch_common(service, UG_CONTACTS_DETAILS);
119 _autolink_popup_response_cb(ald, ald->popup, NULL);
122 static void _autolink_phone_add_to_contact_selected_cb(void *data, Evas_Object *obj,
125 struct autolink_data_t *ald = (struct autolink_data_t *)data;
128 snprintf(buf, sizeof(buf), "%d", CT_UG_REQUEST_ADD_WITH_NUM);
130 service_h service = NULL;
131 service_create(&service);
132 service_add_extra_data(service, CT_UG_BUNDLE_TYPE, buf);
133 service_add_extra_data(service, CT_UG_BUNDLE_NUM, ald->info);
135 ug_launch_common(service, UG_CONTACTS_DETAILS);
136 _autolink_popup_response_cb(ald, ald->popup, NULL);
139 /* END POPUP CALLBACK */
141 static struct anchor_popup_item_t g_email_list[] = {
142 {"IDS_MEMO_OPT_SEND_EMAIL", _autolink_send_email_selected_cb, "memo"},
143 {"IDS_MEMO_BODY_ADD_TO_CONTACT", _autolink_email_add_to_contact_selected_cb, "memo"},
146 static struct anchor_popup_item_t g_phone_list[] = {
147 {"IDS_COM_BODY_VOICE_CALL", _autolink_vioce_call_selected_cb, "sys_string"},
148 {"IDS_COM_BODY_SEND_MESSAGE", _autolink_send_message_selected_cb, "sys_string"},
149 {"IDS_COM_BODY_VIDEO_CALL", _autolink_video_call_selected_cb, "sys_string"},
150 {"IDS_MEMO_BODY_ADD_TO_CONTACT", _autolink_phone_add_to_contact_selected_cb, "memo"},
153 static char *_autolink_gl_label_get(void *data, Evas_Object *obj, const char *part)
155 char *label = (char *)data;
156 if (strcmp(part, "elm.text") == 0) {
157 return strdup(label);
162 static void _autolink_popup_response_cb(void *data, Evas_Object *obj, void *event_info)
166 assert(data != NULL);
167 struct autolink_data_t *ald = (struct autolink_data_t *)data;
168 if (ald->popup != NULL) {
169 evas_object_del(ald->popup);
172 assert(ald->info != NULL);
179 void _autolink_popup_show(char *title, struct autolink_data_t *ald)
181 struct anchor_popup_item_t *list = NULL;
183 Evas_Object *box = NULL;
188 count = ARRAY_SIZE(g_email_list);
192 count = ARRAY_SIZE(g_phone_list);
198 Evas_Object *popup = elm_popup_add(ald->win_main);
200 elm_object_part_text_set(popup, "title,text", title);
201 Evas_Object *btn1 = elm_button_add(popup);
202 elm_object_text_set(btn1, MEMO_I18N_CLOSE);
203 elm_object_part_content_set(popup, "button1", btn1);
204 evas_object_smart_callback_add(btn1, "clicked", _autolink_popup_response_cb, ald);
205 evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
207 static Elm_Genlist_Item_Class itc;
208 memset(&itc, 0, sizeof(Elm_Genlist_Item_Class));
209 itc.item_style = "1text";
210 itc.func.text_get = _autolink_gl_label_get;
212 Evas_Object *genlist = elm_genlist_add(popup);
213 evas_object_smart_callback_add(genlist, "selected", NULL, NULL);
214 evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
215 evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL);
218 for (i = 0; i < count; ++i) {
219 elm_genlist_item_append(genlist, &itc, dgettext(list[i].domain, list[i].label),
220 NULL, ELM_GENLIST_ITEM_NONE, list[i].response, ald);
223 evas_object_show(genlist);
224 box = elm_box_add(popup);
225 evas_object_size_hint_min_set(box, 0, (count>3 ? 3 : count)*71);
226 elm_box_pack_end(box, genlist);
227 evas_object_show(box);
228 elm_object_content_set(popup, box);
229 evas_object_show(popup);
232 void autolink_anchor_clicked_cb(void *data, Evas_Object *obj, void *event_info)
234 Elm_Entry_Anchor_Info *ei = (Elm_Entry_Anchor_Info *)event_info;
235 autolink_data *ald = SMALLOC(autolink_data);
238 int info_len = strlen(ei->name) + 1;
239 ald->info = calloc(1, info_len);
240 if (ald->info == NULL) {
245 ald->win_main = (Evas_Object *)data;
246 /* retrieve anchor info, eg `url|www phone_num|8888 email|abc@k.com` */
247 switch (ei->name[0]) {
249 ald->type = ANCHOR_URL;
252 ald->type = ANCHOR_PHONE;
255 ald->type = ANCHOR_EMAIL;
258 ald->type = NOT_ANCHOR;
261 const char *start = ei->name + strlen(_autolink_anchor_type_to_string(ald->type)) +1;
262 const char *end = strchr(ei->name, ' ');
263 strncpy(ald->info, start, end - start);
264 LOGD("Anchor clicked (%s)\n", ald->info);
266 if ((ald->type == ANCHOR_EMAIL) || (ald->type == ANCHOR_PHONE)){
267 _autolink_popup_show(ald->info, ald);
271 if (ald->type == ANCHOR_URL) {
272 aul_open_content(ald->info); /* launch browser */
278 static Eina_Bool str_is_begin_with(const char *str, const char *prefix)
280 if (strlen(str) < strlen(prefix)) {
285 for (i = 0; i < strlen(prefix); ++i) {
286 if (str[i] != prefix[i]) {
294 /* TYPE CHECKER BEGIN */
296 * [Checker Function Specification]
297 * These function get target type from beginning of string.
298 * The only parameter str is the string that want to be checked.
299 * Let's assume the returned value is r. There are 3 cases:
300 * r > 0 : From beginning to r of str match the target type.
301 * r = 0 : Str doesn't have target type, no longer check.
302 * r < 0 : It doesn't match from beginning, but from -r position maybe matched.
303 * It will be checked next time.
305 static int _autolink_url_checker(const char* str)
307 char *prefix[] = {"http://", "www.", "wap."};
310 for (i = 0; i < ARRAY_SIZE(prefix); ++i) {
311 if (str_is_begin_with(str, prefix[i])) { /* Begin with specified prefix */
313 while(str[j] != '\0' && !isspace(str[j])) {
314 if (str[j] == '<') { /* tag begin */
320 if(j == strlen(prefix[i])) { /* only with prefix alone */
328 /* not matched, get next position */
329 #if 0 /* Need correct */
332 for (i = 0; i < ARRAY_SIZE(prefix); ++i) {
333 p = strstr(str, prefix[i]);
337 } else if (next > p - str) {
347 static int _autolink_email_checker(const char* str)
350 p = strchr(str, '@');
354 } else if (p == str) { /* '@' at beginning */
359 if (next == '@') { /* consecutive '@' */
360 return -(p + 2 - str);
361 } else if (next == '.') { /* "@." */
362 return -(p + 2 - str);
363 } else if (next == '\0') { /* '@' at end of string */
364 return -(p + 1 - str);
365 } else if (isspace(next) || next == '<') { /* '@' at end of word */
366 return -(p + 2 - str);
369 /* check if valid before @ */
373 return -(q + 1 - str);
376 if (*q == '>' || *q == '/') { /* tag end and other illega character */
377 return -(q + 1 - str);
380 if (*q == '.' && ( q == str || *(q - 1) == '.')) {
381 return -(q + 1 - str);
387 /* get the end position of email */
389 while (*q != '\0' && !isspace(*q)) {
390 if (*q == '.' && *(q + 1) == '.') {
394 if (*q == '<') { /* tag begin */
403 static int _autolink_phone_checker(const char *str)
405 /* search beginning */
407 for (i = 0; str[i] != '\0'; ++i) {
408 /* digit, '+', '*' and '#' at the beginning of phone is valid. */
409 if (isdigit(str[i]) || str[i] == '+' || str[i] == '*' || str[i] == '#') {
418 for (i = 1; str[i] != '\0'; ++i) {
419 if (isdigit(str[i]) || str[i] == '*' || str[i] == '#') {
421 } else if (str[i] == '-') {
422 if (str[i - 1] == '-' || str[i - 1] == ' ') { /* "--" or " -" */
426 } else if (str[i] == ' ') {
427 if (str[i - 1] == '-') { /* "- " */
430 } else if (str[i - 1] == ' ' && isdigit(str[i + 1])) { /* consecutive ' ' */
432 while (isdigit(str[i + 1 + j])) { ++j; }
434 while (str[i] == ' ') { i--; }
438 } else { /* other character */
451 /* TYEP CHECKER END */
453 static void _autolink_box_anchor(GString *text, char *type, char *content)
456 if (strcmp(type, "phone_num") == 0) { /* remove '-' and ' ' in phone num. */
457 buf = (char *)malloc(strlen(content) + 1);
460 while (content[i] != '\0') {
461 if (content[i] == '-' || content[i] == ' ') {
474 g_string_append_printf(text,
475 "<color=#72b1f2FF><a href=%s|%s underline=on underline_color=#72b1f2FF>%s</a></color>",
478 if (buf != content) {
483 GString *autolink_add_anchor(const char *content)
485 assert(content != NULL);
487 const char *p = content;
489 GString *text = g_string_new("");
490 GString *buf = g_string_new("");
493 int (*check)(const char* str);
497 {_autolink_url_checker, "url", EINA_TRUE},
498 {_autolink_email_checker, "email", EINA_TRUE},
499 {_autolink_phone_checker, "phone_num", EINA_TRUE},
504 if (p[0] == '<') { /* tag begin */
505 gt = strchr(p, '>'); /* search tag end */
506 assert(gt != NULL); /* assert '<' and '>' are matched */
507 g_string_append_len(text, p, gt - p + 1);
514 for (i = 0; i < ARRAY_SIZE(checkers); ++i) {
515 if (checkers[i].invoke == EINA_TRUE) {
516 r = checkers[i].check(p);
517 if (r == 0) { /* no longer check */
518 checkers[i].invoke = EINA_FALSE;
519 } else if (r > 0) { /* Get */
520 g_string_assign(buf, ""); /* reset buffer */
521 g_string_append_len(buf, p, r);
522 _autolink_box_anchor(text, checkers[i].type, buf->str);
526 if (next_pos <= 0 || next_pos > -r) {
534 g_string_append(text, p);
536 } else if ( i == ARRAY_SIZE(checkers)) {
537 g_string_append_len(text, p, next_pos);
543 g_string_free(buf, TRUE);
544 printf("\t\t********** %s\n", text->str);