Back to index

im-sdk  12.3.91
CannaLE.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003 Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a
00006 copy of this software and associated documentation files (the
00007 "Software"), to deal in the Software without restriction, including
00008 without limitation the rights to use, copy, modify, merge, publish,
00009 distribute, sublicense, and/or sell copies of the Software, and to
00010 permit persons to whom the Software is furnished to do so, subject to
00011 the following conditions: The above copyright notice and this
00012 permission notice shall be included in all copies or substantial
00013 portions of the Software.
00014 
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00017 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00018 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00019 IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
00020 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00021 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
00022 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
00023 ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
00024 
00025 
00026 Except as contained in this notice, the names of The Open Group and/or
00027 Sun Microsystems, Inc. shall not be used in advertising or otherwise to
00028 promote the sale, use or other dealings in this Software without prior
00029 written authorization from The Open Group and/or Sun Microsystems,
00030 Inc., as applicable.
00031 
00032 
00033 X Window System is a trademark of The Open Group
00034 
00035 OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
00036 logo, LBX, X Window System, and Xinerama are trademarks of the Open
00037 Group. All other trademarks and registered trademarks mentioned herein
00038 are the property of their respective owners. No right, title or
00039 interest in or to any trademark, service mark, logo or trade name of
00040 Sun Microsystems, Inc. or its licensors is granted.
00041 
00042 */
00043 
00044 #ifdef WIN32
00045 #include <windows.h>
00046 #endif
00047 
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <stdarg.h>
00052 #include <unistd.h>
00053 #include <assert.h>
00054 #include <pwd.h>
00055 #include <sys/types.h>
00056 #include <canna/jrkanji.h>
00057 
00058 #ifndef _WCHAR_T
00059 #define _WCHAR_T
00060 #endif
00061 
00062 #ifdef DEBUG
00063 #define       ENTER  fprintf(stderr, "%s: enter.\n", __FUNCTION__)
00064 #define       LEAVE  fprintf(stderr, "%s: leave.\n", __FUNCTION__)
00065 #else
00066 #define       ENTER
00067 #define       LEAVE
00068 #endif
00069 
00070 #include "cannadef.h"
00071 #include "SunIM.h"
00072 
00073 static char canna_le_init_filename[] = ".canna";
00074 
00075 #define CANNA_COMMIT_STRING_BUFSIZE (8192 * 2)
00076 #define CANNA_CODESET_LOCALE "ja_JP.eucJP"
00077 #define EUC_JP_SS2 0x8E
00078 #define EUC_JP_SS3 0x8F
00079 #define CANNA_NEXT_CHAR(p)         \
00080   (((*p) == 0) ? (p) :                    \
00081    (((*p) < 0x80) ? ((p) + 1) :           \
00082     (((*p) == EUC_JP_SS3) ? ((p) + 3) :   \
00083      ((p) + 2))))
00084 #define CANNA_GUIDELINE_DELIMITER_P(p)    \
00085   ((((*p) == ' ') && ((p[1]) == ' ')) || ((*p) == '\t') ||     \
00086    (((*p) == 0xA1) && ((p[1]) == 0xA1)))
00087 
00088 #include <dlfcn.h>
00089 #include "csconv.h"
00090 #define CSC_OPEN_LOCALE     "csconv_open_locale"
00091 #define CSC_OPEN     "csconv_open"
00092 #define CSC_CONV     "csconv"
00093 #define CSC_CLOSE    "csconv_close"
00094 
00095 #define CSC_FAILED -1
00096 #define CSC_UNLOADED 0
00097 #define CSC_UNOPENED 1
00098 #define CSC_LOADED 2
00099 
00100 typedef csconv_t     (* csc_open_locale_t)(const char *,
00101                                          const char *, const char *);
00102 typedef csconv_t     (* csc_open_t)(const char *, const char *);
00103 typedef size_t              (* csc_conv_t)(csconv_t, const char **, size_t *,
00104                                    char **, size_t *);
00105 typedef int          (* csc_close_t)(csconv_t);
00106 
00107 static void *               csc_handle;   
00108 static csc_open_locale_t    csc_open_locale;
00109 static csc_open_t           csc_open;
00110 static csc_conv_t           csc_conv;
00111 static csc_close_t          csc_close;
00112 static csconv_t                 csconv_cd = NULL;
00113 
00114 Bool    if_canna_OpenIF();
00115 Bool    if_canna_CloseIF();
00116 Bool    if_canna_GetIFValue();
00117 Bool    if_canna_SetIFValue();
00118 Bool    if_canna_OpenDesktop();
00119 Bool    if_canna_CloseDesktop();
00120 Bool    if_canna_CreateSC();
00121 Bool    if_canna_DestroySC();
00122 Bool    if_canna_GetSCValue();
00123 Bool    if_canna_SetSCValue();
00124 IMText  *if_canna_ResetSC();
00125 void    if_canna_SetSCFocus();
00126 void    if_canna_UnsetSCFocus();
00127 void    if_canna_SendEvent();
00128 
00129 Bool canna_parse_guideline(iml_session_t *s, int *pnum,
00130                         char ***psegs,
00131                         int **pnb,
00132                         int *pcurrent);
00133 void          canna_status_draw_off(iml_session_t *s);
00134 static int    canna_get_current_mode(iml_session_t *s);
00135 static int      canna_get_current_minor_mode(iml_session_t *s);
00136 int             canna_get_current_candidate_position(iml_session_t *s);
00137 int             canna_get_candidate_count(iml_session_t *s);
00138 static void   canna_change_mode(iml_session_t *s, int id);
00139 static Bool   canna_drop_privilege(const char *username);
00140 void            aux_draw(iml_session_t *s, int count_integers,
00141                       int *integers, int count_strings,
00142                       char **strings);
00143 static Bool     process_keyevent(iml_session_t *s, int ch);
00144 
00145 /* IF Method */
00146 if_methods_t canna_methods = {
00147     if_canna_OpenIF,
00148     if_canna_CloseIF,
00149     if_canna_GetIFValue,
00150     if_canna_SetIFValue,
00151 
00152     if_canna_OpenDesktop,
00153     if_canna_CloseDesktop,
00154 
00155     if_canna_CreateSC,
00156     if_canna_DestroySC,
00157     if_canna_GetSCValue,
00158     if_canna_SetSCValue,
00159     if_canna_ResetSC,
00160     if_canna_SetSCFocus,
00161     if_canna_UnsetSCFocus,
00162     if_canna_SendEvent,
00163 };
00164 
00165 UTFCHAR lename_string[] = {0x304B, 0x3093, 0x306A, 0x4C, 0x45, 0x0};
00166 UTFCHAR jahrn_string[] = {0x65E5, 0x672C, 0x8A9E, 0x0};
00167 UTFCHAR lookup_choice_title[] = {0x5019, 0x88DC, 0x9078, 0x629E, 0x0};
00168 char *class_names[] = {"com.OpenI18N.leif.CannaLE.menu"};
00169 
00170 static IMLEName lename = {
00171     "CannaLE", lename_string       /* LE id, HRN */
00172 };
00173 
00174 static IMLocale locales[] = {
00175     {"ja", jahrn_string},   /* locale id, HRN */
00176     {NULL, NULL},
00177 };
00178 
00179 /*
00180   CSConv:
00181 */
00182 
00183 static void
00184 dlopen_csconv()
00185 {
00186     csc_handle = dlopen(CSC_PATH, RTLD_LAZY);
00187     if (NULL == csc_handle) {
00188        csc_handle = (void *)(-1);
00189        return;
00190     }
00191 
00192     csc_open_locale = (csc_open_locale_t)dlsym(csc_handle, CSC_OPEN_LOCALE);
00193     csc_open = (csc_open_t)dlsym(csc_handle, CSC_OPEN);
00194     csc_conv = (csc_conv_t)dlsym(csc_handle, CSC_CONV);
00195     csc_close = (csc_close_t)dlsym(csc_handle, CSC_CLOSE);
00196 
00197     if ((NULL == csc_open_locale) || (NULL == csc_open) ||
00198        (NULL == csc_conv) || (NULL == csc_close)) {
00199        dlclose(csc_handle);
00200        csc_handle = (void *)(-1);
00201        return;
00202     }
00203 }
00204 
00205 static int
00206 csconv_status()
00207 {
00208     if ((csc_handle == (void *)(-1))
00209        || (csconv_cd == (csconv_t)(-1)))
00210        return CSC_FAILED;
00211     else if (csc_handle == NULL)
00212        return CSC_UNLOADED;
00213     else if (csconv_cd == NULL)
00214        return CSC_UNOPENED;
00215 
00216     return CSC_LOADED;
00217 }
00218 
00219 static void
00220 csconv_open_conv()
00221 {
00222     /* Open UTF-16 => Canna Multibyte Format */
00223     if (csconv_status() == CSC_UNOPENED)
00224        csconv_cd = (csc_open_locale)(CANNA_CODESET_LOCALE,
00225                                   "UTF-16",
00226                                   "MultiByte");
00227     if (csconv_cd <= 0)
00228        fprintf(stderr, "CannaLE: Cannot Open csconv - %s\n",
00229               CANNA_CODESET_LOCALE);
00230 }
00231 
00232 static void
00233 setup_csconv()
00234 {
00235     if (csconv_status() == CSC_UNLOADED)
00236        dlopen_csconv();
00237     if (csconv_status() == CSC_UNOPENED)
00238        csconv_open_conv();
00239 
00240     return;
00241 }
00242 
00243 /*
00244   Desktop data:
00245  */
00246 
00247 typedef struct
00248 {
00249     int drop_priv;
00250 } CannaLEDesktop;
00251 
00252 /*
00253   Session data:
00254 */
00255 
00256 static int canna_context_id_counter = 1;
00257 
00258 typedef struct
00259 {
00260     int context_id;
00261     jrKanjiStatusWithValue ksv;
00262     int conversion_start;
00263     int aux_start;
00264     int old_minor_mode;
00265     int update_state;
00266     int force_not_update_state;
00267     Bool is_canna_initialized;
00268 } CannaLESession;
00269 
00270 CannaLESession*
00271 canna_session_data(iml_session_t *s)
00272 {
00273     return (CannaLESession*)(s->specific_data);
00274 }
00275 
00276 CannaLEDesktop *
00277 canna_desktop_data(iml_session_t *s)
00278 {
00279     return (CannaLEDesktop *)(s->desktop->specific_data);
00280 }
00281 
00282 int
00283 canna_session_context(iml_session_t *s)
00284 {
00285     return ((CannaLESession*)(s->specific_data))->context_id;
00286 }
00287 
00288 jrKanjiStatusWithValue*
00289 canna_session_status(iml_session_t *s)
00290 {
00291     return &((CannaLESession*)(s->specific_data))->ksv;
00292 }
00293 
00294 /*
00295   AUX Object:
00296 */
00297 
00298 static IMObjectDescriptorStruct *objects = NULL;
00299 
00300 static void
00301 init_objects()
00302 {
00303     IMObjectDescriptorStruct *l;
00304     objects = (IMObjectDescriptorStruct *) calloc(2, sizeof (IMObjectDescriptorStruct));
00305 
00306     l = objects;
00307 
00308     l->leid = "CannaLE";
00309     l->type = IM_DOWNLOADINGOBJECT_BINGUI_TYPE;
00310     l->name = (UTFCHAR *)"menu";
00311     l->name_length = 10;
00312     l->domain = "com.OpenI18N.leif";
00313     l->scope = "CannaLE";
00314     l->path = "CannaLE/aux.so";
00315     l->signature = "";
00316     l->basepath = NULL;
00317     l->encoding = NULL;
00318 }
00319 
00320 static void
00321 free_objects()
00322 {
00323     free(objects);
00324     objects = NULL;
00325 }
00326 
00327 /*
00328   Feedback operations:
00329 */
00330 
00331 typedef enum {
00332     Canna_Feedback_Input,
00333     Canna_Feedback_Strong,
00334     Canna_Feedback_Normal,
00335 }Canna_Feedback_Types;
00336 
00337 IMFeedbackList *
00338 create_feedback(iml_session_t *s, int size)
00339 {
00340     int i;
00341     IMFeedbackList *feedback;
00342     IMFeedback *fb;
00343     
00344     if (!s) return NULL;
00345 
00346     feedback = ((IMFeedbackList *)
00347               s->If->m->iml_new(s, sizeof(IMFeedbackList) * size));
00348     for (i = 0; i < size; i++) {
00349        IMFeedbackList *fbl = &feedback[i];
00350        fbl->count_feedbacks = 1;
00351        fb = ((IMFeedback *) s->If->m->iml_new(s, sizeof(IMFeedback) * 4));
00352        fbl->feedbacks = fb;
00353        memset(fbl->feedbacks, 0, sizeof(IMFeedback) * 4);
00354     }
00355     return feedback;
00356 }
00357 
00358 IMFeedbackList *
00359 create_feedback2(iml_session_t *s, int size)
00360 {
00361     int i;
00362     IMFeedbackList *feedback;
00363     IMFeedback *fb;
00364     
00365     if (!s) return NULL;
00366 
00367     feedback = ((IMFeedbackList *)
00368               s->If->m->iml_new2(s, sizeof(IMFeedbackList) * size));
00369     for (i = 0; i < size; i++) {
00370        IMFeedbackList *fbl = &feedback[i];
00371        fbl->count_feedbacks = 1;
00372        fb = ((IMFeedback *) s->If->m->iml_new2(s, sizeof(IMFeedback) * 4));
00373        fbl->feedbacks = fb;
00374        memset(fbl->feedbacks, 0, sizeof(IMFeedback) * 4);
00375     }
00376     return feedback;
00377 }
00378 
00379 int
00380 get_feedback(IMFeedbackList *fbl)
00381 {
00382     /* returns IM_DECORATION_FEEDBACK */
00383     IMFeedback *fb = &fbl->feedbacks[0];
00384     return IM_FEEDBACK_VALUE(fb);
00385 }
00386 
00387 void
00388 set_feedback_private(
00389     IMFeedbackList * fbl,
00390     int normalfeedback,
00391     int fg,
00392     int bg,
00393     int underline
00394 )
00395 {
00396     int count = 0;
00397     IMFeedback *fb;
00398     
00399     fb = &fbl->feedbacks[count];
00400     IM_FEEDBACK_TYPE(fb) = IM_DECORATION_FEEDBACK;
00401     IM_FEEDBACK_VALUE(fb) = normalfeedback;
00402     count++;
00403     
00404 #ifdef USE_COLOR_FEEDBACK
00405 
00406     if (fg != -1) {
00407        fb = &fbl->feedbacks[count];
00408        IM_FEEDBACK_TYPE(fb) = IM_FOREGROUND_RGB_FEEDBACK;
00409        IM_FEEDBACK_VALUE(fb) = fg;
00410        count++;
00411     }
00412     if (bg != -1) {
00413        fb = &fbl->feedbacks[count];
00414        IM_FEEDBACK_TYPE(fb) = IM_BACKGROUND_RGB_FEEDBACK;
00415        IM_FEEDBACK_VALUE(fb) = bg;
00416        count++;
00417     }
00418     if (underline != -1) {
00419        fb = &fbl->feedbacks[count];
00420        IM_FEEDBACK_TYPE(fb) = IM_UNDERLINE_RGB_FEEDBACK;
00421        IM_FEEDBACK_VALUE(fb) = underline;
00422        count++;
00423     }
00424 
00425 #endif
00426     IM_FEEDBACK_COUNT(fbl) = count;
00427 }
00428 
00429 void
00430 set_canna_feedback_1(IMFeedbackList *fbl, int feedback_type)
00431 {
00432 
00433     switch(feedback_type) {
00434     case Canna_Feedback_Input:
00435        set_feedback_private(fbl,
00436                           IMUnderline,
00437                           IM_RGB_COLOR(0, 0, 255),        /* FG: blue */
00438                           IM_RGB_COLOR(255, 255, 255), /* BG: white */
00439                           1);                          /* Underline */
00440        break;
00441     case Canna_Feedback_Strong:
00442        set_feedback_private(fbl,
00443                           IMReverse,
00444                           IM_RGB_COLOR(255, 255, 255), /* FG: white */
00445                           IM_RGB_COLOR(0, 0, 255),     /* BG: blue */
00446                           -1);
00447        break;
00448     case Canna_Feedback_Normal:
00449     default:
00450        set_feedback_private(fbl, IMNormal, -1, -1, -1);
00451        break;
00452     }
00453     return;
00454        
00455 }
00456 
00457 void
00458 set_canna_feedback(IMFeedbackList *fbl, int feedback_type,
00459                  int st, int end)
00460 {
00461     for (;st < end;st++)
00462        set_canna_feedback_1((fbl + st), feedback_type);
00463     return;
00464 }
00465 
00466 
00467 IMFeedbackList *
00468 create_canna_feedback(iml_session_t *s,
00469                     int size,
00470                     int normalfeedback,
00471                     int fg,
00472                     int bg)
00473 {
00474     int i;
00475     IMFeedbackList *feedback;
00476 
00477     feedback = (IMFeedbackList *) create_feedback(s, size);
00478     for (i = 0; i < size; i++) {
00479        IMFeedbackList *fbl = &feedback[i];
00480        set_feedback_private(fbl, normalfeedback, fg, bg, -1);
00481     }
00482 
00483     return feedback;
00484 }
00485 
00486 /*
00487   IMText operations:
00488 */
00489 
00490 IMText*
00491 create_IMText(iml_session_t *s, int len)
00492 {
00493     IMText *p;
00494     
00495     if (!s) return NULL;
00496 
00497     p = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
00498     memset(p, 0, sizeof(IMText));
00499     p->encoding = UTF16_CODESET;
00500     p->text.utf_chars = ((UTFCHAR *)
00501                       s->If->m->iml_new(s, sizeof(UTFCHAR) * (len + 1)));
00502     p->char_length = len;
00503     p->feedback = create_feedback(s, len);
00504 
00505     return p;
00506 }
00507 
00508 IMText*
00509 UTFCHAR_to_IMText(iml_session_t *s, UTFCHAR *p)
00510 {
00511     IMText *pit;
00512     UTFCHAR *p2 = p;
00513     int len;
00514 
00515     for (len = 0;*p2;p2++) len++;
00516     pit = create_IMText(s, len);
00517     if (!pit) return NULL;
00518     memcpy(pit->text.utf_chars, p, (len + 1) * sizeof(UTFCHAR));
00519 
00520     return pit;
00521 }
00522 
00523 /*
00524   String conversion:
00525 */
00526 
00527 size_t 
00528 UTFCHAR_buffer_size(size_t canna_str_len)
00529 {
00530     return canna_str_len * sizeof (UTFCHAR);
00531 }
00532 
00533 UTFCHAR*
00534 canna_string_to_UTFCHAR(unsigned char *str)
00535 {
00536     size_t ret, clen, ulen;
00537     UTFCHAR *ustr, *p;
00538     const char *pin;
00539     char *pout;
00540 
00541     clen = strlen(str);
00542     ulen = UTFCHAR_buffer_size(clen + 1);
00543     ustr = (UTFCHAR*) malloc(ulen);
00544     pin = (const char *)str;
00545     pout = (char *)ustr;
00546 
00547     ret = csc_conv(csconv_cd,
00548                  &pin, &clen,
00549                  &pout, &ulen);
00550     if (ret != clen) return NULL;
00551     p = (UTFCHAR *)pout;
00552     *p = 0;
00553     return ustr;
00554 }
00555 
00556 IMText*
00557 canna_string_to_IMText(iml_session_t *s,
00558                      int nseg, int *nb,
00559                      char **strs,
00560                      int *feedback_type,
00561                      int *caret_position)
00562 {
00563     UTFCHAR *ustr = NULL, *p;
00564     IMText *pit;
00565     const char *from;
00566     char *pout;
00567     size_t ret, from_size, ulen, clen;
00568     int i, uidx;
00569     int *idices = NULL;
00570 
00571     clen = 0;
00572     for (i = 0;i < nseg;i++) {
00573        clen += nb[i];
00574     }
00575     ulen = UTFCHAR_buffer_size(clen + 1);
00576     ustr = p = (UTFCHAR*) malloc(sizeof(UTFCHAR) * ulen);
00577     idices = (int*) malloc(sizeof(int) * (nseg + 1));
00578     pout = (char *)ustr;
00579 
00580     for (i = 0;i < nseg;i++) {
00581        from = (const char *)strs[i];
00582        from_size = nb[i];
00583        idices[i] = p - ustr;
00584        ret = csc_conv(csconv_cd,
00585                      &from, &from_size,
00586                      &pout, &ulen);
00587        p = (UTFCHAR *)pout;
00588     }
00589     *p = 0;
00590     uidx = p - ustr;
00591     idices[nseg] = uidx;
00592     pit = create_IMText(s, uidx);
00593     if (pit == NULL)
00594        goto ensure;
00595     memcpy(pit->text.utf_chars, ustr, (p - ustr + 1) * sizeof(UTFCHAR));
00596 
00597     if (feedback_type) {
00598        /* set feedback */
00599        for (i = 0;i < nseg;i++) {
00600            set_canna_feedback(pit->feedback, feedback_type[i],
00601                             idices[i], idices[i + 1]);
00602        }
00603     }
00604 
00605     if (caret_position != NULL) {
00606        *caret_position = idices[1];
00607     }
00608 ensure:
00609     if (ustr != NULL)
00610        free(ustr);
00611     if (idices != NULL)
00612        free(idices);
00613 
00614     return pit;
00615 }
00616 
00617 /*
00618   LEIF operations.
00619 */
00620 
00621 static void
00622 send_commit(iml_session_t *s, IMText *p, int executep)
00623 {
00624     iml_inst *lp;
00625     iml_inst *rrv = NULL;
00626 
00627     lp = s->If->m->iml_make_commit_inst(s, p);
00628     s->If->m->iml_link_inst_tail(&rrv, lp);
00629     if (executep) {
00630        s->If->m->iml_execute(s, &rrv);
00631     }
00632     return;
00633 }
00634 
00635 /*
00636   Canna operations.
00637 */
00638 
00639 static char*
00640 canna_init_filename(char *user)
00641 {
00642     char *buf;
00643     int ipsize;
00644     struct passwd *pw;
00645 
00646     if (!user)
00647        return NULL;
00648     setpwent();
00649     if ((pw = getpwnam(user)) == NULL) {
00650        endpwent();
00651        return NULL;
00652     }
00653     ipsize = strlen(pw->pw_dir);
00654     buf = (char*) malloc((ipsize + 2) * sizeof(char)
00655                       + sizeof(canna_le_init_filename));
00656     if (ipsize < 1) return NULL;
00657     strcpy(buf, pw->pw_dir);
00658     buf[ipsize] = '/';
00659     buf[ipsize + 1] = '\0';
00660     strcat(buf, canna_le_init_filename);
00661 
00662     endpwent();
00663 
00664     /* check whether the file is readable. */
00665     if (access(buf, R_OK) != 0) {
00666        free(buf);
00667        return NULL;
00668     }
00669 
00670     return buf;
00671 }
00672 
00673 Bool
00674 canna_init(iml_session_t *s, char *user)
00675 {
00676     char **warning = NULL;
00677     char *init_filename;
00678 
00679     init_filename = canna_init_filename(user);
00680     if (init_filename) {
00681        jrKanjiControl(canna_session_context(s), KC_SETINITFILENAME, init_filename);
00682        free(init_filename);
00683     }
00684     jrKanjiControl(canna_session_context(s), KC_INITIALIZE, (char *) &warning);
00685 
00686     if (warning) {
00687        char          **p;
00688 
00689        for (p = warning; *p; p++)
00690            fprintf(stderr, "CannaLE: %s\n", *p);
00691 
00692        return False;
00693     }
00694 
00695     jrKanjiControl(canna_session_context(s), KC_SETAPPNAME, (char *) "CannaLE");
00696 
00697     /* set user info */
00698     if (user) {
00699        jrUserInfoStruct info;
00700 
00701        memset(&info, 0, sizeof (info));
00702        info.uname = user;
00703        jrKanjiControl(canna_session_context(s), KC_SETUSERINFO, (char *)&info);
00704     }
00705 
00706     return True;
00707 }
00708 
00709 IMText*
00710 canna_commit_string(iml_session_t *s, char *buf)
00711 {
00712     IMText *p;
00713     int len = strlen(buf);
00714     
00715     p = canna_string_to_IMText(s, 1, &len, &buf, NULL, NULL);
00716     return p;
00717 }
00718 
00719 IMText*
00720 canna_kakutei(iml_session_t *s)
00721 {
00722     jrKanjiStatusWithValue *pksv;
00723 
00724     pksv = canna_session_status(s);
00725     jrKanjiControl(canna_session_context(s), KC_KAKUTEI, (char*) pksv);
00726     return canna_commit_string(s, pksv->buffer);
00727 }
00728 
00729 void
00730 canna_status_draw(iml_session_t *s)
00731 {
00732     iml_inst *lp;
00733     iml_inst *rrv = NULL;
00734     IMText *p;
00735     CannaLESession *pcls = canna_session_data(s);
00736     char *str;
00737     int len;
00738 
00739     jrKanjiStatusWithValue *pksv;
00740     pksv = canna_session_status(s);
00741 
00742     if (pcls->conversion_start == False) {
00743        canna_status_draw_off(s);
00744        return;
00745     }
00746     if (!pcls->is_canna_initialized) {
00747        if (!jrKanjiControl(canna_session_context(s), KC_QUERYCONNECTION, (char *)0)) {
00748            char *warn = "cannaserver isn't running";
00749 
00750            str = strdup(warn);
00751            len = strlen(str);
00752        } else {
00753            pcls->is_canna_initialized = True;
00754        }
00755     }
00756     if (pcls->is_canna_initialized) {
00757        len = jrKanjiControl(canna_session_context(s), KC_QUERYMAXMODESTR, 0);
00758        str = (unsigned char *) malloc(sizeof (unsigned char) * (len + 1));
00759        jrKanjiControl(canna_session_context(s), KC_QUERYMODE, str);
00760     }
00761 
00762     {
00763        /* Create IMText with feedback. */
00764        int ft1;
00765        ft1 = Canna_Feedback_Normal;
00766        p = canna_string_to_IMText(s, 1, &len, &str, &ft1, NULL);
00767     }
00768     free(str);
00769 
00770     if (!IS_REGION_ACTIVE(s, STATUS)) {
00771         lp = s->If->m->iml_make_status_start_inst(s);
00772         s->If->m->iml_link_inst_tail(&rrv, lp);
00773     }
00774     lp = s->If->m->iml_make_status_draw_inst(s, p);
00775     s->If->m->iml_link_inst_tail(&rrv, lp);
00776     
00777     s->If->m->iml_execute(s, &rrv);
00778 }
00779 
00780 void
00781 canna_preedit_draw(iml_session_t *s)
00782 {
00783     iml_inst *lp;
00784     iml_inst *rrv = NULL;
00785     IMText *p;
00786     jrKanjiStatus *pks = canna_session_status(s)->ks;
00787     int caret_position = 0;
00788 
00789     /* When KanjiStatus is uninited, return immediately. */
00790     if (!pks->echoStr) return;
00791 
00792     if (!IS_REGION_ACTIVE(s, PREEDIT)) {
00793         lp = s->If->m->iml_make_preedit_start_inst(s);
00794         s->If->m->iml_link_inst_tail(&rrv, lp);
00795     }
00796 
00797     {
00798        /* Create IMText with feedbacks.  */
00799        int nb[3], fts[3];
00800        char *strs[3];
00801        nb[0] = pks->revPos;
00802        nb[1] = pks->revLen;
00803        nb[2] = pks->length - nb[0] - nb[1];
00804        fts[0] = Canna_Feedback_Input;
00805        fts[1] = Canna_Feedback_Strong;
00806        fts[2] = Canna_Feedback_Input;
00807        strs[0] = pks->echoStr;
00808        strs[1] = strs[0] + pks->revPos;
00809        strs[2] = strs[1] + pks->revLen;
00810        p = canna_string_to_IMText(s, 3, nb, strs, fts, &caret_position);
00811     }
00812 
00813     lp = s->If->m->iml_make_preedit_draw_inst(s, p);
00814     s->If->m->iml_link_inst_tail(&rrv, lp);
00815     lp = s->If->m->iml_make_preedit_caret_inst(s, caret_position);
00816     s->If->m->iml_link_inst_tail(&rrv, lp);
00817     s->If->m->iml_execute(s, &rrv);
00818 }
00819 
00820 void
00821 canna_aux_start(iml_session_t *s)
00822 {
00823     CannaLESession *pcls = canna_session_data(s);
00824     /*
00825      * IS_REGION_ACTIVE seems not working for AUX
00826     if (!IS_REGION_ACTIVE(s, AUX)) {
00827     */
00828     if (pcls->aux_start == False) {
00829        IMAuxStartCallbackStruct *aux;
00830        iml_inst *lp;
00831 
00832 #ifdef DEBUG
00833        printf("DEBUG: %s activating.\n", __FUNCTION__);
00834 #endif
00835 
00836        aux = (IMAuxStartCallbackStruct *)s->If->m->iml_new(s, sizeof (IMAuxStartCallbackStruct));
00837        memset(aux, 0, sizeof (IMAuxStartCallbackStruct));
00838        aux->aux_name = class_names[0];
00839        lp = s->If->m->iml_make_aux_start_inst(s, aux);
00840        s->If->m->iml_execute(s, &lp);
00841 
00842        pcls->aux_start = True;
00843     }
00844 }
00845 
00846 void
00847 canna_aux_draw(iml_session_t *s, int auxmode, void *data, ...)
00848 {
00849     va_list args;
00850     int i, j, num = 0, *segs = NULL, cid, int_data[INT_END], mode, mmode;
00851     char **ps = NULL, **pstr = NULL;
00852     jrKanjiStatus *pks = canna_session_status(s)->ks;
00853     CannaLESession *pcls = canna_session_data(s);
00854 
00855     ENTER;
00856 
00857     va_start(args, data);
00858 
00859     int_data[INT_AUXMODE] = auxmode;
00860     switch (auxmode) {
00861        case AUX_UPDATE_STATE:
00862            mode = canna_get_current_mode(s);
00863            mmode = canna_get_current_minor_mode(s);
00864 #ifdef DEBUG
00865            printf("*** mode = %d, mmode = %d, old_minor = %d\n", mode, mmode, pcls->old_minor_mode);
00866 #endif
00867            if (pcls->force_not_update_state == 1) {
00868               pcls->force_not_update_state = 0;
00869               goto ensure;
00870            }
00871            if (mode != CANNA_MODE_ExtendMode &&
00872               mode != CANNA_MODE_HexMode &&
00873               mode != CANNA_MODE_KigoMode) {
00874               int_data[INT_STATE] = mode;
00875               if (!pks->gline.line)
00876                   goto ensure;
00877               if (!canna_parse_guideline(s, &num, &ps, &segs, &cid))
00878                   goto ensure;
00879               if (num == 0 && pks->gline.line != NULL && pks->gline.length > 0) {
00880                   num = 1;
00881                   pstr = (char **)malloc(sizeof (char *) * (num + 1));
00882                   pstr[0] = (char *)malloc(sizeof (char *) * (pks->gline.length + 1));
00883                   for (i = 0, j = 0; i < pks->gline.length; i++) {
00884                      if (pks->gline.line[i] == 0)
00885                          continue;
00886                      pstr[0][j++] = pks->gline.line[i];
00887                   }
00888                   pstr[0][j] = 0;
00889               } else {
00890                   num = 0;
00891               }
00892               pcls->old_minor_mode = mmode;
00893            } else {
00894               if (mmode != CANNA_MODE_ExtendMode &&
00895                   mmode != CANNA_MODE_TourokuMode &&
00896                   mmode != CANNA_MODE_DeleteDicMode &&
00897                   mmode != CANNA_MODE_TourokuHinshiMode &&
00898                   mmode == pcls->old_minor_mode) {
00899                   /* don't send this event */
00900                   pcls->old_minor_mode = mmode;
00901                   if (pcls->update_state == 0)
00902                      goto ensure;
00903                   pcls->update_state = 0;
00904               } else {
00905                   if (((mmode == CANNA_MODE_EmptyMode ||
00906                       mmode == CANNA_MODE_TankouhoMode) &&
00907                       pcls->old_minor_mode == CANNA_MODE_TourokuMode) ||
00908                      (mmode == CANNA_MODE_EmptyMode &&
00909                       pcls->old_minor_mode == CANNA_MODE_DeleteDicMode)) {
00910                      /* don't hide the aux window */
00911                      mmode = pcls->old_minor_mode;
00912                   } else if (mmode == CANNA_MODE_IchiranMode &&
00913                             pcls->old_minor_mode == CANNA_MODE_TourokuMode) {
00914                      /* don't update the aux window either */
00915                      goto ensure;
00916                   } else {
00917                      pcls->old_minor_mode = mmode;
00918                   }
00919                   pcls->update_state = 0;
00920               }
00921               int_data[INT_STATE] = mmode;
00922               int_data[INT_CURPOS] = canna_get_current_candidate_position(s);
00923               int_data[INT_CANDCOUNT] = canna_get_candidate_count(s);
00924 
00925               /*
00926                * ensure that current cursor position is the beginning of
00927                * items in the server after storing current position.
00928                */
00929               /*
00930                * CAUTION!! don't send invalid key for the current state.
00931                * it causes the status string breakage.
00932                */
00933               if (mmode != CANNA_MODE_TourokuMode &&
00934                   int_data[INT_CANDCOUNT] > 0) {
00935                   char buf[CANNA_COMMIT_STRING_BUFSIZE + 1];
00936                   int size = CANNA_COMMIT_STRING_BUFSIZE;
00937 
00938                   jrKanjiString(canna_session_context(s),
00939                               CANNA_KEY_Home, buf, size, pks);
00940               }
00941               int_data[INT_BEGINPOS] = canna_get_current_candidate_position(s);
00942 
00943 #ifdef DEBUG
00944               printf("*** pos %d(%d)/%d(%d)/%d\n",
00945                      int_data[INT_BEGINPOS],
00946                      canna_get_current_candidate_position(s),
00947                      int_data[INT_CURPOS],
00948                      canna_get_candidate_count(s),
00949                      int_data[INT_CANDCOUNT]);
00950 #endif
00951 
00952               switch (mmode) {
00953                   case CANNA_MODE_HexMode:
00954                   case CANNA_MODE_ChangingServerMode:
00955                   case CANNA_MODE_TourokuMode:
00956                   message:
00957                      if (!pks->gline.line)
00958                          goto ensure;
00959 
00960                      /* DEBUG --> */
00961                      if (!canna_parse_guideline(s, &num, &ps, &segs, &cid))
00962                          goto ensure;
00963                      /* <-- DEBUG */
00964 
00965                      num = 1;
00966                      pstr = (char **)malloc(sizeof (char *) * (num + 1));
00967                      pstr[0] = (char *)malloc(sizeof (char *) * (pks->gline.length + 1));
00968                      /*
00969                       * sigh, need to skip null characters and copies the readable characters to
00970                       * the buffer.
00971                       */
00972                      for (i = 0, j = 0; i < pks->gline.length; i++) {
00973                          if (pks->gline.line[i] == 0)
00974                             continue;
00975                          pstr[0][j++] = pks->gline.line[i];
00976                      }
00977                      pstr[0][j] = 0;
00978                      break;
00979                   case CANNA_MODE_TourokuHinshiMode:
00980                   case CANNA_MODE_DeleteDicMode:
00981                   case CANNA_MODE_TourokuDicMode:
00982                      if (int_data[INT_CANDCOUNT] == 0)
00983                          goto message;
00984                   case CANNA_MODE_ExtendMode:
00985                   case CANNA_MODE_MountDicMode:
00986                      if (!pks->gline.line)
00987                          goto ensure;
00988                      if (!canna_parse_guideline(s, &num, &ps, &segs, &cid))
00989                          goto ensure;
00990                      num *= 2;
00991                      pstr = (char **)malloc(sizeof (char *) * (num + 1));
00992                      for (i = 0; i < num; i++) {
00993                          pstr[i] = (char *)malloc(sizeof (char) * (segs[i] + 1));
00994                          strncpy(pstr[i], ps[i], segs[i]);
00995                          pstr[i][segs[i]] = 0;
00996                      }
00997                      break;
00998                   default:
00999                      num = 0;
01000                      break;
01001               }
01002            }
01003            break;
01004        case AUX_UPDATE_KEY:
01005            {
01006               IMKeyListEvent *kev = (IMKeyListEvent *)data;
01007               IMKeyEventStruct *k = (IMKeyEventStruct *)kev->keylist;
01008               int ch = va_arg(args, int);
01009 
01010               int_data[INT_STATE] = canna_get_current_minor_mode(s);
01011               int_data[INT_KEYCODE] = k->keyCode;
01012               int_data[INT_KEYMOD] = k->modifier;
01013               int_data[INT_TRANSLATEDCODE] = ch;
01014               int_data[INT_CANDCOUNT] = canna_get_candidate_count(s);
01015            }
01016            break;
01017        case AUX_FORCE_UPDATE_STATE:
01018            pcls->update_state = 1;
01019            canna_aux_draw(s, AUX_UPDATE_STATE, NULL);
01020            goto ensure;
01021        case AUX_FORCE_NOT_UPDATE_STATE:
01022            pcls->force_not_update_state = 1;
01023            goto ensure;
01024        case AUX_FOCUS_CHANGE:
01025            int_data[INT_STATE] = (int)data;
01026            if (int_data[INT_STATE] == 0) {
01027               /* going to unfocus */
01028               canna_aux_draw(s, AUX_FORCE_SAVE_STATE, NULL);
01029            } else {
01030               /* going to focus */
01031               canna_aux_draw(s, AUX_FORCE_UPDATE_STATE, NULL);
01032            }
01033            break;
01034        case AUX_FORCE_SAVE_STATE:
01035            int_data[INT_STATE] = pcls->old_minor_mode;
01036            break;
01037     }
01038 
01039     aux_draw(s, INT_END, int_data, num, pstr);
01040 
01041 ensure:
01042     for (i = 0; i < num; i++) {
01043        if (pstr[i] != NULL)
01044            free(pstr[i]);
01045     }
01046     if (pstr != NULL)
01047        free(pstr);
01048     if (ps != NULL)
01049        free(ps);
01050     if (segs != NULL)
01051        free(segs);
01052     va_end(args);
01053 
01054     LEAVE;
01055 }
01056 
01057 void
01058 aux_draw(iml_session_t *s,
01059         int            count_integers,
01060         int           *integers,
01061         int            count_strings,
01062         char         **strings)
01063 {
01064     iml_inst *lp;
01065     IMAuxDrawCallbackStruct *auxdraw;
01066     int i;
01067     size_t len = 7;
01068     IMText *Its, *It;
01069     CannaLESession *pcls = canna_session_data(s);
01070 
01071     /*
01072      * IS_REGION_ACTIVE seems to not working for AUX
01073     if (!IS_REGION_ACTIVE(s, AUX)) {
01074     */
01075     if (pcls->aux_start == False) {
01076        /* canna_aux_start() should be called before calling aux_draw() */
01077        return;
01078     }
01079 
01080     auxdraw = (IMAuxDrawCallbackStruct *)s->If->m->iml_new(s, sizeof (IMAuxDrawCallbackStruct));
01081     memset(auxdraw, 0, sizeof (IMAuxDrawCallbackStruct));
01082     auxdraw->aux_name = class_names[0];
01083     auxdraw->count_integer_values = count_integers;
01084     if (count_integers) {
01085        auxdraw->integer_values = (int *)s->If->m->iml_new(s, sizeof (int) * count_integers);
01086        for (i = 0; i < count_integers; i++) {
01087            auxdraw->integer_values[i] = integers[i];
01088        }
01089     }
01090 
01091     auxdraw->count_string_values = count_strings;
01092     if (count_strings > 0) {
01093        auxdraw->string_values = Its = (IMText *)s->If->m->iml_new(s, sizeof (IMText) * count_strings);
01094 
01095        for (i = 0, It = Its; i < count_strings; i++, It++) {
01096            memset(It, 0, sizeof (IMText));
01097            It->encoding = UTF16_CODESET;
01098            len = UTFCHAR_buffer_size(strlen(strings[i]) + 1);
01099            It->text.utf_chars = canna_string_to_UTFCHAR(strings[i]);
01100            It->char_length = len;
01101 
01102 #ifdef DEBUG
01103            printf("*** '%s'\n", strings[i]);
01104            printf("*** '%s' (%d)\n", (char *)It->text.utf_chars, len);
01105 #endif
01106        }
01107     }
01108 
01109     lp = s->If->m->iml_make_aux_draw_inst(s, auxdraw);
01110     s->If->m->iml_execute(s, &lp);
01111 }
01112 
01113 void
01114 canna_status_draw_off(iml_session_t *s)
01115 {
01116     IMText *p;
01117     iml_inst *lp;
01118     iml_inst *rrv = NULL;
01119     char *str = "";
01120     int len = strlen(str);
01121     int ft1 = Canna_Feedback_Normal;
01122 
01123     p = canna_string_to_IMText(s, 1, &len, &str, &ft1, NULL);
01124     if (!IS_REGION_ACTIVE(s, STATUS)) {
01125        lp = s->If->m->iml_make_status_start_inst(s);
01126        s->If->m->iml_link_inst_tail(&rrv, lp);
01127     }
01128     lp = s->If->m->iml_make_status_draw_inst(s, p);
01129     s->If->m->iml_link_inst_tail(&rrv, lp);
01130     s->If->m->iml_execute(s, &rrv);
01131 }
01132 
01133 void
01134 canna_preedit_done(iml_session_t *s)
01135 {
01136     if (IS_REGION_ACTIVE(s, PREEDIT)) {
01137        iml_inst *lp;
01138         lp = s->If->m->iml_make_preedit_done_inst(s);
01139        s->If->m->iml_execute(s, &lp);
01140     }
01141 }
01142 
01143 void
01144 canna_aux_done(iml_session_t *s)
01145 {
01146     CannaLESession *pcls = canna_session_data(s);
01147 
01148     /* hide aux window */
01149     canna_aux_draw(s, AUX_UPDATE_STATE, NULL);
01150     /*
01151      * IS_REGION_ACTIVE seems to not working for AUX
01152     if (IS_REGION_ACTIVE(s, AUX)) {
01153     */
01154     if (pcls->aux_start == True) {
01155        iml_inst *lp;
01156        IMAuxDoneCallbackStruct *aux;
01157 
01158 #ifdef DEBUG
01159        printf("DEBUG: %s is deactivating\n", __FUNCTION__);
01160 #endif
01161 
01162        aux = (IMAuxDoneCallbackStruct *)s->If->m->iml_new(s, sizeof (IMAuxDoneCallbackStruct));
01163        memset(aux, 0, sizeof (IMAuxDoneCallbackStruct));
01164        aux->aux_name = class_names[0];
01165        lp = s->If->m->iml_make_aux_done_inst(s, aux);
01166        s->If->m->iml_execute(s, &lp);
01167 
01168        pcls->aux_start = False;
01169     }
01170 }
01171 
01172 /*
01173   Caution!!!
01174   This part assumes the structure of guidline given by canna UI
01175   library.  It parses guideline string without any protocol on it.
01176   Therefore, it may not work with the future version of canna
01177   UI library!
01178 */
01179 Bool
01180 canna_parse_guideline(iml_session_t *s, int *pnum,
01181                     char ***psegs,
01182                     int **pnb,
01183                     int *pcurrent)
01184 {
01185     jrKanjiStatus *pks = canna_session_status(s)->ks;
01186     unsigned char *str = pks->gline.line;
01187     unsigned char *p, *st;
01188     int i, idx, tot, delimiterp;
01189 
01190 #ifdef DEBUG
01191     char linestr[1024];
01192 
01193     printf("*** length = %d\n", pks->gline.length);
01194     printf("*** revPos = %d\n", pks->gline.revPos);
01195     printf("*** revLen = %d\n", pks->gline.revLen);
01196     memcpy(linestr, pks->gline.line, (pks->gline.length > 1024 ? 1024 : pks->gline.length));
01197     printf("*** line = '%s'\n", linestr);
01198     printf("*** line(Hex) = '");
01199     for (i = 0; i < pks->gline.length; i++) {
01200        printf("%02X:", linestr[i] & 0xFF);
01201     }
01202     printf("\n");
01203 #endif
01204     tot = 0;
01205     for (p = str, st = NULL;*p;p = CANNA_NEXT_CHAR(p)) {
01206        delimiterp = CANNA_GUIDELINE_DELIMITER_P(p);
01207        if (st && delimiterp) {
01208            tot++;
01209            st = NULL;
01210        }else if (!st && !delimiterp) {
01211            st = p;
01212        }
01213     }
01214     *pnum = tot;
01215     *pcurrent = 0;
01216     *psegs = (char**) malloc(sizeof(unsigned char*) * tot * 2);
01217     *pnb = (int*) malloc(sizeof(int) * tot * 2);
01218     for (p = str, i = 0, idx = 0, st = NULL;
01219         (idx < tot);p = CANNA_NEXT_CHAR(p)) {
01220        delimiterp = CANNA_GUIDELINE_DELIMITER_P(p);
01221        if (st && delimiterp) {
01222            /* the size of the value */
01223            (*pnb)[i] = (p - st);
01224            i++;
01225            idx++;
01226            st = NULL;
01227        }else if (!st && !delimiterp) {
01228            /* label */
01229            (*psegs)[i] = st = p;
01230            (*pnb)[i] = CANNA_NEXT_CHAR(p) - p;
01231            i++;
01232            if (pks->gline.revPos == (p - str))
01233               *pcurrent = idx;
01234            /* value */
01235            (*psegs)[i] = st = CANNA_NEXT_CHAR(p);
01236        }
01237     }
01238 #ifdef DEBUG
01239     for (i = 0;i < (tot * 2);i++) {
01240        memcpy(linestr, (*psegs)[i], (*pnb)[i]);
01241        linestr[(*pnb)[i]] = '\0';
01242        fprintf(stderr, "Seg(%d):'%s'\n", i, linestr);
01243     }
01244 #endif
01245     return True;
01246 }
01247 
01248 int
01249 canna_get_current_candidate_position(iml_session_t *s)
01250 {
01251     jrKanjiStatus *pks = canna_session_status(s)->ks;
01252     unsigned char *str = pks->gline.line;
01253     unsigned char *p, linestr[1024];
01254     int i;
01255 
01256     if ((p = rindex(str, '/')) == NULL) {
01257        return 0;
01258     }
01259     i = 0;
01260     while (*p--) {
01261        if (*p >= '0' && *p <= '9') {
01262            i++;
01263        } else {
01264            p++;
01265            break;
01266        }
01267     }
01268     strncpy(linestr, p, i);
01269     linestr[i] = 0;
01270 
01271     return atoi(linestr);
01272 }
01273 
01274 int
01275 canna_get_candidate_count(iml_session_t *s)
01276 {
01277     jrKanjiStatus *pks = canna_session_status(s)->ks;
01278     unsigned char *str = pks->gline.line;
01279     unsigned char *p, linestr[1024];
01280     int i;
01281 
01282     if ((p = rindex(str, '/')) == NULL) {
01283        return 0;
01284     }
01285     i = 0;
01286     while (*p++) {
01287        if (*p >= '0' && *p <= '9') {
01288            linestr[i] = *p;
01289            i++;
01290        } else {
01291            break;
01292        }
01293     }
01294     linestr[i] = 0;
01295 
01296     return atoi(linestr);
01297 }
01298 
01299 void
01300 canna_start_lookup_choice(iml_session_t *s,
01301                        iml_inst **prrv, int num)
01302 {
01303     if (!IS_REGION_ACTIVE(s, LOOKUP)) {
01304        iml_inst *lp;
01305        IMLookupStartCallbackStruct *start;
01306         start = ((IMLookupStartCallbackStruct *)
01307                s->If->m->iml_new(s, sizeof(IMLookupStartCallbackStruct)));
01308        start->whoIsMaster = IMIsMaster;
01309         start->IMPreference = (LayoutInfo *) s->If->m->iml_new(s, sizeof(LayoutInfo));
01310        memset(start->IMPreference, 0, sizeof(LayoutInfo));
01311 
01312         start->IMPreference->choice_per_window = num;
01313         start->IMPreference->ncolumns = 1;
01314         start->IMPreference->nrows = num;
01315         start->IMPreference->drawUpDirection = DrawUpHorizontally;
01316         start->IMPreference->whoOwnsLabel = IMOwnsLabel;
01317         start->CBPreference = NULL;
01318 
01319         lp = s->If->m->iml_make_lookup_start_inst(s, start);
01320        s->If->m->iml_link_inst_tail(prrv, lp);
01321     }
01322 }
01323 
01324 void
01325 canna_show_lookup_choice(iml_session_t *s)
01326 {
01327     int num;
01328     iml_inst *lp;
01329     iml_inst *rrv = NULL;
01330     IMLookupDrawCallbackStruct *draw;
01331     jrKanjiStatus *pks = canna_session_status(s)->ks;
01332 
01333     /* When KanjiStatus is uninited, return immediately. */
01334     if (!pks->gline.line) return;
01335 
01336     draw = ((IMLookupDrawCallbackStruct *)
01337            s->If->m->iml_new(s, sizeof(IMLookupDrawCallbackStruct)));
01338     memset(draw, 0, sizeof(IMLookupDrawCallbackStruct));
01339     draw->title = UTFCHAR_to_IMText(s, lookup_choice_title);
01340 
01341     /* set choices */
01342     {
01343        int i, cid;
01344        char **ps;
01345        int *segs;
01346         IMText *pvt;
01347         IMText *plt;
01348        int max_len = 0;
01349        
01350        if (!canna_parse_guideline(s, &num, &ps, &segs, &cid))
01351            return;
01352 
01353        if (num <= 0) {
01354            free(ps);
01355            free(segs);
01356            return;
01357        }
01358        draw->index_of_first_candidate = 0;
01359        draw->index_of_last_candidate = num - 1;
01360        draw->n_choices = num;
01361        draw->choices = ((IMChoiceObject *)
01362                       s->If->m->iml_new(s, num * sizeof(IMChoiceObject)));
01363        memset(draw->choices, 0, num * sizeof(IMChoiceObject));
01364        draw->index_of_current_candidate = cid;
01365 
01366        for (cid = 0, i = 0;i < num;i++) {
01367            plt = draw->choices[i].label
01368               = canna_string_to_IMText(s, 1, &segs[cid], &ps[cid], NULL, NULL);
01369            cid++;
01370            pvt = draw->choices[i].value
01371               = canna_string_to_IMText(s, 1, &segs[cid], &ps[cid], NULL, NULL);
01372            cid++;
01373            if (max_len < pvt->char_length)
01374               max_len = pvt->char_length;
01375            if (max_len < plt->char_length)
01376               max_len = plt->char_length;
01377        }
01378        free(ps);
01379        free(segs);
01380        draw->max_len = max_len;
01381 #if 0
01382        fprintf(stderr, "draw->index_of_first_candidate=%x\n",
01383               draw->index_of_first_candidate);
01384        fprintf(stderr, "draw->index_of_last_candidate=%x\n",
01385               draw->index_of_last_candidate);
01386        fprintf(stderr, "draw->n_choices=%x\n",
01387               draw->n_choices);
01388        fprintf(stderr, "draw->choices=%x\n",
01389               draw->choices);
01390        fprintf(stderr, "draw->choices->label=%x\n",
01391               draw->choices->label);
01392        fprintf(stderr, "draw->max_len=%x\n", max_len);
01393        fprintf(stderr, "draw->index_of_current_candidate=%x\n",
01394               draw->index_of_current_candidate);
01395 #endif
01396     }
01397     canna_start_lookup_choice(s, &rrv, num);
01398     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01399     s->If->m->iml_link_inst_tail(&rrv, lp);
01400     s->If->m->iml_execute(s, &rrv);
01401 }
01402 
01403 void
01404 canna_lookup_choice_done(iml_session_t *s)
01405 {
01406     if (IS_REGION_ACTIVE(s, LOOKUP)) {
01407        iml_inst *lp;
01408         lp = s->If->m->iml_make_lookup_done_inst(s);
01409        s->If->m->iml_execute(s, &lp);
01410     }
01411 }
01412 
01413 void
01414 canna_make_conversion_off(iml_session_t *s)
01415 {
01416     CannaLESession *pcls = canna_session_data(s);
01417 
01418     if (pcls->conversion_start == True) {
01419        iml_inst *lp;
01420 
01421        pcls->conversion_start = False;
01422        canna_change_mode(s, CANNA_MODE_AlphaMode);
01423        canna_status_draw(s);
01424        canna_status_draw_off(s);
01425        canna_lookup_choice_done(s);
01426        canna_preedit_done(s);
01427        canna_aux_done(s);
01428 
01429         lp = s->If->m->iml_make_end_conversion_inst(s);
01430        s->If->m->iml_execute(s, &lp);
01431     }
01432 }
01433 
01434 void
01435 canna_make_conversion_on(iml_session_t  *s)
01436 {
01437     CannaLESession *pcls = canna_session_data(s);
01438 
01439     if (pcls->conversion_start == False) {
01440        iml_inst *lp;
01441 
01442         lp = s->If->m->iml_make_start_conversion_inst(s);
01443        s->If->m->iml_execute(s, &lp);
01444 
01445        pcls->conversion_start = True;
01446        if (canna_get_current_mode(s) == CANNA_MODE_AlphaMode) {
01447            canna_change_mode(s, CANNA_MODE_HenkanMode);
01448        }
01449        canna_status_draw(s);
01450        canna_aux_start(s);
01451     }
01452 }
01453 
01454 int
01455 canna_translate_keyevent(IMKeyListEvent *kev)
01456 {
01457     IMKeyEventStruct *k = (IMKeyEventStruct *) kev->keylist;
01458     fprintf(stderr, "iml_session_t() keycode=%x,keychar=%x, state=%x\n",
01459            k->keyCode, k->keyChar, k->modifier);
01460 
01461     switch(k->keyCode) {
01462     case IM_VK_UP:
01463        if (k->modifier & IM_CTRL_MASK) {
01464            return CANNA_KEY_Cntrl_Up;
01465        } else if (k->modifier & IM_SHIFT_MASK) {
01466            return CANNA_KEY_Shift_Up;
01467        }
01468        return  CANNA_KEY_Up;
01469 
01470     case IM_VK_DOWN:
01471        if (k->modifier & IM_CTRL_MASK) {
01472            return CANNA_KEY_Cntrl_Down;
01473        } else if (k->modifier & IM_SHIFT_MASK) {
01474            return CANNA_KEY_Shift_Down;
01475        }
01476        return  CANNA_KEY_Down;
01477 
01478     case IM_VK_LEFT:
01479        if (k->modifier & IM_CTRL_MASK) {
01480            return CANNA_KEY_Cntrl_Left;
01481        } else if (k->modifier & IM_SHIFT_MASK) {
01482            return CANNA_KEY_Shift_Left;
01483        }
01484        return  CANNA_KEY_Left;
01485 
01486     case IM_VK_RIGHT:
01487        if (k->modifier & IM_CTRL_MASK) {
01488            return CANNA_KEY_Cntrl_Right;
01489        } else if (k->modifier & IM_SHIFT_MASK) {
01490            return CANNA_KEY_Shift_Right;
01491        }
01492        return  CANNA_KEY_Right;
01493 
01494     case IM_VK_INSERT:
01495        return CANNA_KEY_Insert;
01496 
01497     case IM_VK_PAGE_UP:
01498        return CANNA_KEY_Rolldown;
01499 
01500     case IM_VK_PAGE_DOWN:
01501        return CANNA_KEY_Rollup;
01502 
01503     case IM_VK_HOME:
01504        return CANNA_KEY_Home;
01505 
01506     case IM_VK_HELP:
01507        return CANNA_KEY_Help;
01508 
01509     case IM_VK_F1:
01510     case IM_VK_F2:
01511     case IM_VK_F3:
01512     case IM_VK_F4:
01513     case IM_VK_F5:
01514     case IM_VK_F6:
01515     case IM_VK_F7:
01516     case IM_VK_F8:
01517     case IM_VK_F9:
01518     case IM_VK_F10:
01519        return CANNA_KEY_F1 + k->keyCode - IM_VK_F1;
01520 
01521     case IM_VK_CONVERT: /* XFER */
01522        if (k->modifier & IM_CTRL_MASK) {
01523            return CANNA_KEY_Cntrl_Xfer;
01524        } else if (k->modifier & IM_SHIFT_MASK) {
01525            return CANNA_KEY_Shift_Xfer;
01526        }
01527        return CANNA_KEY_Xfer;
01528 
01529     case IM_VK_NONCONVERT: /* NFER */
01530        if (k->modifier & IM_CTRL_MASK) {
01531            return CANNA_KEY_Cntrl_Nfer;
01532        } else if (k->modifier & IM_SHIFT_MASK) {
01533            return CANNA_KEY_Shift_Nfer;
01534        }
01535        return CANNA_KEY_Nfer;
01536 
01537     case IM_VK_ENTER:
01538        return 0x0D;
01539 
01540     case IM_VK_BACK_SPACE:
01541        return 0x08;
01542 
01543     case IM_VK_DELETE:
01544        return 0x04;
01545 
01546     case IM_VK_CLEAR:
01547        return 0x0B;
01548 
01549     case IM_VK_PAUSE:
01550        return 0x13;
01551 
01552     case IM_VK_SCROLL_LOCK:
01553        return 0x14;
01554 
01555     case IM_VK_ESCAPE:
01556        return 0x1B;
01557 
01558     default:
01559        if (k->modifier & IM_CTRL_MASK) {
01560            if (k->keyCode >= IM_VK_A && k->keyCode <= IM_VK_CLOSE_BRACKET) {
01561               return 0x01 + k->keyCode - IM_VK_A;
01562            }
01563            if (k->keyCode == IM_VK_CIRCUMFLEX) {
01564               return 0x1E;
01565            }
01566            if (k->keyCode == IM_VK_SLASH) {
01567               return 0x1F;
01568            }
01569            /* no process any Ctrl characters here */
01570            break;
01571        }
01572        if ((k->keyChar > 0)
01573            && (k->keyChar < 0xFFFF)) {
01574            /* Should we translate it to EUC? */
01575            return k->keyChar;
01576        }
01577     }
01578 
01579     fprintf(stderr, "translation failed:keycode=%x,keychar=%x, state=%x\n",
01580            k->keyCode, k->keyChar, k->modifier);
01581     return 0;
01582 }
01583 
01584 static Bool
01585 process_keyevent(iml_session_t *s, int ch)
01586 {
01587     int size = CANNA_COMMIT_STRING_BUFSIZE, n;
01588     jrKanjiStatus *pks = canna_session_status(s)->ks;
01589     char buf[CANNA_COMMIT_STRING_BUFSIZE + 1];
01590     int mode;
01591 
01592     n = jrKanjiString(canna_session_context(s),
01593                     ch, buf, size, pks);
01594     buf[n] = '\0';
01595 
01596     /* if there is no preedit characters and no related characters,
01597      * shouldn't process it.
01598      */
01599     if (n == 1 && (pks->info & KanjiThroughInfo) && pks->length == 0) {
01600        pks->info &= ~KanjiThroughInfo;
01601        return False;
01602     }
01603     if (n > 0) {
01604        IMText *p;
01605 
01606        pks->info &= ~KanjiThroughInfo;
01607        p = canna_commit_string(s, buf);
01608        send_commit(s, p, 1);
01609     }
01610     if (pks->length >= 0)
01611        canna_preedit_draw(s);
01612     if (pks->info & KanjiModeInfo)
01613        canna_status_draw(s);
01614 
01615     /* always call canna_aux_draw() to hide the aux window even if it's not necessary */
01616     canna_aux_draw(s, AUX_UPDATE_STATE, NULL);
01617     mode = canna_get_current_mode(s);
01618     if (mode == CANNA_MODE_ExtendMode || mode == CANNA_MODE_HexMode) {
01619        switch (canna_get_current_minor_mode(s)) {
01620            case CANNA_MODE_ExtendMode:
01621            case CANNA_MODE_HexMode:
01622            case CANNA_MODE_TourokuMode:
01623            case CANNA_MODE_MountDicMode:
01624            case CANNA_MODE_ChangingServerMode:
01625            case CANNA_MODE_TankouhoMode:
01626            case CANNA_MODE_TourokuHinshiMode:
01627            case CANNA_MODE_DeleteDicMode:
01628            case CANNA_MODE_TourokuDicMode:
01629               /* don't use lookup */
01630               /* enforce to close the lookup window, when the state gets back from the lookup window say */
01631               canna_lookup_choice_done(s);
01632               break;
01633            default:
01634               goto use_lookup;
01635        }
01636     } else {
01637 use_lookup:
01638        if (pks->info & KanjiGLineInfo) {
01639            if (pks->gline.length > 0)
01640               canna_show_lookup_choice(s);
01641            else
01642               canna_lookup_choice_done(s);
01643        }
01644     }
01645 
01646     return True;
01647 }
01648 
01649 static int
01650 canna_swap_keyevent(iml_session_t *s, int ch)
01651 {
01652     int mode = canna_get_current_minor_mode(s);
01653     int flag = 0;
01654     int retval = ch;
01655 
01656     switch (mode) {
01657        case CANNA_MODE_KigoMode:
01658        case CANNA_MODE_IchiranMode:
01659        case CANNA_MODE_BushuMode:
01660        case CANNA_MODE_RussianMode:
01661        case CANNA_MODE_GreekMode:
01662        case CANNA_MODE_LineMode:
01663            flag = 1;
01664            break;
01665     }
01666     if (flag == 1) {
01667        switch (ch) {
01668            case CANNA_KEY_Up:
01669               retval = CANNA_KEY_Left;
01670               break;
01671            case CANNA_KEY_Shift_Up:
01672               retval = CANNA_KEY_Shift_Left;
01673               break;
01674            case CANNA_KEY_Cntrl_Up:
01675               retval = CANNA_KEY_Cntrl_Left;
01676               break;
01677            case CANNA_KEY_Down:
01678               retval = CANNA_KEY_Right;
01679               break;
01680            case CANNA_KEY_Shift_Down:
01681               retval = CANNA_KEY_Shift_Right;
01682               break;
01683            case CANNA_KEY_Cntrl_Down:
01684               retval = CANNA_KEY_Cntrl_Right;
01685               break;
01686            case CANNA_KEY_Left:
01687               retval = CANNA_KEY_Up;
01688               break;
01689            case CANNA_KEY_Shift_Left:
01690               retval = CANNA_KEY_Shift_Up;
01691               break;
01692            case CANNA_KEY_Cntrl_Left:
01693               retval = CANNA_KEY_Cntrl_Up;
01694               break;
01695            case CANNA_KEY_Right:
01696               retval = CANNA_KEY_Down;
01697               break;
01698            case CANNA_KEY_Shift_Right:
01699               retval = CANNA_KEY_Shift_Down;
01700               break;
01701            case CANNA_KEY_Cntrl_Right:
01702               retval = CANNA_KEY_Cntrl_Down;
01703               break;
01704        }
01705     }
01706 
01707     return retval;
01708 }
01709 
01710 void
01711 canna_process_keyevent(iml_session_t *s, IMKeyListEvent *kev)
01712 {
01713     int ch, mode;
01714 
01715     ch = canna_translate_keyevent(kev);
01716     ch = canna_swap_keyevent(s, ch);
01717 
01718     /* if current mode needs the aux support, don't commit the keyevent to Canna.
01719        in this case, all of keyevent is handled via aux */
01720     mode = canna_get_current_mode(s);
01721     if (mode == CANNA_MODE_ExtendMode || mode == CANNA_MODE_HexMode) {
01722        switch (canna_get_current_minor_mode(s)) {
01723            case CANNA_MODE_ExtendMode:
01724            case CANNA_MODE_HexMode:
01725            case CANNA_MODE_TourokuMode:
01726            case CANNA_MODE_MountDicMode:
01727            case CANNA_MODE_ChangingServerMode:
01728            case CANNA_MODE_TourokuHinshiMode:
01729            case CANNA_MODE_DeleteDicMode:
01730            case CANNA_MODE_TourokuDicMode:
01731               /* process the keyevent via aux */
01732               canna_aux_draw(s, AUX_UPDATE_KEY, kev, ch);
01733               break;
01734            default:
01735               goto try_to_process;
01736        }
01737     } else {
01738 try_to_process:
01739        if (ch) {
01740            if (!process_keyevent(s, ch))
01741               goto no_process;
01742        } else {
01743 no_process:;
01744            /* I don't process this keyevent.  Return it. */
01745            iml_inst *lp;
01746            lp = s->If->m->iml_make_keypress_inst(s, ((IMKeyEventStruct *)
01747                                             kev->keylist));
01748            s->If->m->iml_execute(s, &lp);
01749        }
01750     }
01751     return;
01752 }
01753 
01754 void
01755 canna_process_auxevent (iml_session_t *s, IMAuxDrawCallbackStruct *aux)
01756 {
01757 #ifdef DEBUG
01758     printf ("*** aux_name=%s\n", aux->aux_name);
01759     printf ("*** count_integer_values=%d\n", aux->count_integer_values);
01760     printf ("*** count_string_values=%d\n", aux->count_string_values);
01761     if (aux->string_values != NULL)
01762        printf ("*** string_values = %s\n", (char *)aux->string_values->text.utf_chars);
01763     printf ("*** keycode = %d\n", aux->integer_values[INT_KEYCODE]);
01764     printf ("*** modifier = %d\n", aux->integer_values[INT_KEYMOD]);
01765     printf ("*** translated = %d\n", aux->integer_values[INT_TRANSLATEDCODE]);
01766 #endif
01767 
01768     if (aux->count_integer_values > 0) {
01769        switch(aux->integer_values[INT_AUXMODE]) {
01770            case AUX_UPDATE_KEY:
01771               if (aux->integer_values[INT_TRANSLATEDCODE] > 0)
01772                   process_keyevent(s, aux->integer_values[INT_TRANSLATEDCODE]);
01773               break;
01774            case AUX_FORCE_UPDATE_STATE:
01775            case AUX_FORCE_NOT_UPDATE_STATE:
01776               canna_aux_draw(s, aux->integer_values[INT_AUXMODE], NULL);
01777               break;
01778            default:
01779               break;
01780        }
01781     }
01782 }
01783 
01784 /*
01785   IF offer.
01786 */
01787 
01788 void
01789 if_GetIfInfo(IMArgList args, int num_args)
01790 {
01791     int i;
01792     for (i = 0; i < num_args; i++, args++) {
01793         switch (args->id) {
01794        case IF_VERSION:
01795            args->value = (IMArgVal) "1.2";
01796            break;
01797        case IF_METHOD_TABLE:
01798            args->value = (IMArgVal) &canna_methods;
01799            break;
01800        case IF_LE_NAME:
01801            args->value = (IMArgVal) &lename;
01802            break;
01803        case IF_SUPPORTED_LOCALES:
01804            args->value = (IMArgVal) &locales;
01805            break;
01806        case IF_SUPPORTED_OBJECTS:
01807            if (!objects)
01808               init_objects(); /* FIXME causes memory leak */
01809            args->value = (IMArgVal) objects;
01810            break;
01811        case IF_NEED_THREAD_LOCK:
01812            args->value = (IMArgVal) True;
01813            break;
01814        default:
01815            break;
01816        }
01817     }
01818 }
01819 
01820 /*
01821   IFs
01822 */
01823 
01824 Bool
01825 if_canna_OpenIF(iml_if_t *If)
01826 {
01827     int st;
01828 
01829     st = csconv_status(); 
01830     if (st == CSC_UNLOADED) {
01831        setup_csconv();
01832     } else if (st == CSC_FAILED) {
01833        return False;
01834     }
01835 
01836     return True;
01837 }
01838 
01839 Bool
01840 if_canna_CloseIF(iml_if_t *If)
01841 {
01842 
01843     int st = csconv_status();
01844 
01845     if (st == CSC_LOADED) {
01846         csc_close(csconv_cd);
01847         dlclose(csc_handle);
01848 
01849         csc_handle =  NULL;
01850         csc_open = NULL;
01851         csc_conv = NULL;
01852         csc_close = NULL;
01853         csc_open_locale = NULL;
01854         csconv_cd = NULL;
01855     }
01856     return True;
01857 }
01858 
01859 Bool
01860 if_canna_GetIFValue(iml_if_t *If, IMArgList args, int num_args)
01861 {
01862     return True;
01863 }
01864 
01865 Bool
01866 if_canna_SetIFValue(iml_if_t *If, IMArgList args, int num_args)
01867 {
01868     return True;
01869 }
01870 
01871 Bool
01872 if_canna_OpenDesktop(iml_desktop_t * desktop,
01873                    IMArgList args,
01874                    int num_args)
01875 {
01876     CannaLEDesktop *d;
01877 
01878     d = (CannaLEDesktop *) malloc(sizeof (CannaLEDesktop));
01879     memset(d, 0, sizeof(CannaLEDesktop));
01880     d->drop_priv = canna_drop_privilege(desktop->user_name);
01881     desktop->specific_data = (void *) d;
01882 
01883     canna_context_id_counter = 1;
01884 
01885     return True;
01886 }
01887 
01888 Bool
01889 if_canna_CloseDesktop(iml_desktop_t * desktop)
01890 {
01891     CannaLEDesktop *d = (CannaLEDesktop *) desktop->specific_data;
01892 
01893     free(d);
01894 
01895     jrKanjiControl(0, KC_FINALIZE, (char *) 0);
01896 
01897     return True;
01898 }
01899 
01900 Bool
01901 if_canna_CreateSC(iml_session_t *s, IMArgList args, int num_args)
01902 {
01903     CannaLESession *pcls = (CannaLESession*) malloc(sizeof(CannaLESession));
01904     jrKanjiStatus *pks = (jrKanjiStatus*) malloc(sizeof(jrKanjiStatus));
01905     iml_desktop_t *desktop = s->desktop;
01906     CannaLEDesktop *d = canna_desktop_data(s);
01907     unsigned char *buf;
01908 
01909     buf = (unsigned char *) malloc(CANNA_COMMIT_STRING_BUFSIZE);
01910     if ((!pcls) || (!pks) || (!buf)) return False;
01911     pcls->ksv.ks = pks;
01912     pcls->ksv.buffer = buf;
01913     buf[0] = '\0';
01914     pcls->ksv.bytes_buffer = CANNA_COMMIT_STRING_BUFSIZE;
01915     pcls->conversion_start = False;
01916     pcls->aux_start = False;
01917     pcls->context_id = canna_context_id_counter++;
01918     pcls->old_minor_mode = 0;
01919     pcls->update_state = 0;
01920     pcls->force_not_update_state = 0;
01921     /* Init jrKanjiStatus variable with 0. */
01922     memset(pks, 0, sizeof(jrKanjiStatus));
01923 
01924     s->specific_data = (void*) pcls;
01925 
01926     /* initialize here because of avoid wrong initialization for multiple users */
01927     if (canna_init(s, d->drop_priv ? desktop->user_name : NULL)) {
01928        if (!jrKanjiControl(canna_session_context(s), KC_QUERYCONNECTION, (char *) 0)) {
01929            fprintf(stderr, "htt: CannaLE: Unable to connect with canna server.\n");
01930            return False;
01931        }
01932        pcls->is_canna_initialized = True;
01933     } else {
01934        /* cannaserver isn't running? or something like that - failed the initialization anyway */
01935        pcls->is_canna_initialized = False;
01936     }
01937 
01938     return True;
01939 }
01940 
01941 Bool
01942 if_canna_DestroySC(iml_session_t *s)
01943 {
01944     CannaLESession *pcls;
01945     jrKanjiStatusWithValue *pksv = canna_session_status(s);
01946 
01947     canna_aux_done(s);
01948     pcls = canna_session_data(s);
01949     jrKanjiControl(canna_session_context(s), KC_CLOSEUICONTEXT, (char *) pksv);
01950     if (pksv->buffer != NULL)
01951        free(pksv->buffer);
01952     if (pksv->ks != NULL)
01953        free(pksv->ks);
01954     free(pcls);
01955     return True;
01956 }
01957 
01958 IMText*
01959 if_canna_ResetSC(iml_session_t *s)
01960 {
01961     iml_inst *lp;
01962     IMText *p;
01963 
01964     /* erase preedit. */
01965     lp = s->If->m->iml_make_preedit_erase_inst(s);
01966     s->If->m->iml_execute(s, &lp);
01967 
01968     /* fix the current string. (kakutei) */
01969     p = canna_kakutei(s);
01970 
01971     if (p->char_length) return p;
01972     return (IMText*) NULL;
01973 }
01974 
01975 Bool
01976 if_canna_SetSCValue(iml_session_t *s, IMArgList args, int num)
01977 {
01978     int i;
01979     IMArg *p = args;
01980 
01981     for (i = 0; i < num; i++, p++) {
01982         switch (p->id) {
01983        case SC_TRIGGER_ON_NOTIFY:
01984            canna_make_conversion_on(s);
01985            break;
01986        case SC_TRIGGER_OFF_NOTIFY:
01987            canna_make_conversion_off(s);
01988            break;
01989        case SC_REALIZE:
01990            /* currently do nothing. */
01991            break;
01992        case SC_LOOKUP_LABELTYPE:
01993            break;
01994        default:
01995            break;
01996        }
01997     }
01998 
01999     return True;
02000 }
02001 
02002 Bool
02003 if_canna_GetSCValue(iml_session_t *s, IMArgList args, int num_args)
02004 {
02005     int i;
02006     IMArg *p = args;
02007 
02008     /* Canna uses at least LATIN, HIRAGANA, KATAKANA,
02009        and KANJI scripts.
02010        That's all to it? */
02011     static int charsubset[] = {
02012         67,                 /* LATIN */
02013         47,                 /* HIRAGANA */
02014         48,                 /* KATAKANA */
02015         71,                 /* KANJI */
02016         0
02017     };
02018 
02019     for (i = 0; i < num_args; i++, p++) {
02020         switch (p->id) {
02021             case SC_SUPPORTED_CHARACTER_SUBSETS:
02022                 /* specify CHARACTER_SUBSETS */
02023                 p->value = (IMArgVal) charsubset;
02024                 break;
02025             default:
02026                 break;
02027             }
02028     }
02029     return True;
02030 }
02031 
02032 void
02033 if_canna_SetSCFocus(iml_session_t *s)
02034 {
02035     canna_status_draw(s);
02036     canna_aux_draw(s, AUX_FOCUS_CHANGE, ((void *)(int) 1));
02037 }
02038 
02039 void
02040 if_canna_UnsetSCFocus(iml_session_t *s)
02041 {
02042     canna_aux_draw(s, AUX_FOCUS_CHANGE, ((void *)(int) 0));
02043 //    canna_aux_done(s);
02044 }
02045 
02046 void
02047 if_canna_SendEvent(iml_session_t *s, IMInputEvent *ev)
02048 {
02049     if (ev) {
02050        switch (ev->type) {
02051        case IM_EventKeyList:
02052            canna_process_keyevent(s, (IMKeyListEvent*) ev);
02053            break;
02054        case IM_EventAux:
02055            canna_process_auxevent(s, ((IMAuxEvent *) ev)->aux);
02056            break;
02057        case IM_EventString:
02058        case IM_EventText:
02059        default:
02060            break;
02061        }
02062     }
02063     return;
02064 }
02065 
02066 static void
02067 canna_change_mode(iml_session_t *s, int id)
02068 {
02069     jrKanjiStatusWithValue *pksv;
02070 
02071     pksv = canna_session_status(s);
02072     pksv->val = id;
02073     jrKanjiControl(canna_session_context(s),
02074                  KC_CHANGEMODE, (char*) pksv);
02075 }
02076 
02077 static int
02078 canna_get_current_mode(iml_session_t *s)
02079 {
02080     char mode[4];
02081 
02082     jrKanjiControl(canna_session_context(s), KC_SETMODEINFOSTYLE, (char *)1);
02083     jrKanjiControl(canna_session_context(s), KC_QUERYMODE, (char *)mode);
02084     jrKanjiControl(canna_session_context(s), KC_SETMODEINFOSTYLE, (char *)0);
02085 
02086 #ifdef DEBUG
02087     printf("*** major = %d\n", mode[0] - '@');
02088 #endif
02089 
02090     return mode[0] - '@';
02091 }
02092 
02093 static int
02094 canna_get_current_minor_mode(iml_session_t *s)
02095 {
02096     char mode[4];
02097 
02098     jrKanjiControl(canna_session_context(s), KC_SETMODEINFOSTYLE, (char *)2);
02099     jrKanjiControl(canna_session_context(s), KC_QUERYMODE, (char *)mode);
02100     jrKanjiControl(canna_session_context(s), KC_SETMODEINFOSTYLE, (char *)0);
02101 
02102 #ifdef DEBUG
02103     printf("*** minor = %d:%d\n", mode[0] - '@', mode[1] - '@');
02104 #endif
02105 
02106     return mode[1] - '@';
02107 }
02108 
02109 static Bool
02110 canna_drop_privilege(const char *username)
02111 {
02112     struct passwd *pw;
02113     uid_t uid;
02114     gid_t gid;
02115 
02116     if (!username)
02117        goto error;
02118     if ((pw = getpwnam(username)) == NULL) {
02119        goto error;
02120     } else {
02121        uid = pw->pw_uid;
02122        gid = pw->pw_gid;
02123        if (uid < 500)
02124            goto error;
02125     }
02126     if (setregid(gid, gid) < 0) {
02127        return False;
02128     }
02129     if (setreuid (uid, uid) < 0) {
02130        return False;
02131     }
02132     return True;
02133 
02134 error:
02135     if ((pw = getpwnam("nobody")) != NULL) {
02136        gid = pw->pw_gid;
02137        uid = pw->pw_uid;
02138        setregid(gid, gid);
02139        setreuid(uid, uid);
02140     } else {
02141        assert(0);
02142     }
02143     return False;
02144 }