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         {
101             if (hdr->major_opcode != XIM_CONNECT)
102                 return (unsigned char *) NULL; 	/* can do nothing */
103             client->byte_order = (CARD8) rec[0];
104         }
105 
106         fm = FrameMgrInit (packet_header_fr,
107                            (char *) hdr,
108                            _Xi18nNeedSwap (i18n_core, *connect_id));
109         total_size = FrameMgrGetTotalSize (fm);
110         /* get data */
111         FrameMgrGetToken (fm, major_opcode);
112         FrameMgrGetToken (fm, minor_opcode);
113         FrameMgrGetToken (fm, length);
114         FrameMgrFree (fm);
115 
116         if ((p = (unsigned char *) malloc (total_size + length * 4)) == NULL)
117             return (unsigned char *) NULL;
118 
119         p1 = p;
120         memmove (p1, &major_opcode, sizeof (CARD8));
121         p1 += sizeof (CARD8);
122         memmove (p1, &minor_opcode, sizeof (CARD8));
123         p1 += sizeof (CARD8);
124         memmove (p1, &length, sizeof (CARD16));
125         p1 += sizeof (CARD16);
126         memmove (p1, rec, length * 4);
127     }
128     else if (ev->format == 32) {
129         /* ClientMessage and WindowProperty */
130         unsigned long length = (unsigned long) ev->data.l[0];
131         Atom atom = (Atom) ev->data.l[1];
132         int	return_code;
133         Atom	actual_type_ret;
134         int	actual_format_ret;
135         unsigned long bytes_after_ret;
136         unsigned char *prop;
137         unsigned long nitems;
138 
139         return_code = XGetWindowProperty (i18n_core->address.dpy,
140                                           x_client->accept_win,
141                                           atom,
142                                           0L,
143                                           length,
144                                           True,
145                                           AnyPropertyType,
146                                           &actual_type_ret,
147                                           &actual_format_ret,
148                                           &nitems,
149                                           &bytes_after_ret,
150                                           &prop);
151         if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
152             if (return_code == Success)
153                 XFree (prop);
154             return (unsigned char *) NULL;
155         }
156         if (length != nitems)
157             length = nitems;
158 	if (actual_format_ret == 16)
159 	    length *= 2;
160 	else if (actual_format_ret == 32)
161 	    length *= 4;
162 
163         /* if hit, it might be an error */
164         if ((p = (unsigned char *) malloc (length)) == NULL)
165             return (unsigned char *) NULL;
166 
167         memmove (p, prop, length);
168         XFree (prop);
169     }
170     return (unsigned char *) p;
171 }
172 
ReadXConnectMessage(XIMS ims,XClientMessageEvent * ev)173 static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev)
174 {
175     Xi18n i18n_core = ims->protocol;
176     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
177     XEvent event;
178     Display *dpy = i18n_core->address.dpy;
179     Window new_client = ev->data.l[0];
180     CARD32 major_version = ev->data.l[1];
181     CARD32 minor_version = ev->data.l[2];
182     XClient *x_client = NewXClient (i18n_core, new_client);
183 
184     if (ev->window != i18n_core->address.im_window)
185         return; 			/* incorrect connection request */
186     /*endif*/
187     if (major_version != 0  ||  minor_version != 0)
188     {
189         major_version =
190         minor_version = 0;
191         /* Only supporting only-CM & Property-with-CM method */
192     }
193     /*endif*/
194     _XRegisterFilterByType (dpy,
195                             x_client->accept_win,
196                             ClientMessage,
197                             ClientMessage,
198                             WaitXIMProtocol,
199                             (XPointer)ims);
200     event.xclient.type = ClientMessage;
201     event.xclient.display = dpy;
202     event.xclient.window = new_client;
203     event.xclient.message_type = spec->connect_request;
204     event.xclient.format = 32;
205     event.xclient.data.l[0] = x_client->accept_win;
206     event.xclient.data.l[1] = major_version;
207     event.xclient.data.l[2] = minor_version;
208     event.xclient.data.l[3] = XCM_DATA_LIMIT;
209 
210     XSendEvent (dpy,
211                 new_client,
212                 False,
213                 NoEventMask,
214                 &event);
215     XFlush (dpy);
216 }
217 
Xi18nXBegin(XIMS ims)218 static Bool Xi18nXBegin (XIMS ims)
219 {
220     Xi18n i18n_core = ims->protocol;
221     Display *dpy = i18n_core->address.dpy;
222     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
223 
224     spec->xim_request = XInternAtom (i18n_core->address.dpy,
225                                      _XIM_PROTOCOL,
226                                      False);
227     spec->connect_request = XInternAtom (i18n_core->address.dpy,
228                                          _XIM_XCONNECT,
229                                          False);
230 
231     _XRegisterFilterByType (dpy,
232                             i18n_core->address.im_window,
233                             ClientMessage,
234                             ClientMessage,
235                             WaitXConnectMessage,
236                             (XPointer)ims);
237     return True;
238 }
239 
Xi18nXEnd(XIMS ims)240 static Bool Xi18nXEnd(XIMS ims)
241 {
242     Xi18n i18n_core = ims->protocol;
243     Display *dpy = i18n_core->address.dpy;
244 
245     _XUnregisterFilter (dpy,
246                         i18n_core->address.im_window,
247                         WaitXConnectMessage,
248                         (XPointer)ims);
249     return True;
250 }
251 
MakeNewAtom(CARD16 connect_id,char * atomName)252 static char *MakeNewAtom (CARD16 connect_id, char *atomName)
253 {
254     static int sequence = 0;
255 
256     sprintf (atomName,
257              "_server%d_%d",
258              connect_id,
259              ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
260     return atomName;
261 }
262 
Xi18nXSend(XIMS ims,CARD16 connect_id,unsigned char * reply,long length)263 static Bool Xi18nXSend (XIMS ims,
264                         CARD16 connect_id,
265                         unsigned char *reply,
266                         long length)
267 {
268     Xi18n i18n_core = ims->protocol;
269     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
270     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
271     XClient *x_client = (XClient *) client->trans_rec;
272     XEvent event;
273 
274     event.type = ClientMessage;
275     event.xclient.window = x_client->client_win;
276     event.xclient.message_type = spec->xim_request;
277 
278     if (length > XCM_DATA_LIMIT)
279     {
280         Atom atom;
281         char atomName[16];
282         Atom actual_type_ret;
283         int actual_format_ret;
284         int return_code;
285         unsigned long nitems_ret;
286         unsigned long bytes_after_ret;
287         unsigned char *win_data;
288 
289         event.xclient.format = 32;
290         atom = XInternAtom (i18n_core->address.dpy,
291                             MakeNewAtom (connect_id, atomName),
292                             False);
293         return_code = XGetWindowProperty (i18n_core->address.dpy,
294                                           x_client->client_win,
295                                           atom,
296                                           0L,
297                                           10000L,
298                                           False,
299                                           XA_STRING,
300                                           &actual_type_ret,
301                                           &actual_format_ret,
302                                           &nitems_ret,
303                                           &bytes_after_ret,
304                                           &win_data);
305         if (return_code != Success)
306             return False;
307         /*endif*/
308         if (win_data)
309             XFree ((char *) win_data);
310         /*endif*/
311         XChangeProperty (i18n_core->address.dpy,
312                          x_client->client_win,
313                          atom,
314                          XA_STRING,
315                          8,
316                          PropModeAppend,
317                          (unsigned char *) reply,
318                          length);
319         event.xclient.data.l[0] = length;
320         event.xclient.data.l[1] = atom;
321     }
322     else
323     {
324         unsigned char buffer[XCM_DATA_LIMIT];
325         int i;
326 
327         event.xclient.format = 8;
328 
329         /* Clear unused field with NULL */
330         memmove(buffer, reply, length);
331         for (i = length; i < XCM_DATA_LIMIT; i++)
332             buffer[i] = (char) 0;
333         /*endfor*/
334         length = XCM_DATA_LIMIT;
335         memmove (event.xclient.data.b, buffer, length);
336     }
337     XSendEvent (i18n_core->address.dpy,
338                 x_client->client_win,
339                 False,
340                 NoEventMask,
341                 &event);
342     XFlush (i18n_core->address.dpy);
343     return True;
344 }
345 
CheckCMEvent(Display * display,XEvent * event,XPointer xi18n_core)346 static Bool CheckCMEvent (Display *display, XEvent *event, XPointer xi18n_core)
347 {
348     Xi18n i18n_core = (Xi18n) ((void *) xi18n_core);
349     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
350 
351     if ((event->type == ClientMessage)
352         &&
353         (event->xclient.message_type == spec->xim_request))
354     {
355         return  True;
356     }
357     /*endif*/
358     return  False;
359 }
360 
Xi18nXWait(XIMS ims,CARD16 connect_id,CARD8 major_opcode,CARD8 minor_opcode)361 static Bool Xi18nXWait (XIMS ims,
362                         CARD16 connect_id,
363                         CARD8 major_opcode,
364                         CARD8 minor_opcode)
365 {
366     Xi18n i18n_core = ims->protocol;
367     XEvent event;
368     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
369     XClient *x_client = (XClient *) client->trans_rec;
370 
371     for (;;)
372     {
373         unsigned char *packet;
374         XimProtoHdr *hdr;
375         int connect_id_ret;
376 
377         XIfEvent (i18n_core->address.dpy,
378                   &event,
379                   CheckCMEvent,
380                   (XPointer) i18n_core);
381         if (event.xclient.window == x_client->accept_win)
382         {
383             if ((packet = ReadXIMMessage (ims,
384                                           (XClientMessageEvent *) & event,
385                                           &connect_id_ret))
386                 == (unsigned char*) NULL)
387             {
388                 return False;
389             }
390             /*endif*/
391             hdr = (XimProtoHdr *)packet;
392 
393             if ((hdr->major_opcode == major_opcode)
394                 &&
395                 (hdr->minor_opcode == minor_opcode))
396             {
397                 return True;
398             }
399             else if (hdr->major_opcode == XIM_ERROR)
400             {
401                 return False;
402             }
403             /*endif*/
404         }
405         /*endif*/
406     }
407     /*endfor*/
408 }
409 
Xi18nXDisconnect(XIMS ims,CARD16 connect_id)410 static Bool Xi18nXDisconnect (XIMS ims, CARD16 connect_id)
411 {
412     Xi18n i18n_core = ims->protocol;
413     Display *dpy = i18n_core->address.dpy;
414     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
415     XClient *x_client = (XClient *) client->trans_rec;
416 
417     XDestroyWindow (dpy, x_client->accept_win);
418     _XUnregisterFilter (dpy,
419 		        x_client->accept_win,
420                         WaitXIMProtocol,
421 		        (XPointer)ims);
422     XFree (x_client);
423     _Xi18nDeleteClient (i18n_core, connect_id);
424     return True;
425 }
426 
_Xi18nCheckXAddress(Xi18n i18n_core,TransportSW * transSW,char * address)427 Bool _Xi18nCheckXAddress (Xi18n i18n_core,
428                           TransportSW *transSW,
429                           char *address)
430 {
431     XSpecRec *spec;
432 
433     if (!(spec = (XSpecRec *) malloc (sizeof (XSpecRec))))
434         return False;
435     /*endif*/
436 
437     i18n_core->address.connect_addr = (XSpecRec *) spec;
438     i18n_core->methods.begin = Xi18nXBegin;
439     i18n_core->methods.end = Xi18nXEnd;
440     i18n_core->methods.send = Xi18nXSend;
441     i18n_core->methods.wait = Xi18nXWait;
442     i18n_core->methods.disconnect = Xi18nXDisconnect;
443     return True;
444 }
445 
WaitXConnectMessage(Display * dpy,Window win,XEvent * ev,XPointer client_data)446 static Bool WaitXConnectMessage (Display *dpy,
447                                  Window win,
448                                  XEvent *ev,
449                                  XPointer client_data)
450 {
451     XIMS ims = (XIMS)client_data;
452     Xi18n i18n_core = ims->protocol;
453     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
454 
455     if (((XClientMessageEvent *) ev)->message_type
456         == spec->connect_request)
457     {
458         ReadXConnectMessage (ims, (XClientMessageEvent *) ev);
459         return True;
460     }
461     /*endif*/
462     return False;
463 }
464 
WaitXIMProtocol(Display * dpy,Window win,XEvent * ev,XPointer client_data)465 static Bool WaitXIMProtocol (Display *dpy,
466                              Window win,
467                              XEvent *ev,
468                              XPointer client_data)
469 {
470     extern void _Xi18nMessageHandler (XIMS, CARD16, unsigned char *, Bool *);
471     XIMS ims = (XIMS) client_data;
472     Xi18n i18n_core = ims->protocol;
473     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
474     Bool delete = True;
475     unsigned char *packet;
476     int connect_id;
477 
478     if (((XClientMessageEvent *) ev)->message_type
479         == spec->xim_request)
480     {
481         if ((packet = ReadXIMMessage (ims,
482                                       (XClientMessageEvent *) ev,
483                                       &connect_id))
484             == (unsigned char *)  NULL)
485         {
486             return False;
487         }
488         /*endif*/
489         _Xi18nMessageHandler (ims, connect_id, packet, &delete);
490         if (delete == True)
491             XFree (packet);
492         /*endif*/
493         return True;
494     }
495     /*endif*/
496     return False;
497 }
498