8d13e4d2eb13d503629d8f8d3c8c128e4b22d414
[platform/core/uifw/libscl-core.git] / src / legacy_support / websocket.cpp
1 /*
2  * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <assert.h>
27 #include <Ecore.h>
28 #include <Ecore_IMF.h>
29 #include <dlog.h>
30
31 #include "websocket.h"
32
33 #include <syslog.h>
34 #include <signal.h>
35
36 #include <libwebsockets.h>
37
38 #define WEBSOCKET_PORT 7681
39
40 #define RECVED_MESSAGE "recved"
41 #define MESSAGE_LEFT "left"
42
43 pthread_t g_ws_server_thread = (pthread_t)NULL;
44 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
45
46 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
47 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
48
49 bool g_ws_server_exit = false;
50 struct lws_context *g_ws_server_context = NULL;
51
52 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
53
54 int force_exit = 0;
55
56 enum protocols {
57     /* always first */
58     PROTOCOL_HTTP = 0,
59
60     PROTOCOL_KEYBOARD,
61
62     /* always last */
63     MAX_PROTOCOL_COUNT
64 };
65
66 struct per_session_data__http {
67     int fd;
68 };
69
70 static int callback_http(struct lws *wsi,
71         enum lws_callback_reasons reason,
72         void *user, void *in, size_t len)
73 {
74     return 0;
75 }
76
77 struct per_session_data__keyboard {
78     int session_id;
79     int valid;
80     int need_init;
81     int initialized;
82 };
83
84 static int callback_keyboard(struct lws *wsi,
85         enum lws_callback_reasons reason,
86         void *user, void *in, size_t len);
87
88 static struct lws_protocols protocols[] = {
89     {
90         "http-only",
91         callback_http,
92         sizeof(struct per_session_data__http),
93         0,
94     },
95     {
96         "keyboard-protocol",
97         callback_keyboard,
98         sizeof(struct per_session_data__keyboard),
99         32,
100     },
101     { NULL, NULL, 0, 0 }
102 };
103
104
105 static int callback_client(struct lws *wsi,
106     enum lws_callback_reasons reason,
107     void *user, void *in, size_t len)
108 {
109     switch (reason) {
110     case LWS_CALLBACK_CLIENT_ESTABLISHED:
111         LOGD("[ClientTest] Connection established");
112         break;
113
114     case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
115         LOGD("[ClientTest] Connection error");
116         break;
117
118     case LWS_CALLBACK_CLOSED:
119         LOGD("[ClientTest] Connection closed");
120         break;
121
122     default:
123         break;
124     }
125
126     return 0;
127 }
128
129 int test_client_connection(void)
130 {
131     struct lws_context *context = NULL;
132     struct lws_context_creation_info context_info;
133     struct lws_client_connect_info connect_info;
134     struct lws *wsi = NULL;
135
136     memset(&context_info, 0, sizeof context_info);
137     memset(&connect_info, 0, sizeof(connect_info));
138
139     const int protocols_num = sizeof(protocols) / sizeof(lws_protocols);
140     static struct lws_protocols client_protocols[protocols_num];
141
142     memcpy(&client_protocols, protocols, sizeof(protocols));
143     for (int loop = 0; loop < protocols_num - 1; loop++) {
144         client_protocols[loop].callback = callback_client;
145     }
146
147     context_info.port = CONTEXT_PORT_NO_LISTEN;
148     context_info.protocols = protocols;
149     context_info.gid = -1;
150     context_info.uid = -1;
151
152     context = lws_create_context(&context_info);
153     LOGD("[ClientTest] create_context : %p", context);
154     if (context == NULL) {
155         return -1;
156     }
157
158     connect_info.address = "localhost";
159     connect_info.port = WEBSOCKET_PORT;
160     connect_info.path = "/";
161     connect_info.context = context;
162     connect_info.ssl_connection = 0;
163     connect_info.host = connect_info.address;
164     connect_info.origin = connect_info.address;
165     connect_info.ietf_version_or_minus_one = -1;
166     connect_info.protocol = "keyboard-protocol";
167
168     wsi = lws_client_connect_via_info(&connect_info);
169     LOGD("[ClientTest] wsi created : %p", wsi);
170
171     if (wsi) {
172         lws_service(context, 50);
173     }
174
175     lws_context_destroy(context);
176
177     return 0;
178 }
179
180 static int callback_keyboard(struct lws *wsi,
181         enum lws_callback_reasons reason,
182         void *user, void *in, size_t len)
183 {
184     static int last_session_id = 0;
185     const int bufsize = 512;
186     int n = 0;
187     unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
188                           LWS_SEND_BUFFER_POST_PADDING];
189     unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
190     struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
191     CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
192
193     switch (reason) {
194     case LWS_CALLBACK_ESTABLISHED:
195         pss->session_id = ++last_session_id;
196         LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
197         pss->valid = false;
198         pss->need_init = false;
199         pss->initialized = false;
200         if (g_ws_server_context) {
201             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
202         }
203         break;
204
205     case LWS_CALLBACK_CLOSED:
206         LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
207         break;
208
209     case LWS_CALLBACK_SERVER_WRITEABLE:
210         if (agent) {
211             /* Ignore valid check since the magic key is not used anymore */
212             if (!pss->valid) pss->valid = true;
213
214             /* We allow data tranmission only if this client is guaranteed to be valid */
215             if (pss->valid) {
216                 pthread_mutex_lock(&g_ws_server_mutex);
217                 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
218
219                 if (pss->need_init && !pss->initialized) {
220                     ISE_MESSAGE message;
221                     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
222                     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
223                     std::string str = CISEMessageSerializer::serialize(message);
224                     SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
225                     n = snprintf((char *)p, bufsize, "%s", str.c_str());
226                     /* too small for partial */
227                     n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
228                     pss->need_init = false;
229                     pss->initialized = true;
230                 } else {
231                     /* One write allowed per one writable callback */
232                     if (messages.size() > 0) {
233                         ISE_MESSAGE &message = messages.front();
234                         bool drop = false;
235                         if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
236                             if (pss->initialized) {
237                                 drop = true;
238                             } else {
239                                 pss->initialized = true;
240                             }
241                         }
242                         if (!drop) {
243                             std::string str = CISEMessageSerializer::serialize(message);
244                             SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
245                             n = snprintf((char *)p, bufsize, "%s", str.c_str());
246                             /* too small for partial */
247                             n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
248                         }
249                         messages.pop();
250                     }
251                 }
252                 if (messages.size() > 0) {
253                     ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
254                 }
255                 pthread_mutex_unlock(&g_ws_server_mutex);
256
257                 if (n < 0) {
258                     LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
259                 }
260
261                 if (messages.size() > 0) {
262                     lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
263                 }
264             } else {
265                 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
266             }
267         }
268         break;
269
270     case LWS_CALLBACK_RECEIVE:
271         if (in) {
272             std::string str = (const char *)in;
273             ISE_MESSAGE message = CISEMessageSerializer::deserialize(str);
274
275             if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
276                 /*
277                 if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
278                     LOGD("LOGIN successful, validating client");
279                     pss->valid = true;
280                 } else {
281                     LOGD("LOGIN failed, invalidating client");
282                     pss->valid = false;
283                 }
284                 */
285                 pss->valid = true;
286
287                 if (agent->initalized()) {
288                     pss->need_init = true;
289                     lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
290                 }
291             }
292
293             /* Ignore valid check since the magic key is not used anymore */
294             if (!pss->valid) pss->valid = true;
295
296             if (pss->valid) {
297                 pthread_mutex_lock(&g_ws_server_mutex);
298                 std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
299                 messages.push(message);
300                 pthread_mutex_unlock(&g_ws_server_mutex);
301
302                 ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE));
303
304                 /* If we received reply message, let's send signal to wake up our main thread */
305                 if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
306                     pthread_mutex_lock(&g_ws_query_mutex);
307                     pthread_cond_signal(&g_ws_query_condition);
308                     pthread_mutex_unlock(&g_ws_query_mutex);
309                 }
310             } else {
311                 LOGD("Ignoring data received since client is not valid %d", pss->session_id);
312             }
313         }
314
315         break;
316     default:
317         break;
318     }
319
320     return 0;
321 }
322
323 void *process_ws_server(void *data)
324 {
325     while (!force_exit && !g_ws_server_exit) {
326         struct timeval tv;
327         gettimeofday(&tv, NULL);
328
329         if (g_ws_server_context) {
330             lws_service(g_ws_server_context, 50);
331         } else {
332             LOGD("WARNING : g_ws_server_context is NULL");
333         }
334     }
335     return NULL;
336 }
337
338 void log_func(int level, const char *line)
339 {
340     if (line) {
341         LOGD("LEVEL : %d , %s", level, line);
342     }
343 }
344
345 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
346 {
347     if (m_current_instance != NULL) {
348         LOGD("WARNING : m_current_instance is NOT NULL");
349     }
350     m_current_instance = this;
351     m_message_pipe = NULL;
352     m_initialized = false;
353 }
354
355 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
356 {
357     if (m_current_instance == this) {
358         m_current_instance = NULL;
359     }
360
361     if (m_message_pipe) {
362         ecore_pipe_del(m_message_pipe);
363         m_message_pipe = NULL;
364     }
365 }
366
367 static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
368 {
369     if (buffer) {
370         if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) {
371             CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
372             if (agent) {
373                 agent->process_recved_messages();
374             }
375         } else {
376             if (g_ws_server_context) {
377                 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
378             } else {
379                 LOGD("WARNING : g_ws_server_context is NULL");
380             }
381         }
382     }
383 }
384
385 bool CWebHelperAgentWebSocket::init()
386 {
387     bool ret = true;
388
389     struct lws_context_creation_info info;
390
391     memset(&info, 0, sizeof info);
392     info.port = WEBSOCKET_PORT;
393
394     int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG;
395     lws_set_log_level(log_level, log_func);
396
397     info.iface = NULL;
398     info.protocols = protocols;
399     info.extensions = NULL;
400     info.ssl_cert_filepath = NULL;
401     info.ssl_private_key_filepath = NULL;
402     info.gid = -1;
403     info.uid = -1;
404     info.options = 0;
405
406     ecore_init();
407
408     /* The WebSocket server is running on a separate thread, and let the thread send a message
409         through this pipe to guarantee thread safety */
410     m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL);
411
412     /* Let's retry creating server context for a certain number of times */
413     const int max_retry_num = 30;
414     int retry_num = 0;
415
416     do {
417         g_ws_server_context = lws_create_context(&info);
418         LOGD("libwebsocket context : %p", g_ws_server_context);
419         usleep(100 * 1000);
420     } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
421
422     pthread_mutex_init(&g_ws_server_mutex, NULL);
423
424     pthread_mutex_init(&g_ws_query_mutex, NULL);
425     pthread_cond_init(&g_ws_query_condition, NULL);
426
427     if (g_ws_server_context) {
428         if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
429             g_ws_server_thread = (pthread_t)NULL;
430             ret = false;
431         }
432     } else {
433         LOGE("Failed creating server context : %p", g_ws_server_context);
434         ret = false;
435     }
436
437     on_init();
438
439     m_initialized = true;
440
441     test_client_connection();
442
443     return ret;
444 }
445
446 bool CWebHelperAgentWebSocket::exit()
447 {
448     on_exit();
449
450     g_ws_server_exit = true;
451
452     if (m_message_pipe) {
453         ecore_pipe_del(m_message_pipe);
454         m_message_pipe = NULL;
455     }
456
457     if (g_ws_server_thread) {
458         pthread_join(g_ws_server_thread, NULL);
459     }
460
461     pthread_cond_destroy(&g_ws_query_condition);
462     pthread_mutex_destroy(&g_ws_query_mutex);
463
464     pthread_mutex_destroy(&g_ws_server_mutex);
465
466     if (g_ws_server_context) {
467         lws_cancel_service(g_ws_server_context);
468         lws_context_destroy(g_ws_server_context);
469         g_ws_server_context = NULL;
470     }
471
472     ecore_shutdown();
473
474     return true;
475 }
476
477 void CWebHelperAgentWebSocket::signal(int sig)
478 {
479     force_exit = 1;
480 }
481
482 template<class T>
483 std::string to_string(T i)
484 {
485     std::stringstream ss;
486     std::string s;
487     ss << i;
488     s = ss.str();
489
490     return s;
491 }
492
493 void CWebHelperAgentWebSocket::on_init()
494 {
495     ISE_MESSAGE message;
496     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
497     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
498
499     pthread_mutex_lock(&g_ws_server_mutex);
500     m_send_message_queue.push(message);
501     pthread_mutex_unlock(&g_ws_server_mutex);
502
503     if (g_ws_server_context) {
504         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
505     } else {
506         LOGD("WARNING : g_ws_server_context is NULL");
507     }
508 }
509
510 void CWebHelperAgentWebSocket::on_exit()
511 {
512     ISE_MESSAGE message;
513     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
514     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
515
516     pthread_mutex_lock(&g_ws_server_mutex);
517     m_send_message_queue.push(message);
518     pthread_mutex_unlock(&g_ws_server_mutex);
519
520     if (g_ws_server_context) {
521         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
522     } else {
523         LOGD("WARNING : g_ws_server_context is NULL");
524     }
525 }
526
527 void CWebHelperAgentWebSocket::on_focus_in(int ic)
528 {
529     ISE_MESSAGE message;
530     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
531     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
532     message.values.push_back(to_string(ic));
533
534     pthread_mutex_lock(&g_ws_server_mutex);
535     m_send_message_queue.push(message);
536     pthread_mutex_unlock(&g_ws_server_mutex);
537
538     if (g_ws_server_context) {
539         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
540     } else {
541         LOGD("WARNING : g_ws_server_context is NULL");
542     }
543 }
544
545 void CWebHelperAgentWebSocket::on_focus_out(int ic)
546 {
547     ISE_MESSAGE message;
548     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
549     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
550     message.values.push_back(to_string(ic));
551
552     pthread_mutex_lock(&g_ws_server_mutex);
553     m_send_message_queue.push(message);
554     pthread_mutex_unlock(&g_ws_server_mutex);
555
556     if (g_ws_server_context) {
557         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
558     } else {
559         LOGD("WARNING : g_ws_server_context is NULL");
560     }
561 }
562
563 void CWebHelperAgentWebSocket::on_show(int ic)
564 {
565     ISE_MESSAGE message;
566     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
567     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
568     message.values.push_back(to_string(ic));
569
570     pthread_mutex_lock(&g_ws_server_mutex);
571     m_send_message_queue.push(message);
572     pthread_mutex_unlock(&g_ws_server_mutex);
573
574     if (g_ws_server_context) {
575         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
576     } else {
577         LOGD("WARNING : g_ws_server_context is NULL");
578     }
579
580     LOGD("put into send message buffer");
581 }
582
583 void CWebHelperAgentWebSocket::on_hide(int ic)
584 {
585     ISE_MESSAGE message;
586     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
587     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
588     message.values.push_back(to_string(ic));
589
590     pthread_mutex_lock(&g_ws_server_mutex);
591     m_send_message_queue.push(message);
592     pthread_mutex_unlock(&g_ws_server_mutex);
593
594     if (g_ws_server_context) {
595         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
596     } else {
597         LOGD("WARNING : g_ws_server_context is NULL");
598     }
599 }
600
601 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
602 {
603     ISE_MESSAGE message;
604     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
605     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
606     message.values.push_back(to_string(degree));
607
608     pthread_mutex_lock(&g_ws_server_mutex);
609     m_send_message_queue.push(message);
610     pthread_mutex_unlock(&g_ws_server_mutex);
611
612     if (g_ws_server_context) {
613         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
614     } else {
615         LOGD("WARNING : g_ws_server_context is NULL");
616     }
617 }
618
619 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
620 {
621     ISE_MESSAGE message;
622     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
623     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
624     message.values.push_back(to_string(ic));
625     message.values.push_back(to_string(cursor_pos));
626
627     pthread_mutex_lock(&g_ws_server_mutex);
628     m_send_message_queue.push(message);
629     pthread_mutex_unlock(&g_ws_server_mutex);
630
631     if (g_ws_server_context) {
632         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
633     } else {
634         LOGD("WARNING : g_ws_server_context is NULL");
635     }
636 }
637
638 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
639 {
640     ISE_MESSAGE message;
641     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
642     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
643     message.values.push_back(to_string(cursor));
644     message.values.push_back(text);
645
646     pthread_mutex_lock(&g_ws_server_mutex);
647     m_send_message_queue.push(message);
648     pthread_mutex_unlock(&g_ws_server_mutex);
649
650     if (g_ws_server_context) {
651         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
652     } else {
653         LOGD("WARNING : g_ws_server_context is NULL");
654     }
655 }
656
657 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
658 {
659     ISE_MESSAGE message;
660     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
661     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
662     message.values.push_back(text);
663
664     pthread_mutex_lock(&g_ws_server_mutex);
665     m_send_message_queue.push(message);
666     pthread_mutex_unlock(&g_ws_server_mutex);
667
668     if (g_ws_server_context) {
669         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
670     } else {
671         LOGD("WARNING : g_ws_server_context is NULL");
672     }
673 }
674
675 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
676 {
677     ISE_MESSAGE message;
678     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
679     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
680
681     bool found = false;
682     for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
683         if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
684             message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
685             found = true;
686         }
687     }
688
689     if (found) {
690         pthread_mutex_lock(&g_ws_server_mutex);
691         m_send_message_queue.push(message);
692         pthread_mutex_unlock(&g_ws_server_mutex);
693
694         if (g_ws_server_context) {
695             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
696         } else {
697             LOGD("WARNING : g_ws_server_context is NULL");
698         }
699     }
700 }
701
702 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
703 {
704     ISE_MESSAGE message;
705     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
706     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
707     message.values.push_back(buf);
708
709     pthread_mutex_lock(&g_ws_server_mutex);
710     m_send_message_queue.push(message);
711     pthread_mutex_unlock(&g_ws_server_mutex);
712
713     if (g_ws_server_context) {
714         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
715     } else {
716         LOGD("WARNING : g_ws_server_context is NULL");
717     }
718 }
719
720 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
721 {
722     ISE_MESSAGE message;
723     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
724     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
725
726     pthread_mutex_lock(&g_ws_server_mutex);
727     m_send_message_queue.push(message);
728     pthread_mutex_unlock(&g_ws_server_mutex);
729
730     if (g_ws_server_context) {
731         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
732     } else {
733         LOGD("WARNING : g_ws_server_context is NULL");
734     }
735
736     wait_for_reply_message();
737
738     std::vector<std::string> values;
739     /* Check if we received reply for GET_IMDATA message */
740     if (process_recved_messages_until_reply_found(
741         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
742             if (values.size() > 0 && buf && len) {
743                 int string_length = values.at(0).length();
744                 (*buf) = new char[string_length + 1];
745                 if (*buf) {
746                     strncpy(*buf, values.at(0).c_str(), string_length);
747                     /* Make sure this is a null-terminated string */
748                     *(*buf + string_length) = '\0';
749                     *len = string_length;
750                 }
751             }
752     } else {
753         LOGD("process_recved_messages_until_reply_found returned FALSE");
754     }
755     /* Now process the rest in the recv buffer */
756     process_recved_messages();
757 }
758
759 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
760 {
761     ISE_MESSAGE message;
762     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
763     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
764
765     bool found = false;
766     for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
767         if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
768             message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
769             found = true;
770         }
771     }
772
773     if (found) {
774         pthread_mutex_lock(&g_ws_server_mutex);
775         m_send_message_queue.push(message);
776         pthread_mutex_unlock(&g_ws_server_mutex);
777
778         if (g_ws_server_context) {
779             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
780         } else {
781             LOGD("WARNING : g_ws_server_context is NULL");
782         }
783     }
784 }
785
786 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
787 {
788     ISE_MESSAGE message;
789     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
790     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
791
792     pthread_mutex_lock(&g_ws_server_mutex);
793     m_send_message_queue.push(message);
794     pthread_mutex_unlock(&g_ws_server_mutex);
795
796     if (g_ws_server_context) {
797         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
798     } else {
799         LOGD("WARNING : g_ws_server_context is NULL");
800     }
801
802     wait_for_reply_message();
803
804     std::vector<std::string> values;
805     /* Check if we received reply for GET_RETURN_KEY_TYPE message */
806     if (process_recved_messages_until_reply_found(
807         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
808             if (type) {
809                 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
810                     if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
811                         *type = ISE_RETURN_KEY_TYPES[loop].type_value;
812                     }
813                 }
814             }
815     }
816     /* Now process the rest in the recv buffer */
817     process_recved_messages();
818 }
819
820 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
821 {
822     ISE_MESSAGE message;
823     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
824     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
825
826     bool found = false;
827     for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
828         if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
829             message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
830             found = true;
831         }
832     }
833
834     if (found) {
835         pthread_mutex_lock(&g_ws_server_mutex);
836         m_send_message_queue.push(message);
837         pthread_mutex_unlock(&g_ws_server_mutex);
838
839         if (g_ws_server_context) {
840             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
841         } else {
842             LOGD("WARNING : g_ws_server_context is NULL");
843         }
844     }
845 }
846
847 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
848 {
849     ISE_MESSAGE message;
850     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
851     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
852
853     pthread_mutex_lock(&g_ws_server_mutex);
854     m_send_message_queue.push(message);
855     pthread_mutex_unlock(&g_ws_server_mutex);
856
857     if (g_ws_server_context) {
858         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
859     } else {
860         LOGD("WARNING : g_ws_server_context is NULL");
861     }
862
863     wait_for_reply_message();
864
865     std::vector<std::string> values;
866     /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
867     if (process_recved_messages_until_reply_found(
868         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
869             if (disabled) {
870                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
871                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
872                         *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
873                     }
874                 }
875             }
876     }
877     /* Now process the rest in the recv buffer */
878     process_recved_messages();
879 }
880
881 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
882 {
883     ISE_MESSAGE message;
884     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
885     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
886
887     bool found = false;
888     for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
889         if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
890             message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
891             found = true;
892         }
893     }
894
895     if (found) {
896         pthread_mutex_lock(&g_ws_server_mutex);
897         m_send_message_queue.push(message);
898         pthread_mutex_unlock(&g_ws_server_mutex);
899
900         if (g_ws_server_context) {
901             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
902         } else {
903             LOGD("WARNING : g_ws_server_context is NULL");
904         }
905     }
906 }
907
908 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
909 {
910     ISE_MESSAGE message;
911     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
912     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
913
914     pthread_mutex_lock(&g_ws_server_mutex);
915     m_send_message_queue.push(message);
916     pthread_mutex_unlock(&g_ws_server_mutex);
917
918     if (g_ws_server_context) {
919         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
920     } else {
921         LOGD("WARNING : g_ws_server_context is NULL");
922     }
923
924     wait_for_reply_message();
925
926     std::vector<std::string> values;
927     /* Check if we received reply for GET_LAYOUT message */
928     if (process_recved_messages_until_reply_found(
929         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
930             if (layout) {
931                 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
932                     if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
933                         *layout = ISE_LAYOUT_TYPES[loop].type_value;
934                     }
935                 }
936             }
937     }
938     /* Now process the rest in the recv buffer */
939     process_recved_messages();
940 }
941
942 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
943 {
944     ISE_MESSAGE message;
945     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
946     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
947     message.values.push_back(to_string(ic));
948
949     pthread_mutex_lock(&g_ws_server_mutex);
950     m_send_message_queue.push(message);
951     pthread_mutex_unlock(&g_ws_server_mutex);
952
953     if (g_ws_server_context) {
954         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
955     } else {
956         LOGD("WARNING : g_ws_server_context is NULL");
957     }
958 }
959
960 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
961 {
962     ISE_MESSAGE message;
963     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
964     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
965     message.values.push_back(to_string(code));
966     message.values.push_back(to_string(mask));
967     message.values.push_back(to_string(layout));
968
969     pthread_mutex_lock(&g_ws_server_mutex);
970     m_send_message_queue.push(message);
971     pthread_mutex_unlock(&g_ws_server_mutex);
972
973     if (g_ws_server_context) {
974         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
975     } else {
976         LOGD("WARNING : g_ws_server_context is NULL");
977     }
978
979     wait_for_reply_message();
980
981     std::vector<std::string> values;
982     /* Check if we received reply for PROCESS_KEY_EVENT message */
983     if (process_recved_messages_until_reply_found(
984         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
985             if (ret) {
986                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
987                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
988                         *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
989                     }
990                 }
991             }
992     }
993     /* Now process the rest in the recv buffer */
994     process_recved_messages();
995 }
996
997 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
998 {
999     return m_current_instance;
1000 }
1001
1002 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
1003 {
1004     return m_send_message_queue;
1005 }
1006
1007 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
1008 {
1009     return m_recv_message_queue;
1010 }
1011
1012 Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe()
1013 {
1014     return m_message_pipe;
1015 }
1016
1017 void CWebHelperAgentWebSocket::wait_for_reply_message()
1018 {
1019     /* Let's wait for at most REPLY_TIMEOUT */
1020     struct timeval now;
1021     struct timespec timeout;
1022     gettimeofday(&now, NULL);
1023     timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
1024     timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
1025     pthread_mutex_lock(&g_ws_query_mutex);
1026     pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
1027     pthread_mutex_unlock(&g_ws_query_mutex);
1028 }
1029
1030 void CWebHelperAgentWebSocket::process_recved_messages()
1031 {
1032     pthread_mutex_lock(&g_ws_server_mutex);
1033
1034     while (m_recv_message_queue.size() > 0) {
1035         ISE_MESSAGE &message = m_recv_message_queue.front();
1036
1037         handle_recved_message(message);
1038
1039         m_recv_message_queue.pop();
1040     }
1041
1042     pthread_mutex_unlock(&g_ws_server_mutex);
1043 }
1044
1045 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
1046 {
1047     bool ret = false;
1048
1049     pthread_mutex_lock(&g_ws_server_mutex);
1050
1051     while (ret == false && m_recv_message_queue.size() > 0) {
1052         ISE_MESSAGE &message = m_recv_message_queue.front();
1053
1054         if (message.command.compare(command) == 0 &&
1055             message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
1056             ret = true;
1057             values = message.values;
1058         }
1059         handle_recved_message(message);
1060
1061         m_recv_message_queue.pop();
1062     }
1063
1064     pthread_mutex_unlock(&g_ws_server_mutex);
1065
1066     return ret;
1067 }
1068
1069 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
1070 {
1071     if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
1072         std::string str = "";
1073         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1074             str += message.values.at(loop).c_str();
1075             if (loop < message.values.size() - 1) {
1076                 str += " ";
1077             }
1078         }
1079         log(str.c_str());
1080     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
1081         send_key_event(0xff6b, 0); // Temporarily reset keyboard engine
1082
1083         std::string str = "";
1084         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1085             str += message.values.at(loop).c_str();
1086             if (loop < message.values.size() - 1) {
1087                 str += " ";
1088             }
1089         }
1090         commit_string(str.c_str());
1091     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
1092         std::string str = "";
1093         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1094             str += message.values.at(loop).c_str();
1095             if (loop < message.values.size() - 1) {
1096                 str += " ";
1097             }
1098         }
1099         update_preedit_string(str.c_str());
1100     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1101         if (message.values.size() == 1) {
1102             send_key_event(atoi(message.values.at(0).c_str()), 0);
1103         }
1104     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1105         LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1106         int portrait_width, portrait_height;
1107         int landscape_width, landscape_height;
1108
1109         if (message.values.size() == 4 || message.values.size() == 2) {
1110             portrait_width = atoi(message.values.at(0).c_str());
1111             portrait_height = atoi(message.values.at(1).c_str());
1112             if (message.values.size() == 2) {
1113                 landscape_width = portrait_width;
1114                 landscape_height = portrait_height;
1115             } else {
1116                 landscape_width = atoi(message.values.at(2).c_str());
1117                 landscape_height = atoi(message.values.at(3).c_str());
1118             }
1119
1120             LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1121                 portrait_width, portrait_height, landscape_width, landscape_height);
1122             set_keyboard_sizes(
1123                 portrait_width, portrait_height, landscape_width, landscape_height);
1124         }
1125     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1126         LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1127         if (message.values.size() == 2) {
1128             LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1129                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1130             set_selection(
1131                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1132         }
1133     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1134         if (message.values.size() == 0) {
1135             get_selection();
1136         }
1137     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1138         LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1139         if (message.values.size() == 2) {
1140             LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1141                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1142             get_surrounding_text(
1143                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1144         }
1145     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1146         LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1147         if (message.values.size() == 2) {
1148             LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1149                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1150             delete_surrounding_text(
1151                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1152         }
1153     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1154         if (g_ws_server_context) {
1155             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1156         } else {
1157             LOGD("WARNING : g_ws_server_context is NULL");
1158         }
1159     }
1160 }