1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 /*
3  * im_iiimf.c - iiimf plugin for mlterm
4  *
5  * Copyright (C) 2004 2005 Seiichi SATO <ssato@sh.rim.or.jp>
6  *
7  */
8 
9 /*
10  * im_iiimf_process_event() is based on IMProcessIncomingEvent() of iiimxcf.
11  */
12 
13 /*
14  * Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the
18  * "Software"), to deal in the Software without restriction, including
19  * without limitation the rights to use, copy, modify, merge, publish,
20  * distribute, sublicense, and/or sell copies of the Software, and to
21  * permit persons to whom the Software is furnished to do so, subject to
22  * the following conditions: The above copyright notice and this
23  * permission notice shall be included in all copies or substantial
24  * portions of the Software.
25  *
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
30  * IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
31  * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
32  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
33  * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
34  * ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
35  *
36  *
37  * Except as contained in this notice, the names of The Open Group and/or
38  * Sun Microsystems, Inc. shall not be used in advertising or otherwise to
39  * promote the sale, use or other dealings in this Software without prior
40  * written authorization from The Open Group and/or Sun Microsystems,
41  * Inc., as applicable.
42  *
43  *
44  * X Window System is a trademark of The Open Group
45  *
46  * OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
47  * logo, LBX, X Window System, and Xinerama are trademarks of the Open
48  * Group. All other trademarks and registered trademarks mentioned herein
49  * are the property of their respective owners. No right, title or
50  * interest in or to any trademark, service mark, logo or trade name of
51  * Sun Microsystems, Inc. or its licensors is granted.
52  *
53  */
54 
55 #include <string.h>    /* strncmp */
56 #include <dirent.h>
57 #include <pobl/bl_def.h> /* WORDS_BIGENDIAN */
58 #include <pobl/bl_mem.h>  /* malloc/alloca/free */
59 #include <pobl/bl_str.h>  /* bl_str_sep/strdup/bl_snprintf */
60 #include <pobl/bl_locale.h> /* bl_get_lang */
61 #include <pobl/bl_debug.h>
62 #include <pobl/bl_util.h> /* bl_get_user_name */
63 #include <mef/ef_utf16_parser.h>
64 #include <mef/ef_iso8859_conv.h>
65 
66 #include "im_iiimf.h"
67 #include "keymap.h"
68 #include "../im_common.h"
69 #include "../im_info.h"
70 
71 #if 0
72 #define IM_IIIMF_DEBUG 1
73 #endif
74 
75 /* XXX: it seems to be undefined in iiim*.h. why? */
76 #define IIIMF_SHIFT_MODIFIER 1
77 #define IIIMF_CONTROL_MODIFIER 2
78 #define IIIMF_META_MODIFIER 4
79 #define IIIMF_ALT_MODIFIER 8
80 
81 /* --- static variables --- */
82 
83 static int ref_count = 0;
84 static int initialized = 0;
85 static ef_parser_t *  parser_utf16 = NULL;
86 static IIIMCF_handle handle = NULL;
87 /* mlterm internal symbols */
88 static ui_im_export_syms_t *  syms = NULL;
89 
90 static int htt_show_status_window = 0;
91 static int htt_generates_kanakey = 0;
92 
93 /* --- static functions --- */
94 
find_language(char * lang)95 static IIIMCF_language find_language(char *  lang) {
96   IIIMCF_language *  array;
97   IIIMCF_language best_result = NULL;
98   IIIMCF_language better_result = NULL;
99   char *  p = NULL;
100   char *  language = NULL;
101   char *  country = NULL;
102   int num;
103   int i;
104 
105   if (lang && (p = alloca(strlen(lang) + 1))) {
106     strcpy(p, lang);
107 
108     if ((country = bl_str_sep(&p, ":"))) {
109       p = country; /* hold for free() */
110       language = bl_str_sep(&country, "_");
111     }
112   }
113 
114   if (language == NULL && country == NULL) {
115     language = bl_get_lang();
116     country = bl_get_country();
117   }
118 
119   if (iiimcf_get_supported_languages(handle, &num, &array) == IIIMF_STATUS_SUCCESS) {
120     for (i = 0; i < num; i++) {
121       const char *  lang_id;
122 
123       if (iiimcf_get_language_id(array[i], &lang_id) != IIIMF_STATUS_SUCCESS) {
124         continue;
125       }
126 
127       /* At first, compare with lang_COUNTRY like "zh_CN" */
128       if (country) {
129         char buf[16];
130 
131         bl_snprintf(buf, sizeof(buf), "%s_%s", language, country);
132 
133         if (strcmp(buf, lang_id) == 0) {
134           best_result = array[i];
135         }
136       }
137 
138       /* Next, compare with lang like "ja" */
139       if (strcmp(language, lang_id) == 0) {
140         better_result = array[i];
141       }
142     }
143   }
144 
145   return (best_result ? best_result : better_result);
146 }
147 
find_language_engine(char * lang)148 static IIIMCF_input_method find_language_engine(char* lang) {
149   IIIMCF_input_method *  array;
150   IIIMCF_input_method result = NULL;
151   char *  le_name = NULL;
152   ef_conv_t *  conv;
153   int num;
154   int i;
155 
156   if (!lang) {
157     return NULL;
158   }
159 
160   if (!(le_name = strstr(lang, ":"))) {
161     return NULL;
162   }
163 
164   /* eliminate leading ":" */
165   le_name ++;
166 
167   if (!(conv = (*syms->vt_char_encoding_conv_new)(VT_ISO8859_1))) {
168     return NULL;
169   }
170 
171   if (iiimcf_get_supported_input_methods(handle, &num, &array) == IIIMF_STATUS_SUCCESS) {
172     for (i = 0; i < num; i++) {
173       const IIIMP_card16 * id;
174       const IIIMP_card16 * hrn; /* human readable name */
175       const IIIMP_card16 * domain;
176 
177       if (iiimcf_get_input_method_desc(array[i], &id, &hrn, &domain) == IIIMF_STATUS_SUCCESS) {
178         u_char *  str;
179 
180         im_convert_encoding(parser_utf16, conv, (u_char*) id, &str, strlen_utf16(id) + 1);
181 
182         if (strcmp(le_name, str) == 0) {
183 #ifdef IM_IIIMF_DEBUG
184           bl_debug_printf(BL_DEBUG_TAG " found le [%s].\n", le_name);
185 #endif
186 
187           result = array[i];
188         }
189 
190         free(str);
191       }
192     }
193   }
194 
195   (*conv->destroy)(conv);
196 
197   return result;
198 }
199 
show_iiimcf_version(void)200 static void show_iiimcf_version(void) {
201 #ifdef IM_IIIMF_DEBUG
202 #define SHOW_VER(flag, str) {                  \
203   int ver;              \
204   if (iiimcf_get_version_number(handle, (flag), &ver)    \
205             == IIIMF_STATUS_ARGUMENT) {               \
206     bl_debug_printf(BL_DEBUG_TAG "%s\t\t:%d\n", (str), ver) {               \
207     bl_debug_printf(BL_DEBUG_TAG "%s\t\t:none\n", (str));\
208   }               \
209 } while (0)
210 
211   SHOW_VER(IIIMCF_LIBRARY_VERSION, "library version");
212   SHOW_VER(IIIMCF_PROTOCOL_VERSION, "protocol version");
213   SHOW_VER(IIIMCF_MINOR_VERSION, "minor version");
214   SHOW_VER(IIIMCF_MAJOR_VERSION, "major version");
215 #endif
216 }
217 
218 /*
219  * callback for candidate screen events
220  */
221 
222 static void candidate_selected(void *p, u_int index) {
223 #ifdef IM_IIIMF_DEBUG
224   bl_debug_printf(BL_DEBUG_TAG " index : %d\n", index);
225 #endif
226 
227   /* not implemented yet. */
228 }
229 
230 
231 /*
232  * processing event from IIIMSF
233  */
234 
235 static void commit(im_iiimf_t *iiimf) {
236   IIIMCF_text iiimcf_text;
237   const IIIMP_card16  *utf16str;
238   u_char buf[256];
239   size_t filled_len;
240 
241 #ifdef IM_IIIMF_DEBUG
242   bl_debug_printf(BL_DEBUG_TAG "\n");
243 #endif
244 
245   if (iiimcf_get_committed_text(iiimf->context, &iiimcf_text) != IIIMF_STATUS_SUCCESS) {
246 #ifdef DEBUG
247     bl_warn_printf(BL_DEBUG_TAG " Could not get committed text.\n");
248 #endif
249     return;
250   }
251 
252   if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
253 #ifdef DEBUG
254     bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string.\n");
255 #endif
256     return;
257   }
258 
259   (*iiimf->im.listener->write_to_term)(iiimf->im.listener->self,
260                                        (u_char*) utf16str, strlen_utf16(utf16str),
261                                        parser_utf16);
262 }
263 
264 static void preedit_start(im_iiimf_t *iiimf) {
265 #ifdef IM_IIIMF_DEBUG
266   bl_debug_printf(BL_DEBUG_TAG "\n");
267 #endif
268 
269   if (iiimf->im.preedit.chars) {
270     (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
271   }
272 
273   iiimf->im.preedit.num_chars = 0;
274   iiimf->im.preedit.filled_len = 0;
275   iiimf->im.preedit.segment_offset = 0;
276   iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
277 }
278 
279 static void preedit_change(im_iiimf_t *iiimf) {
280   IIIMCF_text iiimcf_text;
281   const IIIMP_card16 *utf16str;
282   u_char *str;
283   vt_char_t *p;
284   ef_char_t ch;
285   int is_underline = 0;
286   int caret_pos;
287   u_int count = 0;
288   int in_reverse = 0;
289 
290 #ifdef IM_IIIMF_DEBUG
291   bl_debug_printf(BL_DEBUG_TAG "\n");
292 #endif
293 
294   /*
295    * get preedit string without attribute.
296    */
297 
298   if (iiimcf_get_preedit_text(iiimf->context, &iiimcf_text, &caret_pos) != IIIMF_STATUS_SUCCESS) {
299 #ifdef DEBUG
300     bl_warn_printf(BL_DEBUG_TAG " Could not get preedit text\n");
301 #endif
302     return;
303   }
304 
305   if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
306 #ifdef DEBUG
307     bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string\n");
308 #endif
309     return;
310   }
311 
312   if (strlen_utf16(utf16str) == 0) {
313     /* clear */
314     (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, NULL, 0, 0);
315 
316     if (iiimf->im.preedit.chars) {
317       (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
318       iiimf->im.preedit.chars = NULL;
319       iiimf->im.preedit.num_chars = 0;
320       iiimf->im.preedit.filled_len = 0;
321       iiimf->im.preedit.segment_offset = 0;
322       iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
323     }
324 
325     return ;
326   }
327 
328   /* UTF16 -> term encoding */
329   im_convert_encoding(parser_utf16, iiimf->conv, (u_char*) utf16str, &str,
330                       strlen_utf16(utf16str) + 1);
331 
332 
333   /*
334    * count number of characters to re-allocate im.preedit.chars
335    */
336 
337   (*iiimf->parser_term->init)(iiimf->parser_term);
338   (*iiimf->parser_term->set_str)(iiimf->parser_term, str, strlen(str));
339 
340   while ((*iiimf->parser_term->next_char)(iiimf->parser_term, &ch)) {
341     count ++;
342   }
343 
344 
345   /*
346    * allocate im.preedit.chars
347    */
348 
349   if (iiimf->im.preedit.chars) {
350     (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
351     iiimf->im.preedit.chars = NULL;
352     iiimf->im.preedit.num_chars = 0;
353     iiimf->im.preedit.filled_len = 0;
354     iiimf->im.preedit.segment_offset = 0;
355     iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
356   }
357 
358   if (!(iiimf->im.preedit.chars = calloc(count, sizeof(vt_char_t)))) {
359 #ifdef DEBUG
360     bl_warn_printf(BL_DEBUG_TAG "calloc failed.\n");
361 #endif
362 
363     return;
364   }
365 
366   iiimf->im.preedit.num_chars = count;
367   iiimf->im.preedit.filled_len = 0;
368 
369   (*syms->vt_str_init)(iiimf->im.preedit.chars,
370             iiimf->im.preedit.num_chars);
371 
372 
373   /*
374    * IIIMP_card16(UTF16) -> vt_char_t
375    */
376 
377   p = iiimf->im.preedit.chars;
378   (*syms->vt_str_init)(p, iiimf->im.preedit.num_chars);
379 
380   (*iiimf->parser_term->init)(iiimf->parser_term);
381   (*iiimf->parser_term->set_str)(iiimf->parser_term,
382           str, strlen(str));
383 
384   count = 0;
385 
386   /* TODO: move to inputmethod/common/im_common.c */
387   while ((*iiimf->parser_term->next_char)(iiimf->parser_term, &ch)) {
388     IIIMP_card16  iiimcf_ch;
389     const IIIMP_card32 *feedback_ids;
390     const IIIMP_card32 *feedbacks;
391     int num_feedbacks;
392     vt_color_t fg_color = VT_FG_COLOR;
393     vt_color_t bg_color = VT_BG_COLOR;
394     int is_fullwidth = 0;
395     int is_comb = 0;
396     int is_bold = 0;
397 
398     iiimf->im.preedit.cursor_offset = 0;
399 
400     if (iiimcf_get_char_with_feedback(iiimcf_text, iiimf->im.preedit.filled_len,
401                                       &iiimcf_ch, &num_feedbacks, &feedback_ids,
402                                       &feedbacks) == IIIMF_STATUS_SUCCESS) {
403       int i;
404 
405       for (i = 0; i < num_feedbacks; i++) {
406         /* IIIMP_FEEDBACK_[1,2,3...]_* don't exist? */
407         if (feedback_ids[i] != IIIMP_FEEDBACK_0_ID) {
408           continue;
409         }
410 
411         switch(feedbacks[i]) {
412         case IIIMP_FEEDBACK_0_REVERSE_VIDEO:
413           if (!in_reverse) {
414             iiimf->im.preedit.segment_offset = iiimf->im.preedit.filled_len;
415             in_reverse = 1;
416           }
417           iiimf->im.preedit.cursor_offset =
418               UI_IM_PREEDIT_NOCURSOR;
419           fg_color = VT_BG_COLOR;
420           bg_color = VT_FG_COLOR;
421           break;
422         case IIIMP_FEEDBACK_0_UNDERLINE:
423           is_underline = 1;
424           break;
425         case IIIMP_FEEDBACK_0_HIGHLIGHT:
426           is_bold = 1;
427           break;
428         case IIIMP_FEEDBACK_0_NORMAL_VIDEO:
429         case IIIMP_FEEDBACK_0_PRIMARY:
430         case IIIMP_FEEDBACK_0_SECONDARY:
431         case IIIMP_FEEDBACK_0_TERTIARY:
432           /* not implemented yet */
433         default:
434           break;
435         }
436       }
437     }
438 
439     if ((*syms->vt_convert_to_internal_ch)(iiimf->im.vtparser, &ch) <= 0) {
440       continue;
441     }
442 
443     if (ch.cs == ISO10646_UCS4_1) {
444       if (ch.property & EF_FULLWIDTH) {
445         is_fullwidth = 1;
446       } else if (ch.property & EF_AWIDTH) {
447         /* TODO: check col_size_of_width_a */
448         is_fullwidth = 1;
449       }
450     }
451 
452     if (ch.property & EF_COMBINING) {
453       is_comb = 1;
454 
455       if ((*syms->vt_char_combine)(p - 1, ef_char_to_int(&ch), ch.cs, is_fullwidth,
456                                    (ch.property & EF_AWIDTH) ? 1 : 0, is_comb,
457                                    fg_color, bg_color, is_bold, 0, is_underline, 0, 0)) {
458         continue;
459       }
460 
461       /*
462        * if combining failed, char is normally appended.
463        */
464     }
465 
466     (*syms->vt_char_set)(p, ef_char_to_int(&ch), ch.cs, is_fullwidth,
467                          (ch.property & EF_AWIDTH) ? 1 : 0, is_comb, fg_color,
468                          bg_color, is_bold, 0, is_underline, 0, 0);
469 
470     p++;
471     iiimf->im.preedit.filled_len++;
472   }
473 
474   if (str) {
475     free(str);
476   }
477 
478   if (iiimf->im.preedit.cursor_offset != UI_IM_PREEDIT_NOCURSOR) {
479     iiimf->im.preedit.cursor_offset = iiimf->im.preedit.filled_len;
480   }
481 
482   (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, iiimf->im.preedit.chars,
483                                           iiimf->im.preedit.filled_len,
484                                           iiimf->im.preedit.cursor_offset);
485 }
486 
487 static void preedit_done(im_iiimf_t *iiimf) {
488 #ifdef IM_IIIMF_DEBUG
489   bl_debug_printf(BL_DEBUG_TAG "\n");
490 #endif
491 
492   if (iiimf->im.preedit.chars) {
493     (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
494     iiimf->im.preedit.chars = NULL;
495     iiimf->im.preedit.num_chars = 0;
496     iiimf->im.preedit.filled_len = 0;
497     iiimf->im.preedit.segment_offset = 0;
498     iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
499   }
500 
501   (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, iiimf->im.preedit.chars,
502                                           iiimf->im.preedit.filled_len,
503                                           iiimf->im.preedit.cursor_offset);
504 }
505 
506 static void lookup_choice_start(im_iiimf_t *iiimf) {
507 }
508 
509 static void lookup_choice_change(im_iiimf_t *iiimf) {
510   ui_im_event_listener_t *listener = iiimf->im.listener;
511   IIIMCF_lookup_choice lookup_choice;
512   int size;
513   int index_first;
514   int index_last;
515   int index_current;
516   int x;
517   int y;
518   int i;
519   int num_per_window;
520   int row;
521   int col;
522   int direction;
523 
524 #ifdef IM_IIIMF_DEBUG
525   bl_debug_printf(BL_DEBUG_TAG "\n");
526 #endif
527 
528   if (iiimcf_get_lookup_choice(iiimf->context, &lookup_choice) != IIIMF_STATUS_SUCCESS) {
529 #ifdef DEBUG
530     bl_warn_printf(BL_DEBUG_TAG " Could not get lookup table\n");
531 #endif
532     return;
533   }
534 
535   if (iiimcf_get_lookup_choice_size(lookup_choice, &size, &index_first, &index_last,
536                                     &index_current) != IIIMF_STATUS_SUCCESS) {
537 #ifdef DEBUG
538     bl_warn_printf(BL_DEBUG_TAG " Could not get lookup table.\n");
539 #endif
540     return;
541   }
542 
543   if (iiimcf_get_lookup_choice_configuration(lookup_choice, &num_per_window, &row, &col,
544                                              &direction) != IIIMF_STATUS_SUCCESS) {
545 #ifdef DEBUG
546     bl_warn_printf(BL_DEBUG_TAG " Could not get lookup information.\n");
547 #endif
548     return;
549   }
550 
551 #ifdef IM_IIIMF_DEBUG
552   bl_debug_printf(BL_DEBUG_TAG "size:          %d\n", size);
553   bl_debug_printf(BL_DEBUG_TAG "index_first:   %d\n", index_first);
554   bl_debug_printf(BL_DEBUG_TAG "index_last:    %d\n", index_last);
555   bl_debug_printf(BL_DEBUG_TAG "index_current: %d\n", index_current);
556   bl_debug_printf(BL_DEBUG_TAG "num_per_window:%d\n", num_per_window);
557   bl_debug_printf(BL_DEBUG_TAG "row:           %d\n", row);
558   bl_debug_printf(BL_DEBUG_TAG "col:           %d\n", col);
559 #endif
560 
561   if (num_per_window == 0) {
562     num_per_window = 10;
563   }
564 
565   if (index_first == 0 && index_last == 0) {
566     return;
567   }
568 
569   (*listener->get_spot)(listener->self, iiimf->im.preedit.chars,
570                         iiimf->im.preedit.segment_offset, &x, &y);
571 
572   if (!iiimf->im.cand_screen) {
573     int is_vertical_direction = 0;
574 
575     if (direction == IIIMCF_LOOKUP_CHOICE_VERTICAL_DIRECTION) {
576       is_vertical_direction = 1;
577     }
578 
579     if (iiimf->im.stat_screen) {
580       (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
581       iiimf->im.stat_screen = NULL;
582     }
583 
584     if (!(iiimf->im.cand_screen =
585           (*syms->ui_im_candidate_screen_new)(iiimf->im.disp, iiimf->im.font_man,
586                                               iiimf->im.color_man, iiimf->im.vtparser,
587                                               (*listener->is_vertical)(listener->self),
588                                               is_vertical_direction,
589                                               (*listener->get_line_height)(listener->self),
590                                               x, y))) {
591 #ifdef DEBUG
592       bl_warn_printf(BL_DEBUG_TAG " ui_im_candidate_screen_new() failed.\n");
593 #endif
594 
595       return;
596     }
597 
598     iiimf->im.cand_screen->listener.self = iiimf;
599     iiimf->im.cand_screen->listener.selected = candidate_selected;
600   }
601 
602   if (!(*iiimf->im.cand_screen->init)(iiimf->im.cand_screen, size, num_per_window)) {
603     (*iiimf->im.cand_screen->destroy)(iiimf->im.cand_screen);
604     iiimf->im.cand_screen = NULL;
605     return;
606   }
607 
608   (*iiimf->im.cand_screen->set_spot)(iiimf->im.cand_screen, x, y);
609 
610   for (i = index_first; i <= index_last; i++) {
611     IIIMCF_text iiimcf_text_cand;
612     IIIMCF_text iiimcf_text_label;
613     const IIIMP_card16 *utf16str;
614     u_char *str = NULL;
615     int flag;
616 
617     if (iiimcf_get_lookup_choice_item(lookup_choice, i, &iiimcf_text_cand,
618                                       &iiimcf_text_label, &flag) != IIIMF_STATUS_SUCCESS) {
619 #ifdef DEBUG
620       bl_warn_printf(BL_DEBUG_TAG " Could not candidate item\n");
621 #endif
622       continue;
623     }
624 
625     if (iiimcf_get_text_utf16string(iiimcf_text_cand, &utf16str) != IIIMF_STATUS_SUCCESS) {
626 #ifdef DEBUG
627       bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string\n");
628 #endif
629       continue;
630     }
631 
632     if (im_convert_encoding(parser_utf16, iiimf->conv, (u_char*)utf16str, &str,
633                             strlen_utf16(utf16str) + 1)) {
634       (*iiimf->im.cand_screen->set)(iiimf->im.cand_screen, iiimf->parser_term, str, i);
635       free(str);
636     }
637   }
638 
639   (*iiimf->im.cand_screen->select)(iiimf->im.cand_screen, index_current);
640 }
641 
642 static void status_change(im_iiimf_t *iiimf);
643 
644 static void lookup_choice_done(im_iiimf_t *iiimf) {
645   if (iiimf->im.cand_screen) {
646     (*iiimf->im.cand_screen->destroy)(iiimf->im.cand_screen);
647     iiimf->im.cand_screen = NULL;
648     status_change(iiimf);
649   }
650 }
651 
652 static void status_start(im_iiimf_t *iiimf) {
653 }
654 
655 static void status_change(im_iiimf_t *iiimf) {
656   ui_im_event_listener_t *listener = iiimf->im.listener;
657   IIIMCF_text iiimcf_text;
658   const IIIMP_card16  *utf16str;
659   u_char *str;
660   int x;
661   int y;
662 
663 #ifdef IM_IIIMF_DEBUG
664   bl_debug_printf(BL_DEBUG_TAG "\n");
665 #endif
666 
667   if (!iiimf->on ||
668       !htt_show_status_window ||
669       iiimcf_get_status_text(iiimf->context, &iiimcf_text) != IIIMF_STATUS_SUCCESS) {
670     if (iiimf->im.stat_screen) {
671       (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
672       iiimf->im.stat_screen = NULL;
673     }
674 
675     return;
676   }
677 
678   (*listener->get_spot)(listener->self, iiimf->im.preedit.chars,
679                         iiimf->im.preedit.segment_offset, &x, &y);
680 
681   if (iiimf->im.stat_screen == NULL) {
682     if (!(iiimf->im.stat_screen =
683           (*syms->ui_im_status_screen_new)(iiimf->im.disp, iiimf->im.font_man,
684                                            iiimf->im.color_man, iiimf->im.vtparser,
685                                            (*listener->is_vertical)(listener->self),
686                                            (*listener->get_line_height)(listener->self),
687                                            x, y))) {
688 #ifdef DEBUG
689       bl_warn_printf(BL_DEBUG_TAG " ui_im_satus_screen_new() failed.\n");
690 #endif
691 
692       return;
693     }
694   }
695 
696   if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
697 #ifdef DEBUG
698     bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string.\n");
699 #endif
700     return;
701   }
702 
703   if (im_convert_encoding(parser_utf16, iiimf->conv, (u_char*)utf16str, &str,
704                           strlen_utf16(utf16str) + 1)) {
705     (*iiimf->im.stat_screen->set)(iiimf->im.stat_screen, iiimf->parser_term, str);
706     free(str);
707   }
708 }
709 
710 static void status_done(im_iiimf_t *iiimf) {
711   if (iiimf->im.stat_screen) {
712     (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
713     iiimf->im.stat_screen = NULL;
714   }
715 }
716 
717 
718 static void dispatch(im_iiimf_t *iiimf, IIIMCF_event event, IIIMCF_event_type event_type) {
719   int trigger_flag;
720 
721   switch(event_type) {
722 #if 0
723   case IIIMCF_EVENT_TYPE_DESTROY:
724   case IIIMCF_EVENT_TYPE_RESET:
725   case IIIMCF_EVENT_TYPE_EVENTLIKE:
726 /* case IIIMCF_EVENT_TYPE_KEYEVENT: */
727     /* not implemented yet */
728     break;
729 #endif
730   case IIIMCF_EVENT_TYPE_TRIGGER_NOTIFY:
731     if (iiimcf_get_trigger_notify_flag(event, &trigger_flag) == IIIMF_STATUS_SUCCESS) {
732       iiimf->on = trigger_flag ? 1 : 0;
733       status_change(iiimf);
734     }
735     break;
736 #if 0
737   case IIIMCF_EVENT_TYPE_OPERATION:
738   case IIIMCF_EVENT_TYPE_SETICFOCUS:
739   case IIIMCF_EVENT_TYPE_UNSETICFOCUS:
740 #ifdef HAVE_HOTKEY_NOTFY_EVENT
741   case IIIMCF_EVENT_TYPE_HOTKEY_NOTIFY:
742 #endif
743     /* not implemented yet */
744     break;
745 #endif
746   case IIIMCF_EVENT_TYPE_UI_PREEDIT_START:
747     preedit_start(iiimf);
748     break;
749   case IIIMCF_EVENT_TYPE_UI_PREEDIT_CHANGE:
750     preedit_change(iiimf);
751     break;
752   case IIIMCF_EVENT_TYPE_UI_PREEDIT_DONE:
753     preedit_done(iiimf);
754     break;
755   case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_START:
756     lookup_choice_start(iiimf);
757     break;
758   case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_CHANGE:
759     lookup_choice_change(iiimf);
760     break;
761   case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_DONE:
762     lookup_choice_done(iiimf);
763     break;
764   case IIIMCF_EVENT_TYPE_UI_STATUS_START:
765     status_start(iiimf);
766     break;
767   case IIIMCF_EVENT_TYPE_UI_STATUS_CHANGE:
768     status_change(iiimf);
769     break;
770   case IIIMCF_EVENT_TYPE_UI_STATUS_DONE:
771     status_done(iiimf);
772     break;
773   case IIIMCF_EVENT_TYPE_UI_COMMIT:
774     commit(iiimf);
775     break;
776   case IIIMCF_EVENT_TYPE_AUX_START:
777   case IIIMCF_EVENT_TYPE_AUX_DRAW:
778   case IIIMCF_EVENT_TYPE_AUX_SETVALUES:
779   case IIIMCF_EVENT_TYPE_AUX_DONE:
780 #ifdef HAVE_AUX_GETVALUES_EVENT
781   case IIIMCF_EVENT_TYPE_AUX_GETVALUES:
782 #endif
783     if (iiimf->aux == NULL) {
784       iiimf->aux = aux_new(iiimf);
785     }
786     if (iiimf->aux) {
787       aux_event(iiimf->aux, event, event_type);
788     }
789     break;
790   default:
791     break;
792   }
793 }
794 
795 
796 /*
797  * methods of ui_im_t
798  */
799 
800 static void destroy(ui_im_t *im) {
801   im_iiimf_t *iiimf;
802 
803   iiimf = (im_iiimf_t*) im;
804 
805   if (iiimf->parser_term) {
806     (*iiimf->parser_term->destroy)(iiimf->parser_term);
807   }
808 
809   if (iiimf->conv) {
810     (*iiimf->conv->destroy)(iiimf->conv);
811   }
812 
813   if (iiimf->aux) {
814     aux_destroy(iiimf->aux);
815   }
816 
817   if (iiimf->context) {
818     iiimcf_destroy_context(iiimf->context);
819   }
820 
821   free(iiimf);
822 
823   ref_count--;
824 
825 #ifdef IM_IIIMF_DEBUG
826   bl_debug_printf(BL_DEBUG_TAG " An object was destroyed. ref_count is %d\n", ref_count);
827 #endif
828 
829   if (ref_count == 0 && initialized) {
830     iiimcf_destroy_handle(handle);
831 
832     handle = NULL;
833 
834     iiimcf_finalize();
835 
836     if (parser_utf16) {
837       (*parser_utf16->destroy)(parser_utf16);
838       parser_utf16 = NULL;
839     }
840 
841     aux_quit();
842 
843     initialized = 0;
844   }
845 }
846 
847 static int key_event(ui_im_t *im, u_char key_char, KeySym ksym, XKeyEvent *xevent) {
848   im_iiimf_t *iiimf;
849   IIIMCF_keyevent key;
850   IIIMCF_event event;
851   IIIMF_status status;
852 
853   int is_shift;
854   int is_lock;
855   int is_ctl;
856   int is_alt;
857   int is_meta;
858   int is_super;
859   int is_hyper;
860 
861   iiimf = (im_iiimf_t*) im;
862 
863   key.keycode = 0;
864   key.keychar = 0;
865   key.modifier = 0;
866 
867   (*iiimf->im.listener->compare_key_state_with_modmap)(iiimf->im.listener->self,
868                                                        xevent->state, &is_shift, &is_lock,
869                                                        &is_ctl, &is_alt, &is_meta, NULL,
870                                                        &is_super, &is_hyper);
871 
872   if (is_shift) key.modifier |= IIIMF_SHIFT_MODIFIER;
873   if (is_ctl)   key.modifier |= IIIMF_CONTROL_MODIFIER;
874   if (is_alt)   key.modifier |= IIIMF_ALT_MODIFIER;
875   if (is_meta)  key.modifier |= IIIMF_META_MODIFIER;
876 
877 #if 0
878   if (htt_generates_kanakey && is_shift) {
879     if (!xksym_to_iiimfkey_kana_shift(ksym, &key.keychar, &key.keycode)) {
880       xksym_to_iiimfkey(ksym, &key.keychar, &key.keycode);
881     }
882   }
883 #endif
884 
885   xksym_to_iiimfkey(ksym, &key.keychar, &key.keycode);
886 
887 #if defined(USE_XLIB) || defined(USE_WAYLAND)
888   key.time_stamp = xevent->time;
889 #else
890   key.time_stamp = 0;
891 #endif
892 
893 #if 1
894   /*
895    * ignore Ctrl+] defined as default hotkey.
896    * (see iiimsf/src/IIIMP_hotkey_profile.cpp)
897    */
898   if (!iiimf->on &&
899       key.keycode == IIIMF_KEYCODE_CLOSE_BRACKET &&
900       (key.modifier & IIIMF_CONTROL_MODIFIER)) {
901     return 1;
902   }
903 #endif
904 
905   if (iiimcf_create_keyevent(&key, &event) == IIIMF_STATUS_SUCCESS) {
906     status = iiimcf_forward_event(iiimf->context, event);
907 
908     switch(status) {
909     case IIIMF_STATUS_SUCCESS:
910       return im_iiimf_process_event(iiimf);
911     case IIIMF_STATUS_EVENT_NOT_FORWARDED:
912       break;
913     case IIIMF_STATUS_IC_INVALID:
914       bl_error_printf("Invalid IIIMCF context\n");
915       break;
916     case IIIMF_STATUS_MALLOC:
917 #ifdef DEBUG
918       bl_warn_printf(BL_DEBUG_TAG " iiimcf internal error [IIIMF_STATUS_MALLOC]\n");
919 #endif
920       break;
921     default:
922       bl_error_printf("Could not send key event to IIIMSF\n");
923       break;
924     }
925   }
926 
927   return 1;
928 }
929 
930 static int switch_mode(ui_im_t *im) {
931   return 0;
932 }
933 
934 static int is_active(ui_im_t *im) {
935   return 0;
936 }
937 
938 static void focused(ui_im_t *im) {
939   im_iiimf_t *iiimf;
940   IIIMCF_event event;
941 
942 #ifdef IM_IIIMF_DEBUG
943   bl_debug_printf(BL_DEBUG_TAG "\n");
944 #endif
945 
946   iiimf =  (im_iiimf_t*)  im;
947 
948   if (iiimf->aux) {
949     aux_set_focus(iiimf->aux);
950   }
951 
952   if (iiimcf_create_seticfocus_event(&event) == IIIMF_STATUS_SUCCESS) {
953     if (iiimcf_forward_event(iiimf->context, event) == IIIMF_STATUS_SUCCESS) {
954       im_iiimf_process_event(iiimf);
955     }
956   }
957 
958   if (iiimf->im.stat_screen) {
959     (*iiimf->im.stat_screen->show)(iiimf->im.stat_screen);
960   }
961 
962   if (iiimf->im.cand_screen) {
963     (*iiimf->im.cand_screen->show)(iiimf->im.cand_screen);
964   }
965 }
966 
967 static void unfocused(ui_im_t *im) {
968   im_iiimf_t *iiimf;
969   IIIMCF_event event;
970 
971 #ifdef IM_IIIMF_DEBUG
972   bl_debug_printf(BL_DEBUG_TAG "\n");
973 #endif
974 
975   iiimf = (im_iiimf_t*)  im;
976 
977   if (iiimf->aux) {
978     aux_unset_focus(iiimf->aux);
979   }
980 
981   if (iiimcf_create_unseticfocus_event(&event) == IIIMF_STATUS_SUCCESS) {
982     if (iiimcf_forward_event(iiimf->context, event) == IIIMF_STATUS_SUCCESS) {
983       im_iiimf_process_event(iiimf);
984     }
985   }
986 
987   if (iiimf->im.stat_screen) {
988     (*iiimf->im.stat_screen->hide)(iiimf->im.stat_screen);
989   }
990 
991   if (iiimf->im.cand_screen) {
992     (*iiimf->im.cand_screen->hide)(iiimf->im.cand_screen);
993   }
994 }
995 
996 static int create_handle(IIIMCF_attr attr) {
997   char *env;
998 
999   if ((env = getenv("HTT_SERVER_ADDRESS"))) {
1000     if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_ADDRESS, env)
1001         != IIIMF_STATUS_SUCCESS) {
1002       return 0;
1003     }
1004   }
1005 
1006   if (iiimcf_create_handle(attr, &handle) != IIIMF_STATUS_SUCCESS) {
1007     const char *user;
1008 
1009     if (env == NULL && (user = bl_get_user_name()) &&
1010         (env = alloca(12 + strlen(user) + 5 + 1))) {
1011       DIR *dir;
1012 
1013       sprintf(env, "/tmp/.iiim-%s/", user);
1014       if ((dir = opendir(env))) {
1015         char *p = env + strlen(env);
1016         struct dirent *ent;
1017 
1018         while ((ent = readdir(dir))) {
1019           if (!strchr(ent->d_name, '.') && strlen(ent->d_name) <= 5) {
1020             strcpy(p, ent->d_name);
1021             if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_ADDRESS, env)
1022                 == IIIMF_STATUS_SUCCESS &&
1023                 iiimcf_create_handle(attr, &handle) == IIIMF_STATUS_SUCCESS) {
1024               return 1;
1025             }
1026           }
1027         }
1028       }
1029     }
1030 
1031     return 0;
1032   }
1033 
1034   return 1;
1035 }
1036 
1037 /* --- global functions --- */
1038 
1039 ui_im_t *im_iiimf_new(u_int64_t magic, vt_char_encoding_t term_encoding,
1040                       ui_im_export_syms_t *export_syms,
1041                       char *lang,  /* <language id(rfc1766)>:<language engine> */
1042                       u_int mod_ignore_mask) {
1043   im_iiimf_t *iiimf = NULL;
1044   IIIMCF_attr attr = NULL;
1045   IIIMCF_language language;
1046   IIIMCF_input_method language_engine;
1047 
1048   if (magic != (u_int64_t) IM_API_COMPAT_CHECK_MAGIC) {
1049     bl_error_printf("Incompatible input method API.\n");
1050 
1051     return NULL;
1052   }
1053 
1054   if (!initialized) {
1055     char *env;
1056 
1057     if (iiimcf_initialize(IIIMCF_ATTR_NULL) != IIIMF_STATUS_SUCCESS) {
1058 #ifdef DEBUG
1059       bl_warn_printf(BL_DEBUG_TAG " Could not initialize\n");
1060 #endif
1061       return NULL;
1062     }
1063 
1064     initialized = 1;
1065 
1066     if (iiimcf_create_attr(&attr) != IIIMF_STATUS_SUCCESS) {
1067 #ifdef DEBUG
1068       bl_warn_printf(BL_DEBUG_TAG " Could not create attribute\n");
1069 #endif
1070       goto error;
1071     }
1072 
1073     if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_CLIENT_TYPE,
1074                                      "IIIMF plugin for mlterm") != IIIMF_STATUS_SUCCESS) {
1075 #ifdef DEBUG
1076       bl_warn_printf(BL_DEBUG_TAG " Could not append a string to the attribute\n");
1077 #endif
1078       goto error;
1079     }
1080 
1081 #ifdef USE_XLIB
1082     if ((env = getenv("DISPLAY")) &&
1083         iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_CLIENT_X_DISPLAY_NAME, env)
1084                                      != IIIMF_STATUS_SUCCESS) {
1085 #ifdef DEBUG
1086       bl_warn_printf(BL_DEBUG_TAG " Could not append a string to the attribute\n");
1087 #endif
1088     }
1089 #endif
1090 
1091     if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_SERVICE, "") !=
1092         IIIMF_STATUS_SUCCESS) {
1093 #ifdef DEBUG
1094       bl_warn_printf(BL_DEBUG_TAG " Could not append a server service to the attribute\n");
1095 #endif
1096       goto error;
1097     }
1098 
1099     if (!create_handle(attr)) {
1100       bl_error_printf("Could not create handle for IIIMF. Try to setenv HTT_SERVER_ADDRESS.\n");
1101       goto error;
1102     }
1103 
1104     iiimcf_destroy_attr(attr);
1105     attr = NULL;
1106 
1107     /*
1108      * Note: The byte order is the same as client.
1109      * (see lib/iiimp/data/im-connect.c:iiimp_connect_new())
1110      */
1111 #ifdef WORDS_BIGENDIAN
1112     if (!(parser_utf16 = ef_utf16_parser_new()))
1113 #else
1114       if (!(parser_utf16 = ef_utf16le_parser_new()))
1115 #endif
1116     {
1117       goto error;
1118     }
1119 
1120     if ((env = getenv("HTT_SHOW_STATUS_WINDOW"))) {
1121       if (*env == 't' || *env == 'T') {
1122         htt_show_status_window = 1;
1123       }
1124     }
1125 
1126     if ((env = getenv("HTT_GENERATES_KANAKEY"))) {
1127       if (*env == 't' || *env == 'T') {
1128         htt_generates_kanakey = 1;
1129       }
1130     }
1131 
1132     syms = export_syms;
1133     aux_init(handle, syms, parser_utf16);
1134 
1135     show_iiimcf_version();
1136   }
1137 
1138   language = find_language(lang);
1139   language_engine = find_language_engine(lang);
1140 
1141   if (!(iiimf = malloc(sizeof(im_iiimf_t)))) {
1142     goto error;
1143   }
1144 
1145   /*
1146    * set methods of ui_im_t
1147    */
1148   iiimf->im.destroy = destroy;
1149   iiimf->im.key_event = key_event;
1150   iiimf->im.switch_mode = switch_mode;
1151   iiimf->im.is_active = is_active;
1152   iiimf->im.focused = focused;
1153   iiimf->im.unfocused = unfocused;
1154 
1155   iiimf->context = NULL;
1156   iiimf->parser_term = NULL;
1157   iiimf->conv = NULL;
1158   iiimf->aux = NULL;
1159   iiimf->on = 0;
1160 
1161   if (!(iiimf->parser_term = (*syms->vt_char_encoding_parser_new)(term_encoding))) {
1162     goto error;
1163   }
1164 
1165   if (!(iiimf->conv = (*syms->vt_char_encoding_conv_new)(term_encoding))) {
1166     goto error;
1167   }
1168 
1169   if (iiimcf_create_attr(&attr) != IIIMF_STATUS_SUCCESS) {
1170 #ifdef DEBUG
1171     bl_warn_printf(BL_DEBUG_TAG " Could not create attribute\n");
1172 #endif
1173     goto error;
1174   }
1175 
1176   if (language) {
1177     if (iiimcf_attr_put_ptr_value(attr, IIIMCF_ATTR_INPUT_LANGUAGE,
1178                                   language) != IIIMF_STATUS_SUCCESS) {
1179 #ifdef DEBUG
1180       bl_warn_printf(BL_DEBUG_TAG " Could not append value to the attribute\n");
1181 #endif
1182     }
1183   }
1184 
1185   if (language_engine) {
1186     if (iiimcf_attr_put_ptr_value(attr, IIIMCF_ATTR_INPUT_METHOD,
1187                                   language_engine) != IIIMF_STATUS_SUCCESS) {
1188 #ifdef DEBUG
1189       bl_warn_printf(BL_DEBUG_TAG " Could not append value to the attribute\n");
1190 #endif
1191     }
1192   }
1193 
1194   if (iiimcf_create_context(handle, attr, &iiimf->context) != IIIMF_STATUS_SUCCESS) {
1195 #ifdef DEBUG
1196     bl_warn_printf(BL_DEBUG_TAG " Could not create context\n");
1197 #endif
1198     goto error;
1199   }
1200 
1201   iiimcf_destroy_attr(attr);
1202   attr = NULL;
1203 
1204   ref_count++;
1205 
1206 #ifdef IM_IIIMF_DEBUG
1207   bl_debug_printf(BL_DEBUG_TAG " New object was created. ref_count is %d.\n", ref_count);
1208 #endif
1209 
1210   return (ui_im_t*) iiimf;
1211 
1212 error:
1213   if (attr) {
1214     iiimcf_destroy_attr(attr);
1215   }
1216 
1217   if (initialized && ref_count == 0) {
1218     if (handle) {
1219       iiimcf_destroy_handle(handle);
1220     }
1221 
1222     handle = NULL;
1223 
1224     if (parser_utf16) {
1225       (*parser_utf16->destroy)(parser_utf16);
1226     }
1227 
1228     iiimcf_finalize();
1229 
1230     aux_quit();
1231 
1232     initialized = 0;
1233   }
1234 
1235   if (iiimf) {
1236     if (iiimf->parser_term) {
1237       (*iiimf->parser_term->destroy)(iiimf->parser_term);
1238     }
1239 
1240     if (iiimf->conv) {
1241       (*iiimf->conv->destroy)(iiimf->conv);
1242     }
1243 
1244     free(iiimf);
1245   }
1246 
1247   return NULL;
1248 }
1249 
1250 int im_iiimf_process_event(im_iiimf_t *iiimf) {
1251   int ret = 0;
1252   IIIMCF_event received_event;
1253   IIIMCF_event_type type;
1254 
1255   while (iiimcf_get_next_event(iiimf->context, &received_event) == IIIMF_STATUS_SUCCESS) {
1256     if (iiimcf_get_event_type(received_event, &type) != IIIMF_STATUS_SUCCESS) {
1257       ret = 1;
1258       continue;
1259     }
1260 
1261     if (type == IIIMCF_EVENT_TYPE_KEYEVENT) {
1262       ret = 1;
1263     }
1264     dispatch(iiimf, received_event, type);
1265 
1266     /*
1267      * IIICF library specification said:
1268      *
1269      * NOTICE: old version of libiiimcf had discarded any events
1270      * dispatched by iiimcf_dispatch_event. But in the new
1271      * version, you MUST call iiimcf_ignore_event to all events
1272      * that are obtained by iiimcf_get_next_event even though they
1273      * are dispatched by iiimcf_dispatch_event.
1274      *
1275      */
1276     if (iiimcf_dispatch_event(iiimf->context, received_event) != IIIMF_STATUS_SUCCESS) {
1277 #ifdef DEBUG
1278       bl_warn_printf(BL_DEBUG_TAG " Could not dispatch event\n");
1279 #endif
1280     }
1281 
1282     if (iiimcf_ignore_event(received_event) != IIIMF_STATUS_SUCCESS) {
1283 #ifdef DEBUG
1284       bl_warn_printf(BL_DEBUG_TAG " Could not dispatch event\n");
1285 #endif
1286     }
1287   }
1288 
1289   return ret;
1290 }
1291 
1292 /* --- API for external tools --- */
1293 
1294 im_info_t *im_iiimf_get_info(char *locale, char *encoding) {
1295   im_info_t *result = NULL;
1296   IIIMCF_input_method *input_methods;
1297   IIIMCF_language *langs;
1298   ef_conv_t *conv = NULL;
1299   int num_ims;
1300   int num_langs;
1301   int total = 0;
1302   int idx;
1303   int auto_idx = 0;
1304   int i;
1305   int j;
1306 
1307   if (iiimcf_initialize(IIIMCF_ATTR_NULL) != IIIMF_STATUS_SUCCESS) {
1308     return NULL;
1309   }
1310 
1311   if (iiimcf_create_handle(IIIMCF_ATTR_NULL, &handle) != IIIMF_STATUS_SUCCESS) {
1312     iiimcf_finalize();
1313     return NULL;
1314   }
1315 
1316   if (iiimcf_get_supported_input_methods(handle, &num_ims,
1317                                          &input_methods) != IIIMF_STATUS_SUCCESS) {
1318     goto error;
1319   }
1320 
1321   for (i = 0; i < num_ims; i++) {
1322     if (iiimcf_get_input_method_languages(input_methods[i], &num_langs,
1323                                           &langs) != IIIMF_STATUS_SUCCESS) {
1324       goto error;
1325     }
1326 
1327     total += num_langs;
1328   }
1329 
1330   /*
1331    * Note: The byte order is the same as client.
1332    * (see lib/iiimp/data/im-connect.c:iiimp_connect_new())
1333    */
1334 #ifdef WORDS_BIGENDIAN
1335   if (!(parser_utf16 = ef_utf16_parser_new()))
1336 #else
1337   if (!(parser_utf16 = ef_utf16le_parser_new()))
1338 #endif
1339   {
1340     goto error;
1341   }
1342 
1343   if (!(conv = ef_iso8859_1_conv_new())) {
1344     goto error;
1345   }
1346 
1347   if (!(result = malloc(sizeof(im_info_t)))) {
1348     goto error;
1349   }
1350 
1351   result->id = strdup("iiimf");
1352   result->name = strdup("IIIMF");
1353   result->num_args = total + 1;
1354   result->args = NULL;
1355   result->readable_args = NULL;
1356 
1357   if (!(result->args = calloc(result->num_args, sizeof(char*)))) {
1358     goto error;
1359   }
1360 
1361   if (!(result->readable_args = calloc(result->num_args, sizeof(char*)))) {
1362     goto error;
1363   }
1364 
1365   idx = 1;
1366 
1367   for (i = 0; i < num_ims; i++) {
1368     const IIIMP_card16 *im_id;
1369     const IIIMP_card16 *im_hrn;
1370     const IIIMP_card16 *im_domain;
1371     u_char *im;
1372 
1373     if (iiimcf_get_input_method_desc(input_methods[i], &im_id, &im_hrn,
1374                                      &im_domain) != IIIMF_STATUS_SUCCESS) {
1375       continue;
1376     }
1377 
1378     if (iiimcf_get_input_method_languages(input_methods[i], &num_langs,
1379                                           &langs) != IIIMF_STATUS_SUCCESS) {
1380       continue;
1381     }
1382 
1383     im_convert_encoding(parser_utf16, conv, (u_char*)im_id, &im, strlen_utf16(im_id) + 1);
1384 
1385     for (j = 0; j < num_langs; j++) {
1386       const char *lang_id;
1387       size_t len;
1388 
1389       iiimcf_get_language_id(langs[j], &lang_id);
1390 
1391       if (strncmp(lang_id, locale, 2) == 0 && auto_idx == 0) {
1392         auto_idx = idx;
1393       }
1394 
1395       len = strlen(im) + strlen(lang_id) + 4;
1396 
1397       if ((result->args[idx] = malloc(len))) {
1398         bl_snprintf(result->args[idx], len, "%s:%s", lang_id, im);
1399       } else {
1400         result->args[idx] = strdup("error");
1401       }
1402 
1403       if ((result->readable_args[idx] = malloc(len))) {
1404         bl_snprintf(result->readable_args[idx], len, "%s (%s)", lang_id, im);
1405       } else {
1406         result->readable_args[i] = strdup("error");
1407       }
1408 
1409       idx ++;
1410     }
1411 
1412     free(im);
1413   }
1414 
1415   result->args[0] = strdup("");
1416   if (auto_idx) {
1417     result->readable_args[0] = strdup(result->readable_args[auto_idx]);
1418   } else {
1419     result->readable_args[0] = strdup("unknown");
1420   }
1421 
1422   if (total != idx - 1) {
1423     free(result->id);
1424     free(result->name);
1425 
1426     for (i = 0; i < idx - 1; i++) {
1427       free(result->args[i]);
1428       free(result->readable_args[i]);
1429     }
1430 
1431     free(result->args);
1432     free(result->readable_args);
1433 
1434     free(result);
1435 
1436     result = NULL;
1437   }
1438 
1439   iiimcf_destroy_handle(handle);
1440 
1441   iiimcf_finalize();
1442 
1443   return result;
1444 
1445 error:
1446   if (parser_utf16) {
1447     (*parser_utf16->destroy)(parser_utf16);
1448   }
1449 
1450   if (conv) {
1451     (*conv->destroy)(conv);
1452   }
1453 
1454   if (handle) {
1455     iiimcf_destroy_handle(handle);
1456   }
1457 
1458   iiimcf_finalize();
1459 
1460   if (result) {
1461     if (result->args) {
1462       free(result->args);
1463     }
1464 
1465     if (result->readable_args) {
1466       free(result->readable_args);
1467     }
1468 
1469     free(result);
1470   }
1471 
1472   return NULL;
1473 }
1474