1 /******************************************************************
2 
3          Copyright 1994, 1995 by Sun Microsystems, Inc.
4          Copyright 1993, 1994 by Hewlett-Packard Company
5 
6 Permission to use, copy, modify, distribute, and sell this software
7 and its documentation for any purpose is hereby granted without fee,
8 provided that the above copyright notice appear in all copies and
9 that both that copyright notice and this permission notice appear
10 in supporting documentation, and that the name of Sun Microsystems, Inc.
11 and Hewlett-Packard not be used in advertising or publicity pertaining to
12 distribution of the software without specific, written prior permission.
13 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
14 the suitability of this software for any purpose.  It is provided "as is"
15 without express or implied warranty.
16 
17 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
18 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
21 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
23 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
24 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 
26   Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
27 
28     This version tidied and debugged by Steve Underwood May 1999
29 
30 ******************************************************************/
31 
32 #include <X11/Xlib.h>
33 #include <X11/Xatom.h>
34 #include "FrameMgr.h"
35 #include "IMdkit.h"
36 #include "Xi18n.h"
37 #include "Xi18nX.h"
38 #include "XimFunc.h"
39 
40 extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
41 extern Xi18nClient *_Xi18nNewClient(Xi18n);
42 extern void _Xi18nDeleteClient(Xi18n, CARD16);
43 static Bool WaitXConnectMessage(Display*, Window,
44                                 XEvent*, XPointer);
45 static Bool WaitXIMProtocol(Display*, Window, XEvent*, XPointer);
46 
NewXClient(Xi18n i18n_core,Window new_client)47 static XClient *NewXClient(Xi18n i18n_core, Window new_client)
48 {
49     Display *dpy = i18n_core->address.dpy;
50     Xi18nClient *client = _Xi18nNewClient(i18n_core);
51     XClient *x_client;
52 
53     x_client = (XClient *) malloc(sizeof(XClient));
54     x_client->client_win = new_client;
55     x_client->accept_win = XCreateSimpleWindow(dpy,
56                            DefaultRootWindow(dpy),
57                            0,
58                            0,
59                            1,
60                            1,
61                            1,
62                            0,
63                            0);
64     client->trans_rec = x_client;
65     return ((XClient *) x_client);
66 }
67 
ReadXIMMessage(XIMS ims,XClientMessageEvent * ev,int * connect_id)68 static unsigned char *ReadXIMMessage(XIMS ims,
69                                      XClientMessageEvent *ev,
70                                      int *connect_id)
71 {
72     Xi18n i18n_core = ims->protocol;
73     Xi18nClient *client = i18n_core->address.clients;
74     XClient *x_client = NULL;
75     FrameMgr fm;
76     extern XimFrameRec packet_header_fr[];
77     unsigned char *p = NULL;
78     unsigned char *p1;
79 
80     while (client != NULL) {
81         x_client = (XClient *) client->trans_rec;
82         if (x_client->accept_win == ev->window) {
83             *connect_id = client->connect_id;
84             break;
85         }
86         client = client->next;
87     }
88 
89     if (ev->format == 8) {
90         /* ClientMessage only */
91         XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
92         unsigned char *rec = (unsigned char *)(hdr + 1);
93         register int total_size;
94         CARD8 major_opcode;
95         CARD8 minor_opcode;
96         CARD16 length;
97         extern int _Xi18nNeedSwap(Xi18n, CARD16);
98 
99         if (client->byte_order == '?') {
100             if (hdr->major_opcode != XIM_CONNECT)
101                 return (unsigned char *) NULL;  /* can do nothing */
102             client->byte_order = (CARD8) rec[0];
103         }
104 
105         fm = FrameMgrInit(packet_header_fr,
106                           (char *) hdr,
107                           _Xi18nNeedSwap(i18n_core, *connect_id));
108         total_size = FrameMgrGetTotalSize(fm);
109         /* get data */
110         FrameMgrGetToken(fm, major_opcode);
111         FrameMgrGetToken(fm, minor_opcode);
112         FrameMgrGetToken(fm, length);
113         FrameMgrFree(fm);
114 
115         if ((p = (unsigned char *) malloc(total_size + length * 4)) == NULL)
116             return (unsigned char *) NULL;
117 
118         p1 = p;
119         memcpy(p1, &major_opcode, sizeof(CARD8));
120         p1 += sizeof(CARD8);
121         memcpy(p1, &minor_opcode, sizeof(CARD8));
122         p1 += sizeof(CARD8);
123         memcpy(p1, &length, sizeof(CARD16));
124         p1 += sizeof(CARD16);
125         memcpy(p1, rec, length * 4);
126     } else if (ev->format == 32) {
127         /* ClientMessage and WindowProperty */
128         unsigned long length = (unsigned long) ev->data.l[0];
129         Atom atom = (Atom) ev->data.l[1];
130         int return_code;
131         Atom    actual_type_ret;
132         int actual_format_ret;
133         unsigned long bytes_after_ret;
134         unsigned char *prop;
135         unsigned long nitems;
136 
137         return_code = XGetWindowProperty(i18n_core->address.dpy,
138                                          x_client->accept_win,
139                                          atom,
140                                          0L,
141                                          length,
142                                          True,
143                                          AnyPropertyType,
144                                          &actual_type_ret,
145                                          &actual_format_ret,
146                                          &nitems,
147                                          &bytes_after_ret,
148                                          &prop);
149         if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
150             if (return_code == Success)
151                 XFree(prop);
152             return (unsigned char *) NULL;
153         }
154         if (length != nitems)
155             length = nitems;
156         if (actual_format_ret == 16)
157             length *= 2;
158         else if (actual_format_ret == 32)
159             length *= 4;
160 
161         /* if hit, it might be an error */
162         if ((p = (unsigned char *) malloc(length)) == NULL)
163             return (unsigned char *) NULL;
164 
165         memcpy(p, prop, length);
166         XFree(prop);
167     }
168     return (unsigned char *) p;
169 }
170 
ReadXConnectMessage(XIMS ims,XClientMessageEvent * ev)171 static void ReadXConnectMessage(XIMS ims, XClientMessageEvent *ev)
172 {
173     Xi18n i18n_core = ims->protocol;
174     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
175     XEvent event;
176     Display *dpy = i18n_core->address.dpy;
177     Window new_client = ev->data.l[0];
178     CARD32 major_version = ev->data.l[1];
179     CARD32 minor_version = ev->data.l[2];
180     XClient *x_client = NewXClient(i18n_core, new_client);
181 
182     if (ev->window != i18n_core->address.im_window)
183         return;             /* incorrect connection request */
184     /*endif*/
185     if (major_version != 0  ||  minor_version != 0) {
186         major_version =
187             minor_version = 0;
188         /* Only supporting only-CM & Property-with-CM method */
189     }
190     /*endif*/
191     _XRegisterFilterByType(dpy,
192                            x_client->accept_win,
193                            ClientMessage,
194                            ClientMessage,
195                            WaitXIMProtocol,
196                            (XPointer)ims);
197     event.xclient.type = ClientMessage;
198     event.xclient.display = dpy;
199     event.xclient.window = new_client;
200     event.xclient.message_type = spec->connect_request;
201     event.xclient.format = 32;
202     event.xclient.data.l[0] = x_client->accept_win;
203     event.xclient.data.l[1] = major_version;
204     event.xclient.data.l[2] = minor_version;
205     event.xclient.data.l[3] = XCM_DATA_LIMIT;
206 
207     XSendEvent(dpy,
208                new_client,
209                False,
210                NoEventMask,
211                &event);
212     XFlush(dpy);
213 }
214 
Xi18nXBegin(XIMS ims)215 static Bool Xi18nXBegin(XIMS ims)
216 {
217     Xi18n i18n_core = ims->protocol;
218     Display *dpy = i18n_core->address.dpy;
219     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
220 
221     spec->xim_request = XInternAtom(i18n_core->address.dpy,
222                                     _XIM_PROTOCOL,
223                                     False);
224     spec->connect_request = XInternAtom(i18n_core->address.dpy,
225                                         _XIM_XCONNECT,
226                                         False);
227 
228     _XRegisterFilterByType(dpy,
229                            i18n_core->address.im_window,
230                            ClientMessage,
231                            ClientMessage,
232                            WaitXConnectMessage,
233                            (XPointer)ims);
234     return True;
235 }
236 
Xi18nXEnd(XIMS ims)237 static Bool Xi18nXEnd(XIMS ims)
238 {
239     Xi18n i18n_core = ims->protocol;
240     Display *dpy = i18n_core->address.dpy;
241 
242     _XUnregisterFilter(dpy,
243                        i18n_core->address.im_window,
244                        WaitXConnectMessage,
245                        (XPointer)ims);
246     return True;
247 }
248 
MakeNewAtom(CARD16 connect_id,char * atomName)249 static char *MakeNewAtom(CARD16 connect_id, char *atomName)
250 {
251     static int sequence = 0;
252 
253     sprintf(atomName,
254             "_server%d_%d",
255             connect_id,
256             ((sequence > 20)  ? (sequence = 0)  :  sequence++));
257     return atomName;
258 }
259 
Xi18nXSend(XIMS ims,CARD16 connect_id,unsigned char * reply,long length)260 static Bool Xi18nXSend(XIMS ims,
261                        CARD16 connect_id,
262                        unsigned char *reply,
263                        long length)
264 {
265     Xi18n i18n_core = ims->protocol;
266     Xi18nClient *client = _Xi18nFindClient(i18n_core, connect_id);
267     if (!client)
268         return False;
269     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
270     XClient *x_client = (XClient *) client->trans_rec;
271     XEvent event;
272 
273     event.type = ClientMessage;
274     event.xclient.window = x_client->client_win;
275     event.xclient.message_type = spec->xim_request;
276 
277     if (length > XCM_DATA_LIMIT) {
278         Atom atom;
279         char atomName[16];
280         Atom actual_type_ret;
281         int actual_format_ret;
282         int return_code;
283         unsigned long nitems_ret;
284         unsigned long bytes_after_ret;
285         unsigned char *win_data;
286 
287         event.xclient.format = 32;
288         atom = XInternAtom(i18n_core->address.dpy,
289                            MakeNewAtom(connect_id, atomName),
290                            False);
291         return_code = XGetWindowProperty(i18n_core->address.dpy,
292                                          x_client->client_win,
293                                          atom,
294                                          0L,
295                                          10000L,
296                                          False,
297                                          XA_STRING,
298                                          &actual_type_ret,
299                                          &actual_format_ret,
300                                          &nitems_ret,
301                                          &bytes_after_ret,
302                                          &win_data);
303         if (return_code != Success)
304             return False;
305         /*endif*/
306         if (win_data)
307             XFree((char *) win_data);
308         /*endif*/
309         XChangeProperty(i18n_core->address.dpy,
310                         x_client->client_win,
311                         atom,
312                         XA_STRING,
313                         8,
314                         PropModeAppend,
315                         (unsigned char *) reply,
316                         length);
317         event.xclient.data.l[0] = length;
318         event.xclient.data.l[1] = atom;
319     } else {
320         unsigned char buffer[XCM_DATA_LIMIT];
321         int i;
322 
323         event.xclient.format = 8;
324 
325         /* Clear unused field with NULL */
326         memcpy(buffer, reply, length);
327         for (i = length; i < XCM_DATA_LIMIT; i++)
328             buffer[i] = (char) 0;
329         /*endfor*/
330         length = XCM_DATA_LIMIT;
331         memcpy(event.xclient.data.b, buffer, length);
332     }
333     XSendEvent(i18n_core->address.dpy,
334                x_client->client_win,
335                False,
336                NoEventMask,
337                &event);
338     XFlush(i18n_core->address.dpy);
339     return True;
340 }
341 
CheckCMEvent(Display * display,XEvent * event,XPointer xi18n_core)342 static Bool CheckCMEvent(Display *display, XEvent *event, XPointer xi18n_core)
343 {
344     Xi18n i18n_core = (Xi18n)((void *) xi18n_core);
345     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
346 
347     if ((event->type == ClientMessage)
348             &&
349             (event->xclient.message_type == spec->xim_request)) {
350         return  True;
351     }
352     /*endif*/
353     return  False;
354 }
355 
Xi18nXWait(XIMS ims,CARD16 connect_id,CARD8 major_opcode,CARD8 minor_opcode)356 static Bool Xi18nXWait(XIMS ims,
357                        CARD16 connect_id,
358                        CARD8 major_opcode,
359                        CARD8 minor_opcode)
360 {
361     Xi18n i18n_core = ims->protocol;
362     XEvent event;
363     Xi18nClient *client = _Xi18nFindClient(i18n_core, connect_id);
364     if (!client)
365         return False;
366     XClient *x_client = (XClient *) client->trans_rec;
367 
368     for (;;) {
369         unsigned char *packet;
370         XimProtoHdr *hdr;
371         int connect_id_ret;
372 
373         XIfEvent(i18n_core->address.dpy,
374                  &event,
375                  CheckCMEvent,
376                  (XPointer) i18n_core);
377         if (event.xclient.window == x_client->accept_win) {
378             if ((packet = ReadXIMMessage(ims,
379                                          (XClientMessageEvent *) & event,
380                                          &connect_id_ret))
381                     == (unsigned char*) NULL) {
382                 return False;
383             }
384             /*endif*/
385             hdr = (XimProtoHdr *)packet;
386 
387             if ((hdr->major_opcode == major_opcode)
388                     &&
389                     (hdr->minor_opcode == minor_opcode)) {
390                 return True;
391             } else if (hdr->major_opcode == XIM_ERROR) {
392                 return False;
393             }
394             /*endif*/
395         }
396         /*endif*/
397     }
398     /*endfor*/
399 }
400 
Xi18nXDisconnect(XIMS ims,CARD16 connect_id)401 static Bool Xi18nXDisconnect(XIMS ims, CARD16 connect_id)
402 {
403     Xi18n i18n_core = ims->protocol;
404     Display *dpy = i18n_core->address.dpy;
405     Xi18nClient *client = _Xi18nFindClient(i18n_core, connect_id);
406     if (!client)
407         return False;
408     XClient *x_client = (XClient *) client->trans_rec;
409 
410     XDestroyWindow(dpy, x_client->accept_win);
411     _XUnregisterFilter(dpy,
412                        x_client->accept_win,
413                        WaitXIMProtocol,
414                        (XPointer)ims);
415     XFree(x_client);
416     _Xi18nDeleteClient(i18n_core, connect_id);
417     return True;
418 }
419 
_Xi18nCheckXAddress(Xi18n i18n_core,TransportSW * transSW,char * address)420 Bool _Xi18nCheckXAddress(Xi18n i18n_core,
421                          TransportSW *transSW,
422                          char *address)
423 {
424     XSpecRec *spec;
425 
426     if (!(spec = (XSpecRec *) malloc(sizeof(XSpecRec))))
427         return False;
428     /*endif*/
429 
430     i18n_core->address.connect_addr = (XSpecRec *) spec;
431     i18n_core->methods.begin = Xi18nXBegin;
432     i18n_core->methods.end = Xi18nXEnd;
433     i18n_core->methods.send = Xi18nXSend;
434     i18n_core->methods.wait = Xi18nXWait;
435     i18n_core->methods.disconnect = Xi18nXDisconnect;
436     return True;
437 }
438 
WaitXConnectMessage(Display * dpy,Window win,XEvent * ev,XPointer client_data)439 static Bool WaitXConnectMessage(Display *dpy,
440                                 Window win,
441                                 XEvent *ev,
442                                 XPointer client_data)
443 {
444     XIMS ims = (XIMS)client_data;
445     Xi18n i18n_core = ims->protocol;
446     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
447 
448     if (((XClientMessageEvent *) ev)->message_type
449             == spec->connect_request) {
450         ReadXConnectMessage(ims, (XClientMessageEvent *) ev);
451         return True;
452     }
453     /*endif*/
454     return False;
455 }
456 
WaitXIMProtocol(Display * dpy,Window win,XEvent * ev,XPointer client_data)457 static Bool WaitXIMProtocol(Display *dpy,
458                             Window win,
459                             XEvent *ev,
460                             XPointer client_data)
461 {
462     extern void _Xi18nMessageHandler(XIMS, CARD16, unsigned char *, Bool *);
463     XIMS ims = (XIMS) client_data;
464     Xi18n i18n_core = ims->protocol;
465     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
466     Bool delete = True;
467     unsigned char *packet;
468     int connect_id;
469 
470     if (((XClientMessageEvent *) ev)->message_type
471             == spec->xim_request) {
472         if ((packet = ReadXIMMessage(ims,
473                                      (XClientMessageEvent *) ev,
474                                      &connect_id))
475                 == (unsigned char *)  NULL) {
476             return False;
477         }
478         /*endif*/
479         _Xi18nMessageHandler(ims, connect_id, packet, &delete);
480         if (delete == True)
481             XFree(packet);
482         /*endif*/
483         return True;
484     }
485     /*endif*/
486     return False;
487 }
488 
489 // kate: indent-mode cstyle; space-indent on; indent-width 0;
490