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