b814ec3b94a415ca5d9b2b62f3c58777946afbab
[profile/ivi/isf.git] / ism / modules / imengine / scim_socket_imengine.cpp
1 /** @file scim_socket_imengine.cpp
2  * implementation of class SocketFactory and SocketInstance.
3  */
4
5 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
6
7 /*
8  * Smart Common Input Method
9  * 
10  * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
11  *
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this program; if not, write to the
25  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
26  * Boston, MA  02111-1307  USA
27  *
28  * $Id: scim_socket_imengine.cpp,v 1.21 2005/07/06 03:57:04 suzhe Exp $
29  *
30  */
31
32 #define Uses_SCIM_IMENGINE
33 #define Uses_SCIM_CONFIG_BASE
34 #define Uses_SCIM_CONFIG_PATH
35 #define Uses_SCIM_SOCKET
36 #define Uses_SCIM_TRANSACTION
37 #define Uses_C_STDLIB
38 #define Uses_SCIM_PANEL_AGENT
39
40
41 #include <string.h>
42 #include <unistd.h>
43 #include "scim_private.h"
44 #include "scim.h"
45 #include "scim_socket_imengine.h"
46 #include "scim_stl_map.h"
47 #include "isf_query_utility.h"
48
49
50 #define scim_module_init                    socket_LTX_scim_module_init
51 #define scim_module_exit                    socket_LTX_scim_module_exit
52 #define scim_imengine_module_init           socket_LTX_scim_imengine_module_init
53 #define scim_imengine_module_create_factory socket_LTX_scim_imengine_module_create_factory
54
55 #define SCIM_CONFIG_IMENGINE_SOCKET_TIMEOUT "/IMEngine/Socket/Timeout"
56 #define SCIM_CONFIG_IMENGINE_SOCKET_ADDRESS "/IMEngine/Socket/Address"
57
58 #define SCIM_SOCKET_FRONTEND_DEF_ADDRESS    "local:/tmp/scim-socket-frontend"
59
60 #ifndef SCIM_TEMPDIR
61   #define SCIM_TEMPDIR "/tmp"
62 #endif
63
64 using namespace scim;
65
66
67 class scim::SocketIMEngineGlobal
68 {
69 #if SCIM_USE_STL_EXT_HASH_MAP
70 typedef __gnu_cxx::hash_map <String, String, scim_hash_string> IconRepository;
71 #elif SCIM_USE_STL_HASH_MAP
72 typedef std::hash_map <String, String, scim_hash_string> IconRepository;
73 #else
74 typedef std::map <String, String> IconRepository;
75 #endif
76
77     SocketClient             m_socket_client;
78     SocketAddress            m_socket_address;
79     uint32                   m_socket_magic_key;
80     int                      m_socket_timeout;
81
82     std::vector<String>      m_peer_factories;
83
84     IconRepository           m_icon_repository;
85
86     Signal0<void>            m_signal_reconnect;
87
88 public:
89     SocketIMEngineGlobal ();
90     ~SocketIMEngineGlobal ();
91
92     bool            create_connection ();
93     unsigned int    number_of_factories ();
94     SocketFactory * create_factory (unsigned int index);
95
96     void            init_transaction (Transaction &trans);
97     bool            send_transaction (Transaction &trans);
98     bool            receive_transaction (Transaction &trans);
99
100     void            get_ise_info_map (const char *filename);
101     String          load_icon (const String &icon);
102
103     Connection      connect_reconnect_signal (Slot0<void> *slot_reconnect);
104
105 private:
106     void            init ();
107     void            destroy ();
108
109     void            destroy_all_icons ();
110 };
111
112 static SocketIMEngineGlobal *global = 0;
113 static std::map<String, ISEINFO> ise_info_repository;
114
115 extern "C" {
116     void scim_module_init (void)
117     {
118         if (!global)
119             global = new SocketIMEngineGlobal;
120     }
121
122     void scim_module_exit (void)
123     {
124         if (global) {
125             delete global;
126             global = 0;
127         }
128     }
129
130     unsigned int scim_imengine_module_init (const ConfigPointer &config)
131     {
132         if (global)
133             return global->number_of_factories ();
134         return 0;
135     }
136
137     IMEngineFactoryPointer scim_imengine_module_create_factory (unsigned int index)
138     {
139         if (!global)
140             return 0;
141
142         SocketFactory *sf = global->create_factory (index);
143
144         if (!sf || !sf->valid ()) {
145             delete sf;
146             sf = 0;
147         }
148
149         return sf;
150     }
151 }
152
153 namespace scim {
154
155 SocketIMEngineGlobal::SocketIMEngineGlobal ()
156     : m_socket_magic_key (0),
157       m_socket_timeout (-1)
158 {
159     init ();
160 }
161
162 SocketIMEngineGlobal::~SocketIMEngineGlobal ()
163 {
164     destroy ();
165 }
166
167 void
168 SocketIMEngineGlobal::init ()
169 {
170     SCIM_DEBUG_IMENGINE(1) << "Init SocketIMEngine Global.\n";
171
172     String address = scim_get_default_socket_imengine_address ();
173
174     m_socket_timeout = scim_get_default_socket_timeout ();
175     m_socket_address.set_address (address);
176
177     if (!m_socket_address.valid ())
178         return;
179
180     // Connect to SocketFrontEnd.
181     if (!create_connection ()) {
182         SCIM_DEBUG_IMENGINE(2) << " Cannot connect to SocketFrontEnd (" << address << ").\n";
183         return;
184     }
185
186     SCIM_DEBUG_IMENGINE(2) << " Connected to SocketFrontEnd (" << address
187                          << ") MagicKey (" << m_socket_magic_key << ").\n";
188
189     // Get IMEngineFactory list.
190     String user_file_name = String (USER_ENGINE_FILE_NAME);
191
192     ise_info_repository.clear ();
193     m_peer_factories.clear ();
194     get_ise_info_map (user_file_name.c_str ());
195 }
196
197 bool
198 SocketIMEngineGlobal::create_connection ()
199 {
200     SCIM_DEBUG_IMENGINE(1) << __FUNCTION__ << "...\n";
201
202     // Connect to SocketFrontEnd.
203     if (!m_socket_client.connect (m_socket_address))
204         return false;
205
206     if (!scim_socket_open_connection (m_socket_magic_key,
207                                       String ("SocketIMEngine"),
208                                       String ("SocketFrontEnd"),
209                                       m_socket_client,
210                                       m_socket_timeout)) {
211         m_socket_client.close ();
212         return false;
213     }
214
215     m_signal_reconnect.emit ();
216
217     return true;
218 }
219
220 void
221 SocketIMEngineGlobal::destroy ()
222 {
223     SCIM_DEBUG_IMENGINE(1) << "Destroy SocketIMEngine Global.\n";
224
225     m_socket_client.close ();
226
227     destroy_all_icons ();
228 }
229
230 unsigned int
231 SocketIMEngineGlobal::number_of_factories ()
232 {
233     return m_peer_factories.size ();
234 }
235
236 SocketFactory *
237 SocketIMEngineGlobal::create_factory (unsigned int index)
238 {
239     if (index < m_peer_factories.size ()) {
240         return new SocketFactory (m_peer_factories [index]);
241     }
242     return 0;
243 }
244
245 void
246 SocketIMEngineGlobal::init_transaction (Transaction &trans)
247 {
248     trans.clear ();
249     trans.put_command (SCIM_TRANS_CMD_REQUEST);
250     trans.put_data (m_socket_magic_key);
251 }
252
253 bool
254 SocketIMEngineGlobal::send_transaction (Transaction &trans)
255 {
256     return trans.write_to_socket (m_socket_client);
257 }
258
259 bool
260 SocketIMEngineGlobal::receive_transaction (Transaction &trans)
261 {
262     return trans.read_from_socket (m_socket_client, m_socket_timeout);
263 }
264
265 void
266 SocketIMEngineGlobal::get_ise_info_map (const char *filename)
267 {
268     FILE *engine_list_file = fopen (filename, "r");
269     if (engine_list_file == NULL) {
270         std::cerr << "failed to open " << filename << "\n";
271         return;
272     }
273
274     char buf[MAXLINE];
275
276     while (fgets (buf, MAXLINE, engine_list_file) != NULL && strlen (buf) > 0) {
277         ISEINFO info;
278         isf_get_ise_info_from_string (buf, info);
279
280         if (info.mode == TOOLBAR_KEYBOARD_MODE) {
281             m_peer_factories.push_back (info.uuid);
282             ise_info_repository[info.uuid] = info;
283         }
284     }
285
286     fclose (engine_list_file);
287     return;
288 }
289
290 String
291 SocketIMEngineGlobal::load_icon (const String &icon)
292 {
293     String local_icon = icon;
294
295     IconRepository::const_iterator it = m_icon_repository.find (icon);
296
297     // The icon has been loaded, just return the local copy filename.
298     if (it != m_icon_repository.end ())
299         local_icon = it->second;
300
301     // This icon is already available in local system, just return.
302     if (scim_load_file (local_icon, 0) != 0)
303         return local_icon;
304
305     Transaction trans;
306     int cmd;
307     char *bufptr = 0;
308     size_t filesize = 0;
309
310     local_icon = String ("");
311
312     init_transaction (trans);
313     trans.put_command (SCIM_TRANS_CMD_LOAD_FILE);
314     trans.put_data (icon);
315
316     // Load icon file from remote SocketFrontEnd.
317     if (send_transaction (trans) && receive_transaction (trans) &&
318         trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REPLY &&
319         trans.get_data (&bufptr, filesize) &&
320         trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_OK) {
321
322         String tempfile;
323         String::size_type pos = icon.rfind (SCIM_PATH_DELIM);
324
325         if (pos != String::npos) {
326             tempfile = icon.substr (pos + 1, String::npos);
327         } else {
328             tempfile = icon;
329         }
330
331         char tmp [80];
332         snprintf (tmp, 80, "%lu", (unsigned long) m_socket_magic_key);
333
334         tempfile = String (SCIM_TEMPDIR) + String (SCIM_PATH_DELIM_STRING) +
335                    String ("scim-") + String (tmp) + String ("-") +
336                    tempfile;
337
338         SCIM_DEBUG_IMENGINE(1) << "Creating temporary icon file: " << tempfile << "\n";
339
340         std::ofstream os (tempfile.c_str ());
341
342         if (os) {
343             os.write (bufptr, filesize);
344             os.close ();
345
346             // Check if the file is written correctly.
347             if (scim_load_file (tempfile, 0) == filesize) {
348                 m_icon_repository [icon] = tempfile;
349                 local_icon = tempfile;
350             } else {
351                 unlink (tempfile.c_str ());
352             }
353         }
354     }
355
356     delete [] bufptr;
357
358     return local_icon;
359 }
360
361 Connection
362 SocketIMEngineGlobal::connect_reconnect_signal (Slot0<void> *slot_reconnect)
363 {
364     return m_signal_reconnect.connect (slot_reconnect);
365 }
366
367 void
368 SocketIMEngineGlobal::destroy_all_icons ()
369 {
370     IconRepository::const_iterator it = m_icon_repository.begin ();
371
372     for (; it != m_icon_repository.end (); ++ it) {
373         unlink (it->second.c_str ());
374     }
375
376     m_icon_repository.clear ();
377 }
378
379 int
380 SocketFactory::create_peer_instance (const String &encoding)
381 {
382     int cmd;
383     int si_peer_id = -1;
384     uint32 val;
385     Transaction trans;
386
387     SCIM_DEBUG_IMENGINE(1) << "Create IMEngine Instance " << m_peer_uuid << ".\n";
388
389     global->init_transaction (trans);
390     trans.put_command (SCIM_TRANS_CMD_NEW_INSTANCE);
391     trans.put_data (m_peer_uuid);
392     trans.put_data (encoding);
393     if (global->send_transaction (trans)) {
394         if (global->receive_transaction (trans) &&
395             trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REPLY &&
396             trans.get_data (val) &&
397             trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_OK) {
398
399             si_peer_id = (int) val;
400         }
401     }
402
403     SCIM_DEBUG_IMENGINE(2) << " IMEngineInstance created (" << si_peer_id << ")\n";
404
405     return si_peer_id;
406 }
407
408 SocketFactory::SocketFactory (const String &peer_uuid)
409     : m_name (utf8_mbstowcs (_("Unknown"))),
410       m_language (String ("")),
411       m_peer_uuid (peer_uuid),
412       m_icon_file (String ("")),
413       m_ok (false)
414 {
415     String locales;
416     String iconfile;
417     Transaction trans;
418
419     SCIM_DEBUG_IMENGINE(1) << "Create SocketFactory " << peer_uuid << ".\n";
420
421     // Get factory name, locales, language and icon file.
422     std::map<String, ISEINFO>::iterator iter;
423     iter = ise_info_repository.find (m_peer_uuid);
424     if (iter != ise_info_repository.end ()) {
425         m_name = utf8_mbstowcs (iter->second.name);
426         set_locales (iter->second.locales);
427         m_language = iter->second.language;
428         //m_icon_file = global->load_icon (iter->second.icon);
429         m_ok = true;
430     } else {
431         m_language.clear ();
432     }
433 }
434
435 SocketFactory::~SocketFactory ()
436 {
437 }
438
439 WideString
440 SocketFactory::get_name () const
441 {
442     return m_name;
443 }
444
445 WideString
446 SocketFactory::get_authors () const
447 {
448     int cmd;
449     WideString authors;
450     Transaction trans;
451
452     SCIM_DEBUG_IMENGINE(1) << "Get Authors " << m_peer_uuid << ".\n";
453
454     // Get factory authors.
455     for (int retry = 0; retry < 3; ++retry) {
456         global->init_transaction (trans);
457         trans.put_command (SCIM_TRANS_CMD_GET_FACTORY_AUTHORS);
458         trans.put_data (m_peer_uuid);
459
460         if (global->send_transaction (trans) && global->receive_transaction (trans) &&
461             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_REPLY &&
462             trans.get_data (authors) &&
463             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_OK)
464             break;
465
466         authors = utf8_mbstowcs (_("Unknown"));
467
468         if (!global->create_connection ())
469             break;
470     }
471
472     return authors;
473 }
474
475 WideString
476 SocketFactory::get_credits () const
477 {
478     int cmd;
479     WideString credits;
480     Transaction trans;
481
482     SCIM_DEBUG_IMENGINE(1) << "Get Credits " << m_peer_uuid << ".\n";
483
484     // Get factory credits.
485     for (int retry = 0; retry < 3; ++retry) {
486         global->init_transaction (trans);
487         trans.put_command (SCIM_TRANS_CMD_GET_FACTORY_CREDITS);
488         trans.put_data (m_peer_uuid);
489
490         if (global->send_transaction (trans) && global->receive_transaction (trans) &&
491             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_REPLY &&
492             trans.get_data (credits) &&
493             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_OK)
494             break;
495
496         credits = utf8_mbstowcs (_("Unknown"));
497
498         if (!global->create_connection ())
499             break;
500     }
501
502     return credits;
503 }
504
505 WideString
506 SocketFactory::get_help () const
507 {
508     int cmd;
509     WideString help;
510     Transaction trans;
511
512     SCIM_DEBUG_IMENGINE(1) << "Get Help " << m_peer_uuid << ".\n";
513
514     // Get factory help.
515     for (int retry = 0; retry < 3; ++retry) {
516         global->init_transaction (trans);
517         trans.put_command (SCIM_TRANS_CMD_GET_FACTORY_HELP);
518         trans.put_data (m_peer_uuid);
519
520         if (global->send_transaction (trans) && global->receive_transaction (trans) &&
521             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_REPLY &&
522             trans.get_data (help)    &&
523             trans.get_command (cmd)  && cmd == SCIM_TRANS_CMD_OK)
524             break;
525
526         help = utf8_mbstowcs (_("Unknown"));
527
528         if (!global->create_connection ())
529             break;
530     }
531
532     return help;
533 }
534
535 String
536 SocketFactory::get_uuid () const
537 {
538     return m_peer_uuid;
539 }
540
541 String
542 SocketFactory::get_icon_file () const
543 {
544     return m_icon_file;
545 }
546
547 String
548 SocketFactory::get_language () const
549 {
550     if (m_language.length ())
551         return m_language;
552     else
553         return IMEngineFactoryBase::get_language ();
554 }
555
556 IMEngineInstancePointer
557 SocketFactory::create_instance (const String& encoding, int id)
558 {
559     int si_peer_id = create_peer_instance (encoding);
560
561     SCIM_DEBUG_IMENGINE(2) << " IMEngineInstance created (" << si_peer_id << ")\n";
562
563     return new SocketInstance (this, encoding, id, si_peer_id);
564 }
565
566 SocketInstance::SocketInstance (SocketFactory *factory,
567                                 const String& encoding,
568                                 int           id,
569                                 int           peer_id)
570     : IMEngineInstanceBase (factory, encoding, id),
571       m_factory (factory),
572       m_peer_id (peer_id)
573 {
574     m_signal_reconnect_connection = global->connect_reconnect_signal (slot (this, &SocketInstance::reconnect_callback));
575 }
576
577 SocketInstance::~SocketInstance ()
578 {
579     Transaction trans;
580
581     SCIM_DEBUG_IMENGINE(1) << "Destroy IMEngine Instance " << m_peer_id << ".\n";
582
583     m_signal_reconnect_connection.disconnect ();
584
585     if (m_peer_id >= 0) {
586         global->init_transaction (trans);
587
588         trans.put_command (SCIM_TRANS_CMD_DELETE_INSTANCE);
589         trans.put_data (m_peer_id);
590
591         commit_transaction (trans);
592     }
593 }
594
595 bool
596 SocketInstance::process_key_event (const KeyEvent& key)
597 {
598     Transaction trans;
599
600     global->init_transaction (trans);
601
602     SCIM_DEBUG_IMENGINE(1) << "process_key_event (" << m_peer_id << ")\n";
603
604     trans.put_command (SCIM_TRANS_CMD_PROCESS_KEY_EVENT);
605     trans.put_data (m_peer_id);
606     trans.put_data (key);
607
608     return commit_transaction (trans);
609 }
610
611 void
612 SocketInstance::move_preedit_caret (unsigned int pos)
613 {
614     Transaction trans;
615
616     global->init_transaction (trans);
617
618     SCIM_DEBUG_IMENGINE(1) << "move_preedit_caret (" << m_peer_id << ")\n";
619
620     trans.put_command (SCIM_TRANS_CMD_MOVE_PREEDIT_CARET);
621     trans.put_data (m_peer_id);
622     trans.put_data ((uint32) pos);
623
624     commit_transaction (trans);
625 }
626
627 void
628 SocketInstance::select_aux (unsigned int item)
629 {
630     Transaction trans;
631
632     global->init_transaction (trans);
633
634     SCIM_DEBUG_IMENGINE(1) << "select_aux (" << m_peer_id << ")\n";
635
636     trans.put_command (ISM_TRANS_CMD_SELECT_AUX);
637     trans.put_data (m_peer_id);
638     trans.put_data ((uint32) item);
639
640     commit_transaction (trans);
641 }
642
643 void
644 SocketInstance::select_candidate (unsigned int item)
645 {
646     Transaction trans;
647
648     global->init_transaction (trans);
649
650     SCIM_DEBUG_IMENGINE(1) << "select_candidate (" << m_peer_id << ")\n";
651
652     trans.put_command (SCIM_TRANS_CMD_SELECT_CANDIDATE);
653     trans.put_data (m_peer_id);
654     trans.put_data ((uint32) item);
655
656     commit_transaction (trans);
657 }
658
659 void
660 SocketInstance::update_lookup_table_page_size (unsigned int page_size)
661 {
662     Transaction trans;
663
664     global->init_transaction (trans);
665
666     SCIM_DEBUG_IMENGINE(1) << "update_lookup_table_page_size (" << m_peer_id << ")\n";
667
668     trans.put_command (SCIM_TRANS_CMD_UPDATE_LOOKUP_TABLE_PAGE_SIZE);
669     trans.put_data (m_peer_id);
670     trans.put_data ((uint32) page_size);
671
672     commit_transaction (trans);
673 }
674
675 void
676 SocketInstance::lookup_table_page_up ()
677 {
678     Transaction trans;
679
680     global->init_transaction (trans);
681
682     SCIM_DEBUG_IMENGINE(1) << "lookup_table_page_up (" << m_peer_id << ")\n";
683
684     trans.put_command (SCIM_TRANS_CMD_LOOKUP_TABLE_PAGE_UP);
685     trans.put_data (m_peer_id);
686
687     commit_transaction (trans);
688 }
689
690 void
691 SocketInstance::lookup_table_page_down ()
692 {
693     Transaction trans;
694
695     global->init_transaction (trans);
696
697     SCIM_DEBUG_IMENGINE(1) << "lookup_table_page_up (" << m_peer_id << ")\n";
698
699     trans.put_command (SCIM_TRANS_CMD_LOOKUP_TABLE_PAGE_DOWN);
700     trans.put_data (m_peer_id);
701
702     commit_transaction (trans);
703 }
704
705 void
706 SocketInstance::reset_option ()
707 {
708     Transaction trans;
709
710     global->init_transaction (trans);
711
712     SCIM_DEBUG_IMENGINE(1) << "reset_option (" << m_peer_id << ")\n";
713
714     trans.put_command (ISM_TRANS_CMD_RESET_ISE_OPTION);
715     trans.put_data (m_peer_id);
716
717     commit_transaction (trans);
718 }
719
720 void
721 SocketInstance::reset ()
722 {
723     Transaction trans;
724
725     global->init_transaction (trans);
726
727     SCIM_DEBUG_IMENGINE(1) << "reset (" << m_peer_id << ")\n";
728
729     trans.put_command (SCIM_TRANS_CMD_RESET);
730     trans.put_data (m_peer_id);
731
732     commit_transaction (trans);
733 }
734
735 void
736 SocketInstance::focus_in ()
737 {
738     Transaction trans;
739
740     global->init_transaction (trans);
741
742     SCIM_DEBUG_IMENGINE(1) << "focus_in (" << m_peer_id << ")\n";
743
744     trans.put_command (SCIM_TRANS_CMD_FOCUS_IN);
745     trans.put_data (m_peer_id);
746
747     commit_transaction (trans);
748 }
749
750 void
751 SocketInstance::focus_out ()
752 {
753     Transaction trans;
754
755     global->init_transaction (trans);
756
757     SCIM_DEBUG_IMENGINE(1) << "focus_out (" << m_peer_id << ")\n";
758
759     trans.put_command (SCIM_TRANS_CMD_FOCUS_OUT);
760     trans.put_data (m_peer_id);
761
762     commit_transaction (trans);
763 }
764
765 void
766 SocketInstance::trigger_property (const String &property)
767 {
768     Transaction trans;
769
770     global->init_transaction (trans);
771
772     SCIM_DEBUG_IMENGINE(1) << "trigger_property (" << m_peer_id << ", " << property << ")\n";
773
774     trans.put_command (SCIM_TRANS_CMD_TRIGGER_PROPERTY);
775     trans.put_data (m_peer_id);
776     trans.put_data (property);
777
778     commit_transaction (trans);
779 }
780
781 void
782 SocketInstance::process_helper_event (const String &helper_uuid, const Transaction &helper_trans)
783 {
784     Transaction trans;
785
786     global->init_transaction (trans);
787
788     SCIM_DEBUG_IMENGINE(1) << "process_helper_event (" << m_peer_id << ", " << helper_uuid << ")\n";
789
790     trans.put_command (SCIM_TRANS_CMD_PROCESS_HELPER_EVENT);
791     trans.put_data (m_peer_id);
792     trans.put_data (helper_uuid);
793     trans.put_data (helper_trans);
794
795     commit_transaction (trans);
796 }
797
798 void
799 SocketInstance::update_client_capabilities (unsigned int cap)
800 {
801     Transaction trans;
802
803     global->init_transaction (trans);
804
805     SCIM_DEBUG_IMENGINE(1) << "update_client_capabilities (" << m_peer_id << ", " << cap << ")\n";
806
807     trans.put_command (SCIM_TRANS_CMD_UPDATE_CLIENT_CAPABILITIES);
808     trans.put_data (m_peer_id);
809     trans.put_data ((uint32) cap);
810
811     commit_transaction (trans);
812 }
813
814 bool
815 SocketInstance::commit_transaction (Transaction &trans)
816 {
817     SCIM_DEBUG_IMENGINE(2) << " commit_transaction:\n";
818
819     bool ret = false;
820
821     if (m_peer_id >= 0) {
822         if (global->send_transaction (trans)) {
823             while (1) {
824                 if (!global->receive_transaction (trans)) break;
825                 if (!do_transaction (trans, ret)) return ret;
826             }
827         }
828     }
829
830     if (global->create_connection ())
831         reset ();
832
833     return ret;
834 }
835
836 bool
837 SocketInstance::do_transaction (Transaction &trans, bool &ret)
838 {
839     int cmd = -1;
840     bool cont = false;
841
842     ret = false;
843
844     SCIM_DEBUG_IMENGINE(2) << " Do transaction:\n";
845
846     if (trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REPLY) {
847         while (trans.get_command (cmd)) {
848             switch (cmd) {
849                 case SCIM_TRANS_CMD_SHOW_PREEDIT_STRING:
850                 {
851                     SCIM_DEBUG_IMENGINE(3) << "  show_preedit_string ()\n";
852                     show_preedit_string ();
853                     break;
854                 }
855                 case SCIM_TRANS_CMD_SHOW_AUX_STRING:
856                 {
857                     SCIM_DEBUG_IMENGINE(3) << "  show_aux_string ()\n";
858                     show_aux_string ();
859                     break;
860                 }
861                 case SCIM_TRANS_CMD_SHOW_LOOKUP_TABLE:
862                 {
863                     SCIM_DEBUG_IMENGINE(3) << "  show_lookup_table ()\n";
864                     show_lookup_table ();
865                     break;
866                 }
867                 case SCIM_TRANS_CMD_HIDE_PREEDIT_STRING:
868                 {
869                     SCIM_DEBUG_IMENGINE(3) << "  hide_preedit_string ()\n";
870                     hide_preedit_string ();
871                     break;
872                 }
873                 case SCIM_TRANS_CMD_HIDE_AUX_STRING:
874                 {
875                     SCIM_DEBUG_IMENGINE(3) << "  hide_aux_string ()\n";
876                     hide_aux_string ();
877                     break;
878                 }
879                 case SCIM_TRANS_CMD_HIDE_LOOKUP_TABLE:
880                 {
881                     SCIM_DEBUG_IMENGINE(3) << "  hide_lookup_table ()\n";
882                     hide_lookup_table ();
883                     break;
884                 }
885                 case SCIM_TRANS_CMD_UPDATE_PREEDIT_CARET:
886                 {
887                     uint32 caret;
888                     if (trans.get_data (caret)) {
889                         SCIM_DEBUG_IMENGINE(3) << "  update_preedit_caret (" << caret << ")\n";
890                         update_preedit_caret (caret);
891                     }
892                     break;
893                 }
894                 case SCIM_TRANS_CMD_UPDATE_PREEDIT_STRING:
895                 {
896                     WideString str;
897                     AttributeList attrs;
898                     if (trans.get_data (str) && trans.get_data (attrs)) {
899                         SCIM_DEBUG_IMENGINE(3) << "  update_preedit_string ()\n";
900                         update_preedit_string (str, attrs);
901                     }
902                     break;
903                 }
904                 case SCIM_TRANS_CMD_UPDATE_AUX_STRING:
905                 {
906                     WideString str;
907                     AttributeList attrs;
908                     if (trans.get_data (str) && trans.get_data (attrs)) {
909                         SCIM_DEBUG_IMENGINE(3) << "  update_aux_string ()\n";
910                         update_aux_string (str, attrs);
911                     }
912                     break;
913                 }
914                 case SCIM_TRANS_CMD_UPDATE_LOOKUP_TABLE:
915                 {
916                     CommonLookupTable table;
917                     if (trans.get_data (table)) {
918                         SCIM_DEBUG_IMENGINE(3) << "  update_lookup_table ()\n";
919                         update_lookup_table (table);
920                     }
921                     break;
922                 }
923                 case SCIM_TRANS_CMD_COMMIT_STRING:
924                 {
925                     WideString str;
926                     if (trans.get_data (str)) {
927                         SCIM_DEBUG_IMENGINE(3) << "  commit_string ()\n";
928                         commit_string (str);
929                     }
930                     break;
931                 }
932                 case SCIM_TRANS_CMD_FORWARD_KEY_EVENT:
933                 {
934                     KeyEvent key;
935                     if (trans.get_data (key)) {
936                         SCIM_DEBUG_IMENGINE(3) << "  forward_key_event ()\n";
937                         forward_key_event (key);
938                     }
939                     break;
940                 }
941                 case SCIM_TRANS_CMD_REGISTER_PROPERTIES:
942                 {
943                     PropertyList proplist;
944                     if (trans.get_data (proplist)) {
945                         SCIM_DEBUG_IMENGINE(3) << "  register_properties ()\n";
946
947                         // Load icon files of these properties from remote SocketFrontEnd.
948                         for (PropertyList::iterator it = proplist.begin (); it != proplist.end (); ++it)
949                             it->set_icon (global->load_icon (it->get_icon ()));
950
951                         register_properties (proplist);
952                     }
953                     break;
954                 }
955                 case SCIM_TRANS_CMD_UPDATE_PROPERTY:
956                 {
957                     Property prop;
958                     if (trans.get_data (prop)) {
959                         SCIM_DEBUG_IMENGINE(3) << "  update_property ()\n";
960
961                         // Load the icon file of this property from remote SocketFrontEnd.
962                         prop.set_icon (global->load_icon (prop.get_icon ()));
963
964                         update_property (prop);
965                     }
966                     break;
967                 }
968                 case SCIM_TRANS_CMD_BEEP:
969                 {
970                     SCIM_DEBUG_IMENGINE(3) << "  beep ()\n";
971                     beep ();
972                     break;
973                 }
974                 case SCIM_TRANS_CMD_START_HELPER:
975                 {
976                     String helper_uuid;
977                     if (trans.get_data (helper_uuid)) {
978                         SCIM_DEBUG_IMENGINE(3) << "  start_helper (" << helper_uuid << ")\n";
979                         start_helper (helper_uuid);
980                     }
981                     break; 
982                 }
983                 case SCIM_TRANS_CMD_STOP_HELPER:
984                 {
985                     String helper_uuid;
986                     if (trans.get_data (helper_uuid)) {
987                         SCIM_DEBUG_IMENGINE(3) << "  stop_helper (" << helper_uuid << ")\n";
988                         stop_helper (helper_uuid);
989                     }
990                     break; 
991                 }
992                 case SCIM_TRANS_CMD_SEND_HELPER_EVENT:
993                 {
994                     String helper_uuid;
995                     Transaction temp_trans;
996                     if (trans.get_data (helper_uuid) && trans.get_data (temp_trans)) {
997                         SCIM_DEBUG_IMENGINE(3) << "  send_helper_event (" << helper_uuid << ")\n";
998                         send_helper_event (helper_uuid, temp_trans);
999                     }
1000                     break; 
1001                 }
1002                 case SCIM_TRANS_CMD_OK:
1003                 {
1004                     SCIM_DEBUG_IMENGINE(3) << "  ret = true\n";
1005                     ret = true;
1006                     break;
1007                 }
1008                 case SCIM_TRANS_CMD_GET_SURROUNDING_TEXT:
1009                 {
1010                     WideString text;
1011                     int cursor;
1012                     uint32 maxlen_before;
1013                     uint32 maxlen_after;
1014                     Transaction temp_trans;
1015                     if (trans.get_data (maxlen_before) && trans.get_data (maxlen_after)) {
1016                         global->init_transaction (temp_trans);
1017                         if (get_surrounding_text (text, cursor, (int) maxlen_before, (int) maxlen_after)) {
1018                             temp_trans.put_command (SCIM_TRANS_CMD_GET_SURROUNDING_TEXT);
1019                             temp_trans.put_data (text);
1020                             temp_trans.put_data ((uint32) cursor);
1021                         } else {
1022                             temp_trans.put_command (SCIM_TRANS_CMD_FAIL);
1023                         }
1024                         if (!global->send_transaction (temp_trans))
1025                             std::cerr << "GET_SURROUNDING_TEXT: global->send_transaction () is failed!!!\n";
1026                     }
1027                     cont = true;
1028                     break;
1029                 }
1030                 case SCIM_TRANS_CMD_DELETE_SURROUNDING_TEXT:
1031                 {
1032                     uint32 offset;
1033                     uint32 len;
1034                     Transaction temp_trans;
1035                     if (trans.get_data (offset) && trans.get_data (len)) {
1036                         global->init_transaction (temp_trans);
1037                         if (delete_surrounding_text ((int) offset, (int) len)) {
1038                             temp_trans.put_command (SCIM_TRANS_CMD_DELETE_SURROUNDING_TEXT);
1039                             temp_trans.put_command (SCIM_TRANS_CMD_OK);
1040                         } else {
1041                             temp_trans.put_command (SCIM_TRANS_CMD_FAIL);
1042                         }
1043                         if (!global->send_transaction (temp_trans))
1044                             std::cerr << "DELETE_SURROUNDING_TEXT: global->send_transaction () is failed!!!\n";
1045                     }
1046                     cont = true;
1047                     break;
1048                 }
1049                 default:
1050                     SCIM_DEBUG_IMENGINE(3) << "  Strange cmd: " << cmd << "\n";;
1051             }
1052         }
1053     } else {
1054         SCIM_DEBUG_IMENGINE(3) << "  Failed to get cmd: " << cmd << "\n";
1055     }
1056
1057     SCIM_DEBUG_IMENGINE(2) << " End of Do transaction\n";
1058
1059     return cont;
1060 }
1061
1062 void
1063 SocketInstance::reconnect_callback (void)
1064 {
1065     m_peer_id = m_factory->create_peer_instance (get_encoding ());
1066 }
1067
1068 } // namespace scim
1069
1070 /*
1071 vi:ts=4:nowrap:ai:expandtab
1072 */