Mercurial > kinput2.yaz
diff lib/imlib/imrequest.c @ 0:92745d501b9a
initial import from kinput2-v3.1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 08 Mar 2010 04:44:30 +0900 |
parents | |
children | 1f9e9cb00c6c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/imlib/imrequest.c Mon Mar 08 04:44:30 2010 +0900 @@ -0,0 +1,1452 @@ +#ifndef lint +static char *rcsid = "$Id: imrequest.c,v 1.19 2002/01/27 11:33:37 ishisone Exp $"; +#endif +/* + * Copyright (c) 1994 Software Research Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Software Research + * Associates makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * Author: Makoto Ishisone, Software Research Associates, Inc., Japan + */ + +/* in order to include xEvent definition */ +#define NEED_EVENTS +#include <X11/Xproto.h> + +#include "im.h" +#include "imreq.h" + +/* + * Request handle functions + */ +static void ximDisconnectProc _Pt_((IMConnection *, int, int, int)); +static void ximErrorProc _Pt_((IMConnection *, int, int, int)); +static void ximOpenProc _Pt_((IMConnection *, int, int, int)); +static void ximCloseProc _Pt_((IMConnection *, int, int, int)); +static void ximTriggerNotifyProc _Pt_((IMConnection *, int, int, int)); +static void ximEncodingNegotiationProc _Pt_((IMConnection *, int, int, int)); +static void ximQueryExtensionProc _Pt_((IMConnection *, int, int, int)); +static void ximSetIMValuesProc _Pt_((IMConnection *, int, int, int)); +static void ximGetIMValuesProc _Pt_((IMConnection *, int, int, int)); +static void ximCreateICProc _Pt_((IMConnection *, int, int, int)); +static void ximDestroyICProc _Pt_((IMConnection *, int, int, int)); +static void ximSetICValuesProc _Pt_((IMConnection *, int, int, int)); +static void ximGetICValuesProc _Pt_((IMConnection *, int, int, int)); +static void ximSetICFocusProc _Pt_((IMConnection *, int, int, int)); +static void ximUnsetICFocusProc _Pt_((IMConnection *, int, int, int)); +static void ximForwardEventProc _Pt_((IMConnection *, int, int, int)); +static void ximExtForwardKeyeventProc _Pt_((IMConnection *, int, int, int)); +static void ximSyncProc _Pt_((IMConnection *, int, int, int)); +static void ximSyncReplyProc _Pt_((IMConnection *, int, int, int)); +static void ximResetICProc _Pt_((IMConnection *, int, int, int)); +static void ximExtMoveProc _Pt_((IMConnection *, int, int, int)); + +static void ximAlreadyConnectedProc _Pt_((IMConnection *, int, int, int)); +static void ximShouldNotBeSentProc _Pt_((IMConnection *, int, int, int)); +static void ximAuthPhaseProc _Pt_((IMConnection *, int, int, int)); +static void ximNopProc _Pt_((IMConnection *, int, int, int)); + +/* + * Core request table + */ +static IMRequest coreRequestTbl[] = { + { "CONNECT", XIM_CONNECT, 0, ximAlreadyConnectedProc }, + { "CONNECT-REPLY", XIM_CONNECT_REPLY, 0, ximShouldNotBeSentProc }, + { "DISCONNECT", XIM_DISCONNECT, 0, ximDisconnectProc }, + { "DISCONNECT-REPLY", XIM_DISCONNECT_REPLY, 0, ximShouldNotBeSentProc }, + { "AUTH-REQUIRED", XIM_AUTH_REQUIRED, 0, ximAuthPhaseProc }, + { "AUTH-REPLY", XIM_AUTH_REPLY, 0, ximAuthPhaseProc }, + { "AUTH-NEXT", XIM_AUTH_NEXT, 0, ximAuthPhaseProc }, + { "AUTH-SETUP", XIM_AUTH_SETUP, 0, ximShouldNotBeSentProc }, + { "AUTH-NG", XIM_AUTH_NG, 0, ximAuthPhaseProc }, + { "ERROR", XIM_ERROR, 0, ximErrorProc }, + { "OPEN", XIM_OPEN, 0, ximOpenProc }, + { "OPEN-REPLY", XIM_OPEN_REPLY, 0, ximShouldNotBeSentProc }, + { "CLOSE", XIM_CLOSE, 0, ximCloseProc }, + { "CLOSE-REPLY", XIM_CLOSE_REPLY, 0, ximShouldNotBeSentProc }, + { "SET-EVENT-MASK", XIM_SET_EVENT_MASK, 0, ximShouldNotBeSentProc }, + { "REGISTER-TRIGGERKEYS", XIM_REGISTER_TRIGGERKEYS, 0, + ximShouldNotBeSentProc }, + { "TRIGGER-NOTIFY", XIM_TRIGGER_NOTIFY, 0, ximTriggerNotifyProc }, + { "TRIGGER-NOTIFY-REPLY", XIM_TRIGGER_NOTIFY_REPLY, 0, + ximShouldNotBeSentProc }, + { "ENCODING-NEGOTIATION", XIM_ENCODING_NEGOTIATION, 0, + ximEncodingNegotiationProc }, + { "ENCODING-NEGOTIATION-REPLY", XIM_ENCODING_NEGOTIATION_REPLY, 0, + ximShouldNotBeSentProc }, + { "QUERY-EXTENSION", XIM_QUERY_EXTENSION, 0, ximQueryExtensionProc }, + { "QUERY-EXTENSION-REPLY", XIM_QUERY_EXTENSION_REPLY, 0, + ximShouldNotBeSentProc }, + { "SET-IM-VALUES", XIM_SET_IM_VALUES, 0, ximSetIMValuesProc }, + { "SET-IM-VALUES-REPLY", XIM_SET_IM_VALUES_REPLY, 0, + ximShouldNotBeSentProc }, + { "GET-IM-VALUES", XIM_GET_IM_VALUES, 0, ximGetIMValuesProc }, + { "GET-IM-VALUES-REPLY", XIM_GET_IM_VALUES_REPLY, 0, + ximShouldNotBeSentProc }, + { "CREATE-IC", XIM_CREATE_IC, 0, ximCreateICProc }, + { "CREATE-IC-REPLY", XIM_CREATE_IC_REPLY, 0, ximShouldNotBeSentProc }, + { "DESTROY-IC", XIM_DESTROY_IC, 0, ximDestroyICProc }, + { "DESTROY-IC-REPLY", XIM_DESTROY_IC_REPLY, 0, ximShouldNotBeSentProc }, + { "SET-IC-VALUES", XIM_SET_IC_VALUES, 0, ximSetICValuesProc }, + { "SET-IC-VALUES-REPLY", XIM_SET_IC_VALUES_REPLY, 0, + ximShouldNotBeSentProc }, + { "GET-IC-VALUES", XIM_GET_IC_VALUES, 0, ximGetICValuesProc }, + { "GET-IC-VALUES-REPLY", XIM_GET_IC_VALUES_REPLY, 0, + ximShouldNotBeSentProc }, + { "SET-IC-FOCUS", XIM_SET_IC_FOCUS, 0, ximSetICFocusProc }, + { "UNSET-IC-FOCUS", XIM_UNSET_IC_FOCUS, 0, ximUnsetICFocusProc }, + { "FORWARD-EVENT", XIM_FORWARD_EVENT, 0, ximForwardEventProc }, + { "SYNC", XIM_SYNC, 0, ximSyncProc }, + { "SYNC-REPLY", XIM_SYNC_REPLY, 0, ximSyncReplyProc }, + { "COMMIT", XIM_COMMIT, 0, ximShouldNotBeSentProc }, + { "RESET-IC", XIM_RESET_IC, 0, ximResetICProc }, + { "RESET-IC-REPLY", XIM_RESET_IC_REPLY, 0, ximShouldNotBeSentProc }, + { "GEOMETRY", XIM_GEOMETRY, 0, ximShouldNotBeSentProc }, + { "STR-CONVERSION", XIM_STR_CONVERSION, 0, ximShouldNotBeSentProc }, + { "STR-CONVERSION-REPLY", XIM_STR_CONVERSION_REPLY, 0, + ximShouldNotBeSentProc }, + { "PREEDIT-START", XIM_PREEDIT_START, 0, ximShouldNotBeSentProc }, + { "PREEDIT-START-REPLY", XIM_PREEDIT_START_REPLY, 0, + ximNopProc }, + { "PREEDIT-DRAW", XIM_PREEDIT_DRAW, 0, ximShouldNotBeSentProc }, + { "PREEDIT-CARET", XIM_PREEDIT_CARET, 0, ximShouldNotBeSentProc }, + { "PREEDIT-CARET-REPLY", XIM_PREEDIT_CARET_REPLY, 0, + ximNopProc }, + { "PREEDIT-DONE", XIM_PREEDIT_DONE, 0, ximShouldNotBeSentProc }, + { "PREEDITSTATE", XIM_PREEDITSTATE, 0, ximShouldNotBeSentProc }, + { "STATUS-START", XIM_STATUS_START, 0, ximShouldNotBeSentProc }, + { "STATUS-DRAW", XIM_STATUS_DRAW, 0, ximShouldNotBeSentProc }, + { "STATUS-DONE", XIM_STATUS_DONE, 0, ximShouldNotBeSentProc }, + { NULL, 0, 0, NULL }, +}; + +/* + * Extension request table + */ +static IMRequest extRequestTbl[] = { + { "XIM_EXT_SET_EVENT_MASK", XIM_EXT_SET_EVENT_MASK, 0, + ximShouldNotBeSentProc, XIM_EXT_SET_EVENT_MASK_MASK }, + { "XIM_EXT_FORWARD_KEYEVENT", XIM_EXT_FORWARD_KEYEVENT, 0, + ximExtForwardKeyeventProc, XIM_EXT_FORWARD_KEYEVENT_MASK }, + { "XIM_EXT_MOVE", XIM_EXT_MOVE, 0, + ximExtMoveProc, XIM_EXT_MOVE_MASK }, + { NULL, 0, 0, NULL }, +}; + +/* + * Request dispatch table (global) + */ +IMRequest *IMMainDispatchTable[256]; + + +static void compileTbl _Pt_((IMRequest *req)); +static char *ecode2str _Pt_((int code)); +static void putTriggerkeyList _Pt_((IMIM *imp)); +static int findCtext _Pt_((IMConnection *conn, int arglen)); +static IMRequest *getExtension _Pt_((char *name)); +static void putExtension _Pt_((IMConnection *conn, IMRequest *req)); +static void swapData _Pt_((char *data, char *format)); +static int getEvent _Pt_((IMConnection *conn, unsigned int serial, + int offset, XEvent *ev)); +static void postponeEvent _Pt_((IMIC *icp, int synchronous, XEvent *ev)); +static void handleForwardedEvent _Pt_((IMIC *icp, int synchronous, XEvent *ev)); +static void processPendingEvents _Pt_((IMIC *icp, + IMPendingEvent *pending_event)); + + +/*- compileTbl: assemble IMMainDispatchTbl -*/ +static void +compileTbl(req) +IMRequest *req; +{ + while (req->name != NULL) { + req->next = IMMainDispatchTable[req->major]; + IMMainDispatchTable[req->major] = req; + req++; + } +} + +/*- ximDisconnectProc: handle XIM_DISCONNECT request -*/ +/* ARGSUSED */ +static void +ximDisconnectProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp = conn->im_list; + IMIM *imp_next; + + TRACE(("ximDisconnectProc(#%d)\n", conn->serial)); + + if (arglen != 0) { + DPRINT(("ximDisconnectProc: arglen != 0\n")); + IMSendBadLength(conn, 0, 0); + return; + } + + while (imp != NULL) { + imp_next = imp->next; + IMDestroyIM(imp); + imp = imp_next; + } + IMSendSimpleRequest(conn, XIM_DISCONNECT_REPLY, 0); + IMSchedule(conn, SCHED_CLOSE); +} + +/*- ecode2str: error code to error name string converter -*/ +static char * +ecode2str(code) +int code; +{ + char *s; + + switch (code) { + case IMBadAlloc: s = "BadAlloc"; break; + case IMBadStyle: s = "BadStyle"; break; + case IMBadClientWindow: s = "BadClientWindow"; break; + case IMBadFocusWindow: s = "BadFocusWindow"; break; + case IMBadArea: s = "BadArea"; break; + case IMBadSpotLocation: s = "BadSpotLocation"; break; + case IMBadColormap: s = "BadColormap"; break; + case IMBadAtom: s = "BadAtom"; break; + case IMBadPixel: s = "BadPixel"; break; + case IMBadPixmap: s = "BadPixmap"; break; + case IMBadName: s = "BadName"; break; + case IMBadCursor: s = "BadCursor"; break; + case IMBadProtocol: s = "BadProtocol"; break; + case IMBadForeground: s = "BadForeground"; break; + case IMBadBackground: s = "BadBackground"; break; + case IMLocaleNotSupported: s = "LocaleNotSupported"; break; + case IMBadSomething: s = "BadSomething"; break; + default: s = "? (undefined error code)"; break; + } + return s; +} + +/*- ximErrorProc: handle XIM_Error messsage -*/ +/* ARGSUSED */ +static void +ximErrorProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + unsigned int imid, icid; + int flag; + int code; + int msg_len; + char msg[256 + 1]; + + TRACE(("ximErrorProc(#%d)\n", conn->serial)); + + if (arglen < 10) { + DPRINT(("corrupted XIM_ERROR message (arglen < 10) received\n")); + return; + } + imid = IMGetC16(conn, 0); + icid = IMGetC16(conn, 2); + flag = IMGetC16(conn, 4); + code = IMGetC16(conn, 6); + msg_len = IMGetC16(conn, 8); + if (msg_len > 0) { + if (msg_len + 12 > arglen) { + DPRINT(("corrupted XIM_ERROR message (message too long) received\n")); + return; + } + if (msg_len > 256) msg_len = 256; + IMGetString(conn, 12, msg, msg_len); + } + if (DEBUG_CONDITION) { + printf("** XIM_ERROR message received:\n"); + if (flag & 1) { + printf("\t input-method ID: %d\n", imid); + } else { + printf("\t input-method ID: N/A\n"); + } + if (flag & 2) { + printf("\tinput-context ID: %d\n", icid); + } else { + printf("\tinput-context ID: N/A\n"); + } + printf("\t error code: %s\n", ecode2str(code)); + printf("\t error message: %s\n", msg); + } +} + +/*- putTriggerkeyList: put trigger key list on the output stream -*/ +static void +putTriggerkeyList(imp) +IMIM *imp; +{ + IMConnection *conn = imp->connection; + IMTriggerKey *triggers; + int num_triggers; + int i; + + triggers = IMTriggerKeys(imp, &num_triggers); + + IMPutC32(conn, (unsigned long)(12 * num_triggers)); + for (i = 0; i < num_triggers; i++) { + IMPutC32(conn, triggers[i].keysym); + IMPutC32(conn, (unsigned long)triggers[i].modifiers); + IMPutC32(conn, (unsigned long)triggers[i].check_modifiers); + } +} + +/*- ximOpenProc: handle XIM_OPEN request -*/ +/* ARGSUSED */ +static void +ximOpenProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + int locale_len; + char localename[256 + 1]; + int offset; + IMConverter *icp; + IMIM *imp; + + TRACE(("ximOpenProc(#%d)\n", conn->serial)); + + if (arglen < 1) { + DPRINT(("ximOpenProc: arglen < 1\n")); + IMSendBadLength(conn, 0, 0); + return; + } + + locale_len = IMGetC8(conn, 0); + if (arglen < locale_len + 1) { + DPRINT(("ximOpenProc: locale too long\n")); + IMSendBadLength(conn, 0, 0); + return; + } + + bcopy(IMBUFDATA(IM_INBUF(conn)) + 1, localename, locale_len); + localename[locale_len] = '\0'; + TRACE(("\tlocalename: %s\n", localename)); + + if ((icp = IMGetConverter(conn->proto_widget, localename)) == NULL) { + DPRINT(("ximOpenProc: unsupported locale %s\n", localename)); + IMSendError(conn, IMLocaleNotSupported, 0, 0, "unknown locale"); + return; + } + + imp = IMCreateIM(conn, icp); + + /* + * Send open reply message. + */ + offset = IMPutHeader(conn, XIM_OPEN_REPLY, 0, 0); + IMPutC16(conn, imp->id); + IMPutIMAttrList(imp); + IMPutICAttrList(imp); + IMFinishRequest(conn, offset); + + /* + * Notify conversion trigger keys. + * + * Note: + * The spec says that XIM_REGISTER_TRIGGERKEYS message should + * be sent to the client bofore XIM_OPEN_REPLY message, in + * order to use dynamic event flow model. However, this + * does not work with current Xlib implementation. So we + * send XIM_REGISTER_TRIGGERKEYS just after XIM_OPEN_REPLY, + * which works fine. + */ + offset = IMPutHeader(conn, XIM_REGISTER_TRIGGERKEYS, 0, 0); + IMPutC16(conn, imp->id); + IMPutC16(conn, 0); + putTriggerkeyList(imp); + IMFinishRequest(conn, offset); +} + +/*- ximCloseProc: handle XIM_CLOSE request -*/ +/* ARGSUSED */ +static void +ximCloseProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + + TRACE(("ximCloseProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximCloseProc: arglen != 4\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + IMPutHeader(conn, XIM_CLOSE_REPLY, 0, 4); + IMPutC16(conn, imp->id); + IMPutPad(conn); + IMSchedule(conn, SCHED_WRITE); + + IMDestroyIM(imp); +} + +/*- ximTriggerNotifyProc: handle XIM_TRIGGER_NOTIFY request -*/ +/* ARGSUSED */ +static void +ximTriggerNotifyProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + int flag; + int key_index; + int num_triggers; + + TRACE(("ximTriggerNotifyProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + + if (arglen != 16) { + DPRINT(("ximTriggerNotifyProc: arglen != 16\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + flag = (int)IMGetC32(conn, 4); + key_index = (int)IMGetC32(conn, 8); + TRACE(("\tflag=%d, index=%d\n", flag, key_index)); + + /* + * Check flag and index. Since kinput2 does not + * specifiy off-keys, any off-key notifications + * are invalid. + * The current Xlib implementation (as of pl4) + * specifies incorrect key_index, so index check + * is turned off until the bug is fixed. + */ + + (void)IMTriggerKeys(icp->im, &num_triggers); + if (flag != 0 +#ifndef XIM_BC + || key_index >= num_triggers +#endif /* XIM_BC */ + ) { + /* invalid parameter */ + DPRINT(("ximTriggerNotifyProc: invalid trigger spec.\n")); + IMSendError(conn, IMBadSomething, icp->im->id, icp->id, + "invalid trigger key specification"); + return; + } + + /* + * If we are already in conversion mode, do nothing special. + */ + if (!(icp->state & IC_CONVERTING)) { + /* + * Start conversion. + */ + if (IMStartConversion(icp) < 0) return; + } + + /* + * Send XIM_TRIGGER_NOTIFY_REPLY request. + */ + (void)IMPutHeader(conn, XIM_TRIGGER_NOTIFY_REPLY, 0, 4); + IMPutC16(conn, icp->im->id); + IMPutC16(conn, icp->id); + IMSchedule(conn, SCHED_WRITE); +} + +/*- findCtext: look up COMPOUND_TEXT from encoding list -*/ +static int +findCtext(conn, arglen) +IMConnection *conn; +int arglen; +{ + int offset, name_end; + int encoding_index; + unsigned int name_bytes; + + offset = 2; + name_bytes = IMGetC16(conn, offset); + offset += 2; + name_end = offset + name_bytes; + if (name_end > arglen) return -2; + + /* + * Examine encodings listed by name. + */ + encoding_index = 0; + while (offset < name_end) { + char str_buf[256 + 1]; + int str_len; + + str_len = IMGetC8(conn, offset++); + IMGetString(conn, offset, str_buf, str_len); + if (!strcmp(str_buf, "COMPOUND_TEXT")) { + return encoding_index; + } + offset += str_len; + encoding_index++; + } + + /* + * Encodings listed by detailed data follow, but + * I have no idea what they are. + */ + return -1; +} + +/*- ximEncodingNegotiationProc: handle XIM_ENCODING_NEGOTIATION request -*/ +/* ARGSUSED */ +static void +ximEncodingNegotiationProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + int encoding_index; + + TRACE(("ximEncodingNegotiationProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + + if (arglen < 8) { + DPRINT(("ximEncodingNegotiationProc: arglen < 8\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + /* + * Always use COMPOUND_TEXT. + */ + if ((encoding_index = findCtext(conn, arglen)) < -1) { + /* bad argument error */ + DPRINT(("ximEncodingNegotiationProc: encoding list corrupted\n")); + IMSendError(conn, IMBadSomething, imp->id, 0, + "corrupted argument"); + return; + } + TRACE(("\tselected encoding index: %d\n", encoding_index)); + + (void)IMPutHeader(conn, XIM_ENCODING_NEGOTIATION_REPLY, 0, 8); + IMPutC16(conn, imp->id); + IMPutC16(conn, 0); + IMPutI16(conn, encoding_index); + IMPutPad(conn); + IMSchedule(conn, SCHED_WRITE); +} + +/*- getExtension: search named extension -*/ +static IMRequest * +getExtension(name) +char *name; +{ + IMRequest *req = extRequestTbl; + + while (req->name != NULL) { + if (!strcmp(req->name, name)) return req; + req++; + } + return NULL; +} + +/*- putExtension: put extension information on the output stream -*/ +static void +putExtension(conn, req) +IMConnection *conn; +IMRequest *req; +{ + int text_length; + + text_length = strlen(req->name); + IMPutC8(conn, req->major); + IMPutC8(conn, req->minor); + IMPutC16(conn, (unsigned int)text_length); + IMPutString(conn, req->name, text_length); + IMPutPad(conn); +} + +/*- ximQueryExtensionProc: handle XIM_QUERY_EXTENSION request -*/ +/* ARGSUSED */ +static void +ximQueryExtensionProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + int ext_len; + int cur_off; + int req_offset; + int size_offset; + int list_start, list_end; + + TRACE(("ximQueryExtensionProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + if (arglen < 4) { + DPRINT(("ximQueryExtensionProc: arglen < 4\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + ext_len = IMGetC16(conn, 2); + if (4 + ext_len > arglen) { + DPRINT(("ximQueryExtensionProc: extension list too long\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + cur_off = 4; + + req_offset = IMPutHeader(conn, XIM_QUERY_EXTENSION_REPLY, 0, 0); + IMPutC16(conn, imp->id); + size_offset = IMWritePos(conn); + IMPutC16(conn, 0); /* dummy. overwritten afterwards */ + + list_start = IMWritePos(conn); + + if (ext_len == 0) { + IMRequest *ext_req = extRequestTbl; + + while (ext_req->name != NULL) { + putExtension(conn, ext_req); + ext_req++; + } + + } else { + IMRequest *ext_req; + + while (ext_len > 1) { + int str_len; + char ext_name[256 + 1]; + + str_len = IMGetC8(conn, cur_off); + cur_off++; + + if (str_len + 1 > ext_len) { + DPRINT(("ximQueryExtensionProc: extension name too long\n")); + IMCancelRequest(conn, req_offset); + /* BadString */ + IMSendBadLength(conn, imp->id, 0); + return; + } + + IMGetString(conn, cur_off, ext_name, str_len); + TRACE(("\tclient queries %s extension\n", ext_name)); + + if ((ext_req = getExtension(ext_name)) != NULL) { + putExtension(conn, ext_req); + imp->mask |= ext_req->mask; + } + cur_off += str_len; + ext_len -= str_len + 1; + } + } + + list_end = IMWritePos(conn); + IMRewriteC16(conn, size_offset, (unsigned int)(list_end - list_start)); + + IMFinishRequest(conn, req_offset); +} + +/*- ximSetIMValuesProc: handle XIM_SET_IM_VALUES request -*/ +/* ARGSUSED */ +static void +ximSetIMValuesProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + char *attr; + int attr_len; + + TRACE(("ximSetIMValuesProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + if (arglen < 4) { + DPRINT(("ximSetIMValuesProc: arglen < 4\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + attr_len = IMGetC16(conn, 2); + attr = IMBUFDATA(IM_INBUF(conn)) + 4; + + if (arglen < attr_len + 4) { + DPRINT(("ximSetIMValuesProc: attribute len too long\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + if (IMSetIMValues(imp, attr, attr_len, major) < 0) return; + + (void)IMPutHeader(conn, XIM_SET_IM_VALUES_REPLY, 0, 4); + IMPutC16(conn, imp->id); + IMPutPad(conn); + IMSchedule(conn, SCHED_WRITE); +} + +/*- ximGetIMValuesProc: handle XIM_GET_IM_VALUES request -*/ +/* ARGSUSED */ +static void +ximGetIMValuesProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + char *attr; + int attr_len; + int offset; + + TRACE(("ximGetIMValuesProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + if (arglen < 4) { + DPRINT(("ximGetIMValuesProc: arglen < 4\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + attr_len = IMGetC16(conn, 2); + attr = IMBUFDATA(IM_INBUF(conn)) + 4; + if (arglen < attr_len + 4 || attr_len % 2 == 1) { + DPRINT(("ximGetIMValuesProc: attr_len too long or an odd number\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + offset = IMPutHeader(conn, XIM_GET_IM_VALUES_REPLY, 0, 0); + IMPutC16(conn, imp->id); + + if (IMGetIMValues(imp, attr, attr_len, offset) < 0) return; + + IMFinishRequest(conn, offset); +} + +/*- ximCreateICProc: handle XIM_CREATE_IC request -*/ +/* ARGSUSED */ +static void +ximCreateICProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIM *imp; + IMIC *icp; + char *attr_data; + int attr_len; + + TRACE(("ximCreateICProc(#%d)\n", conn->serial)); + + if ((imp = IMGetIM(conn, arglen)) == NULL) return; + if (arglen < 4) { + /* BadArglen */ + DPRINT(("ximCreateICProc: arglen < 4\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + + attr_len = IMGetC16(conn, 2); + attr_data = IMBUFDATA(IM_INBUF(conn)) + 4; + if (arglen < attr_len + 4) { + DPRINT(("ximCreateICProc: attr_len too long\n")); + IMSendBadLength(conn, imp->id, 0); + return; + } + icp = IMCreateIC(imp); + if (IMSetICValues(icp, attr_data, attr_len, major) < 0) { + IMDestroyIC(icp); + return; + } + IMSendRequestWithIC(conn, XIM_CREATE_IC_REPLY, 0, icp); + + IMStatusStart(icp); +} + +/*- ximDestroyICProc: handle XIM_DESTROY_IC request -*/ +/* ARGSUSED */ +static void +ximDestroyICProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + unsigned int imid, icid; + + TRACE(("ximDestroyICProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximDestroyICProc: arglen != 4\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + /* Save ID of IM/IC before IMDestroyIC() */ + imid = icp->im->id; + icid = icp->id; + + IMStatusDone(icp); + + IMDestroyIC(icp); + + /* IMSendRequestWithIC(conn, XIM_DESTROY_IC_REPLY, 0, icp); */ + IMPutHeader(conn, XIM_DESTROY_IC_REPLY, 0, 4); + IMPutC16(conn, imid); + IMPutC16(conn, icid); + IMSchedule(conn, SCHED_WRITE); +} + +/*- ximSetICValuesProc: handle XIM_SET_IC_VALUES request -*/ +/* ARGSUSED */ +static void +ximSetICValuesProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + char *attr; + int attr_len; + + TRACE(("ximSetICValuesProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen < 8) { + DPRINT(("ximSetICValuesProc: arglen < 8\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + attr_len = IMGetC16(conn, 4); + attr = IMBUFDATA(IM_INBUF(conn)) + 8; + + if (arglen < attr_len + 8) { + DPRINT(("ximSetICValuesProc: attr_len too long\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + if (IMSetICValues(icp, attr, attr_len, major) < 0) return; + + IMSendRequestWithIC(conn, XIM_SET_IC_VALUES_REPLY, 0, icp); +} + +/*- ximGetICValuesProc: handle XIM_GET_IC_VALUES request -*/ +/* ARGSUSED */ +static void +ximGetICValuesProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + char *attr; + int attr_len; + int offset; + + TRACE(("ximGetICValuesProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen < 6) { + DPRINT(("ximGetICValuesProc: arglen < 6\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + attr_len = IMGetC16(conn, 4); + attr = IMBUFDATA(IM_INBUF(conn)) + 6; + if (arglen < attr_len + 6 || attr_len % 2 == 1) { + DPRINT(("ximGetICValuesProc: attr_len too long or an odd number\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + offset = IMPutHeader(conn, XIM_GET_IC_VALUES_REPLY, 0, 0); + IMPutC16(conn, icp->im->id); + IMPutC16(conn, icp->id); + + if (IMGetICValues(icp, attr, attr_len, offset) < 0) return; + + IMFinishRequest(conn, offset); +} + +/*- ximSetICFocusProc: handle XIM_SET_IC_FOCUS request -*/ +/* ARGSUSED */ +static void +ximSetICFocusProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + + TRACE(("ximSetICFocusProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximSetICFocusProc: arglen != 4\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + IMStatusStart(icp); + IMSetFocus(icp); +} + +/*- ximUnsetICFocusProc: handle XIM_UNSET_IC_FOCUS request -*/ +/* ARGSUSED */ +static void +ximUnsetICFocusProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + + TRACE(("ximUnsetICFocusProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximUnsetICFocusProc: arglen != 4\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + IMUnsetFocus(icp); + IMStatusDone(icp); +} + +/*- swapData: do byte swapping -*/ +static void +swapData(data, format) +char *data; +char *format; +{ + unsigned char *p = (unsigned char *)data; + int x; + int f; + +#define SWAPB(b1, b2) x = b1; b1 = b2; b2 = x + while ((f = *format++) != '\0') { + switch (f) { + case 'x': + p++; + break; + case 'l': + SWAPB(p[0], p[3]); + SWAPB(p[1], p[2]); + p += 4; + break; + case 's': + SWAPB(p[0], p[1]); + p += 2; + break; + } + } +#undef SWAPB +} + + +/*- getEvent: read a wire event and convert it to XEvent format -*/ +static int +getEvent(conn, serial, offset, ev) +IMConnection *conn; +unsigned int serial; +int offset; +XEvent *ev; +{ + IMBuffer *ibp = IM_INBUF(conn); + xEvent wire_event; + int swap_needed; + int one = 1; + char *onep = (char *)&one; + + /* + * Get wire event from input buffer. + */ + bcopy(IMBUFDATA(ibp) + offset, (char *)&wire_event, sizeof(wire_event)); + + /* + * Do we need byte swapping? + */ + if (*onep == 0) { /* big endian */ + swap_needed = (conn->byte_order == ORDER_LITTLE); + } else { /* little endian */ + swap_needed = (conn->byte_order == ORDER_BIG); + } + +#define SWAPEV(format) if (swap_needed) swapData((char *)&wire_event, format) + + /* + * Get common part of the wire event. + */ + SWAPEV("xxs"); + ev->type = wire_event.u.u.type & 0x7f; + ev->xany.serial = (serial << 16) | wire_event.u.u.sequenceNumber; + ev->xany.display = XtDisplay(conn->proto_widget); + ev->xany.send_event = wire_event.u.u.type > 127; + + /* + * Convert wire format to XEvent format. + */ + switch (ev->type) { + case KeyPress: + case KeyRelease: + SWAPEV("xxxxllllsssssxx"); +#define WIRE wire_event.u.keyButtonPointer + ev->xkey.window = WIRE.event; + ev->xkey.root = WIRE.root; + ev->xkey.subwindow = WIRE.child; + ev->xkey.time = WIRE.time; + ev->xkey.x = cvtINT16toInt(WIRE.eventX); + ev->xkey.y = cvtINT16toInt(WIRE.eventY); + ev->xkey.x_root = cvtINT16toInt(WIRE.rootX); + ev->xkey.y_root = cvtINT16toInt(WIRE.rootY); + ev->xkey.state = WIRE.state; + ev->xkey.keycode = wire_event.u.u.detail; + ev->xkey.same_screen = WIRE.sameScreen; +#undef WIRE + break; + case ButtonPress: + case ButtonRelease: + SWAPEV("xxxxllllsssssxx"); +#define WIRE wire_event.u.keyButtonPointer + ev->xbutton.window = WIRE.event; + ev->xbutton.root = WIRE.root; + ev->xbutton.subwindow = WIRE.child; + ev->xbutton.time = WIRE.time; + ev->xbutton.x = cvtINT16toInt(WIRE.eventX); + ev->xbutton.y = cvtINT16toInt(WIRE.eventY); + ev->xbutton.x_root = cvtINT16toInt(WIRE.rootX); + ev->xbutton.y_root = cvtINT16toInt(WIRE.rootY); + ev->xbutton.state = WIRE.state; + ev->xbutton.button = wire_event.u.u.detail; + ev->xbutton.same_screen = WIRE.sameScreen; +#undef WIRE + break; + case MotionNotify: + SWAPEV("xxxxllllsssssxx"); +#define WIRE wire_event.u.keyButtonPointer + ev->xmotion.window = WIRE.event; + ev->xmotion.root = WIRE.root; + ev->xmotion.subwindow = WIRE.child; + ev->xmotion.time = WIRE.time; + ev->xmotion.x = cvtINT16toInt(WIRE.eventX); + ev->xmotion.y = cvtINT16toInt(WIRE.eventY); + ev->xmotion.x_root = cvtINT16toInt(WIRE.rootX); + ev->xmotion.y_root = cvtINT16toInt(WIRE.rootY); + ev->xmotion.state = WIRE.state; + ev->xmotion.is_hint = wire_event.u.u.detail; + ev->xmotion.same_screen = WIRE.sameScreen; +#undef WIRE + break; + default: + /* + * For now, this function deals only Key/Pointer events. + */ + return 0; + } +#undef SWAPEV + + return 1; /* success */ +} + +/*- postponeEvent: record events for delayed processing -*/ +static void +postponeEvent(icp, synchronous, ev) +IMIC *icp; +int synchronous; +XEvent *ev; +{ + IMPendingEvent *pending; + + pending = XtNew(IMPendingEvent); + pending->ic = icp; + pending->synchronous = synchronous; + bcopy((char *)ev, (char *)&pending->event, sizeof(XEvent)); + pending->next = icp->pending_events; + icp->pending_events = pending; +} + +/*- handleForwardedEvent: deal with forwarded events -*/ +static void +handleForwardedEvent(icp, synchronous, ev) +IMIC *icp; +int synchronous; +XEvent *ev; +{ + IMConnection *conn = icp->im->connection; + + TRACE(("handleForwardedEvent()\n")); + + icp->state |= IC_FORWARDING; + + if (icp->state & IC_SYNCING) { + /* + * We are waiting for SYNC_REPLY message. + * Postpone event processing. + */ + DDPRINT(2, ("forward event processing suspended\n")); + postponeEvent(icp, synchronous, ev); + return; + } + + IMForwardEvent(icp, ev); + +#ifdef notyet + if (synchronous) { + if (!(icp->state & IC_CONVERTING)) { + /* + * Stop forwarding key events. + */ + IMStopForwarding(icp); + } + /* + * All the processing is done. Send XIM_SYNC_REPLY. + */ + IMSendRequestWithIC(conn, XIM_SYNC_REPLY, 0, icp); + } else { + int cur_pos2; + + cur_pos2 = IMWritePos(conn); + if (!(icp->state & IC_CONVERTING)) { + /* + * Stop forwarding key events. + */ + IMStopForwarding(icp); + /* + * Put dummy commit request (for setting sync flag). + */ + } + } +#else + /* + * Currently, kinput2 supports only full synchronous method. + */ + if (!(icp->state & IC_CONVERTING)) { + /* + * Stop forwarding key events. + */ + IMStopForwarding(icp); + } + /* + * All the processing is done. Send XIM_SYNC_REPLY. + */ + if (icp->state & IC_FORWARDING) { + icp->state &= ~IC_FORWARDING; + IMSendRequestWithIC(conn, XIM_SYNC_REPLY, 0, icp); + } +#endif +} + +/*- ximForwardEventProc: handle XIM_FORWARD_EVENT request -*/ +/* ARGSUSED */ +static void +ximForwardEventProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + int synchronous; + unsigned int serial; + XEvent event; + + TRACE(("ximForwardEventProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 40) { + DPRINT(("ximForwardEventProc: arglen != 40\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + synchronous = IMGetC16(conn, 4) & 1; + serial = IMGetC16(conn, 6); + + if (getEvent(conn, serial, 8, &event)) { + handleForwardedEvent(icp, synchronous, &event); + } +} + +/*- ximExtForwardKeyeventProc: handle XIM_EXT_FORWARD_KEYEVENT_MASK request -*/ +/* ARGSUSED */ +static void +ximExtForwardKeyeventProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + int synchronous; + int type; + unsigned int serial; + XEvent event; + + TRACE(("ximExtForwardKeyeventProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + + if (!(icp->im->mask & XIM_EXT_FORWARD_KEYEVENT_MASK)) { + DPRINT(("ximExtForwardKeyeventProc: ext_forward_keyevent disabled\n")); + IMSendBadProtocol(conn, "ext_forward_keyevent extension not enabled"); + return; + } + + if (arglen != 16) { + DPRINT(("ximExtForwardKeyeventProc: arglen != 16\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + + synchronous = IMGetC16(conn, 4) & 1; + serial = IMGetC16(conn, 6); + type = IMGetC8(conn, 8); + if (type != KeyPress && type != KeyRelease) { + /* Badtype */ + IMSendError(conn, IMBadSomething, icp->im->id, icp->id, + "forwarded event is invalid type"); + return; + } + + event.type = type; + event.xkey.serial = serial; /* ??? */ + event.xkey.keycode = IMGetC8(conn, 9); + event.xkey.state = IMGetC16(conn, 10); + event.xkey.time = IMGetC32(conn, 12); + event.xkey.window = IMGetC32(conn, 16); + event.xkey.root = icp->client_profile.root; + event.xkey.subwindow = None; + event.xkey.x = 0; + event.xkey.y = 0; + event.xkey.x_root = 0; + event.xkey.y_root = 0; + event.xkey.same_screen = True; + + handleForwardedEvent(icp, synchronous, &event); +} + +/*- ximSyncProc: handle XIM_SYNC request -*/ +/* ARGSUSED */ +static void +ximSyncProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + + TRACE(("ximSyncProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximSyncProc: arglen != 4\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + IMSendRequestWithIC(conn, XIM_SYNC_REPLY, 0, icp); +} + +/*- processPendingEvents: process pending events forwarded by the client -*/ +static void +processPendingEvents(icp, pending_event) +IMIC *icp; +IMPendingEvent *pending_event; +{ + /* + * Pending events list is in reverse order. + * Processing is done from the tail of the list, using + * recursive call. + */ + if (pending_event == NULL) return; + processPendingEvents(icp, pending_event->next); + pending_event->next = NULL; + handleForwardedEvent(icp, pending_event->synchronous, + &pending_event->event); + XtFree((char *)pending_event); +} + +/*- ximSyncReplyProc: handle XIM_SYNC_REPLY message -*/ +/* ARGSUSED */ +static void +ximSyncReplyProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + + TRACE(("ximSyncReplyProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximSyncReplyProc: arglen != 4\n")); + return; + } + if (icp->state & IC_SYNCING) { + icp->state &= ~IC_SYNCING; + processPendingEvents(icp, icp->pending_events); + } +} + +/*- ximResetICProc: handle XIM_RESET_IC message -*/ +/* ARGSUSED */ +static void +ximResetICProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + char *text = NULL; + int offset; + int text_length; + + TRACE(("ximResetICProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + if (arglen != 4) { + DPRINT(("ximResetICProc: arglen != 4\n")); + IMSendBadLength(conn, icp->im->id, icp->id); + return; + } + icp->state |= IC_RESETTING; + text_length = IMResetIC(icp, &text); + + offset = IMPutHeader(conn, XIM_RESET_IC_REPLY, 0, 0); + IMPutC16(conn, icp->im->id); + IMPutC16(conn, icp->id); + IMPutC16(conn, (unsigned int)text_length); + if (text_length > 0) IMPutString(conn, text, text_length); + IMFinishRequest(conn, offset); + if (text != NULL) XtFree(text); + icp->state &= ~IC_RESETTING; +} + +/*- ximExtMoveProc: handle XIM_EXT_MOVE request -*/ +/* ARGSUSED */ +static void +ximExtMoveProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + IMIC *icp; + int x, y; + + TRACE(("ximExtMoveProc(#%d)\n", conn->serial)); + + if ((icp = IMGetIC(conn, arglen)) == NULL) return; + x = IMGetI16(conn, 4); + y = IMGetI16(conn, 6); + IMMoveLocation(icp, x, y); +} + +/*- ximAlreadyConnectedProc: handle duplicate XIM_CONNECT request -*/ +/* ARGSUSED */ +static void +ximAlreadyConnectedProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + TRACE(("ximAlreadyConnectedProc(#%d)\n", conn->serial)); + + DPRINT(("connection #%d sent multiple XIM_CONNECT request\n", + conn->serial)); + IMSendBadProtocol(conn, "duplicate XIM_CONNECT message"); +} + +/*- ximShouldNotBeSentProc: handle requests which clients should not send -*/ +/* ARGSUSED */ +static void +ximShouldNotBeSentProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + TRACE(("ximShouldNotBeSentProc(#%d)\n", conn->serial)); + + DPRINT(("connection #%d sent invalid request\n", conn->serial)) + IMSendBadProtocol(conn, "Clients should not send this request"); +} + +/*- ximAuthPhaseProc: handle requests for authentication -*/ +/* ARGSUSED */ +static void +ximAuthPhaseProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + TRACE(("ximAuthPhaseProc(#%d)\n", conn->serial)); + + DPRINT(("connection #%d sends auth-related request\n", conn->serial)); + IMSendBadProtocol(conn, "not authentication phase"); +} + +/*- ximNopProc: nop -*/ +/* ARGSUSED */ +static void +ximNopProc(conn, major, minor, arglen) +IMConnection *conn; +int major; +int minor; +int arglen; +{ + TRACE(("ximNopProc(#%d)\n", conn->serial)); + + /* do nothing */ +} + +/* + * Public Function + */ + +/*- IMCompileReq: initialize IMMainDispatchTable -*/ +void +IMCompileReq() +{ + static int compiled = 0; + + if (compiled) return; + compileTbl(coreRequestTbl); + compileTbl(extRequestTbl); + compiled = 1; +}