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     //pklong
211     //fprintf(stderr, "ReadXConnectMessage Serial: %ld\n", event.xclient.serial);
212     //
213     XSendEvent (dpy,
214                 new_client,
215                 False,
216                 NoEventMask,
217                 &event);
218     XFlush (dpy);
219 }
220 
Xi18nXBegin(XIMS ims)221 static Bool Xi18nXBegin (XIMS ims)
222 {
223     Xi18n i18n_core = ims->protocol;
224     Display *dpy = i18n_core->address.dpy;
225     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
226 
227     spec->xim_request = XInternAtom (i18n_core->address.dpy,
228                                      _XIM_PROTOCOL,
229                                      False);
230     spec->connect_request = XInternAtom (i18n_core->address.dpy,
231                                          _XIM_XCONNECT,
232                                          False);
233 
234     _XRegisterFilterByType (dpy,
235                             i18n_core->address.im_window,
236                             ClientMessage,
237                             ClientMessage,
238                             WaitXConnectMessage,
239                             (XPointer)ims);
240     return True;
241 }
242 
Xi18nXEnd(XIMS ims)243 static Bool Xi18nXEnd(XIMS ims)
244 {
245     Xi18n i18n_core = ims->protocol;
246     Display *dpy = i18n_core->address.dpy;
247 
248     _XUnregisterFilter (dpy,
249                         i18n_core->address.im_window,
250                         WaitXConnectMessage,
251                         (XPointer)ims);
252     return True;
253 }
254 
MakeNewAtom(CARD16 connect_id,char * atomName)255 static char *MakeNewAtom (CARD16 connect_id, char *atomName)
256 {
257     static int sequence = 0;
258 
259     sprintf (atomName,
260              "_server%d_%d",
261              connect_id,
262              ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
263     return atomName;
264 }
265 
Xi18nXSend(XIMS ims,CARD16 connect_id,unsigned char * reply,long length)266 static Bool Xi18nXSend (XIMS ims,
267                         CARD16 connect_id,
268                         unsigned char *reply,
269                         long length)
270 {
271     Xi18n i18n_core = ims->protocol;
272     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
273     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
274     XClient *x_client = (XClient *) client->trans_rec;
275     XEvent event;
276 
277     event.type = ClientMessage;
278     event.xclient.window = x_client->client_win;
279     event.xclient.message_type = spec->xim_request;
280 
281     if (length > XCM_DATA_LIMIT)
282     {
283         Atom atom;
284         char atomName[16];
285         Atom actual_type_ret;
286         int actual_format_ret;
287         int return_code;
288         unsigned long nitems_ret;
289         unsigned long bytes_after_ret;
290         unsigned char *win_data;
291 
292         event.xclient.format = 32;
293         atom = XInternAtom (i18n_core->address.dpy,
294                             MakeNewAtom (connect_id, atomName),
295                             False);
296         return_code = XGetWindowProperty (i18n_core->address.dpy,
297                                           x_client->client_win,
298                                           atom,
299                                           0L,
300                                           10000L,
301                                           False,
302                                           XA_STRING,
303                                           &actual_type_ret,
304                                           &actual_format_ret,
305                                           &nitems_ret,
306                                           &bytes_after_ret,
307                                           &win_data);
308         if (return_code != Success)
309             return False;
310         /*endif*/
311         if (win_data)
312             XFree ((char *) win_data);
313         /*endif*/
314         XChangeProperty (i18n_core->address.dpy,
315                          x_client->client_win,
316                          atom,
317                          XA_STRING,
318                          8,
319                          PropModeAppend,
320                          (unsigned char *) reply,
321                          length);
322         event.xclient.data.l[0] = length;
323         event.xclient.data.l[1] = atom;
324     }
325     else
326     {
327         unsigned char buffer[XCM_DATA_LIMIT];
328         int i;
329 
330         event.xclient.format = 8;
331 
332         /* Clear unused field with NULL */
333         memmove(buffer, reply, length);
334         for (i = length; i < XCM_DATA_LIMIT; i++)
335             buffer[i] = (char) 0;
336         /*endfor*/
337         length = XCM_DATA_LIMIT;
338         memmove (event.xclient.data.b, buffer, length);
339     }
340     XSendEvent (i18n_core->address.dpy,
341                 x_client->client_win,
342                 False,
343                 NoEventMask,
344                 &event);
345     XFlush (i18n_core->address.dpy);
346     return True;
347 }
348 
CheckCMEvent(Display * display,XEvent * event,XPointer xi18n_core)349 static Bool CheckCMEvent (Display *display, XEvent *event, XPointer xi18n_core)
350 {
351     Xi18n i18n_core = (Xi18n) ((void *) xi18n_core);
352     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
353 
354     if ((event->type == ClientMessage)
355         &&
356         (event->xclient.message_type == spec->xim_request))
357     {
358         return  True;
359     }
360     /*endif*/
361     return  False;
362 }
363 
Xi18nXWait(XIMS ims,CARD16 connect_id,CARD8 major_opcode,CARD8 minor_opcode)364 static Bool Xi18nXWait (XIMS ims,
365                         CARD16 connect_id,
366                         CARD8 major_opcode,
367                         CARD8 minor_opcode)
368 {
369     Xi18n i18n_core = ims->protocol;
370     XEvent event;
371     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
372     XClient *x_client = (XClient *) client->trans_rec;
373 
374     for (;;)
375     {
376         unsigned char *packet;
377         XimProtoHdr *hdr;
378         int connect_id_ret;
379 
380         XIfEvent (i18n_core->address.dpy,
381                   &event,
382                   CheckCMEvent,
383                   (XPointer) i18n_core);
384         if (event.xclient.window == x_client->accept_win)
385         {
386             if ((packet = ReadXIMMessage (ims,
387                                           (XClientMessageEvent *) & event,
388                                           &connect_id_ret))
389                 == (unsigned char*) NULL)
390             {
391                 return False;
392             }
393             /*endif*/
394             hdr = (XimProtoHdr *)packet;
395 
396             if ((hdr->major_opcode == major_opcode)
397                 &&
398                 (hdr->minor_opcode == minor_opcode))
399             {
400                 return True;
401             }
402             else if (hdr->major_opcode == XIM_ERROR)
403             {
404                 return False;
405             }
406             /*endif*/
407         }
408         /*endif*/
409     }
410     /*endfor*/
411 }
412 
Xi18nXDisconnect(XIMS ims,CARD16 connect_id)413 static Bool Xi18nXDisconnect (XIMS ims, CARD16 connect_id)
414 {
415     Xi18n i18n_core = ims->protocol;
416     Display *dpy = i18n_core->address.dpy;
417     Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
418     XClient *x_client = (XClient *) client->trans_rec;
419 
420     XDestroyWindow (dpy, x_client->accept_win);
421     _XUnregisterFilter (dpy,
422 		        x_client->accept_win,
423                         WaitXIMProtocol,
424 		        (XPointer)ims);
425     XFree (x_client);
426     _Xi18nDeleteClient (i18n_core, connect_id);
427     return True;
428 }
429 
_Xi18nCheckXAddress(Xi18n i18n_core,TransportSW * transSW,char * address)430 Bool _Xi18nCheckXAddress (Xi18n i18n_core,
431                           TransportSW *transSW,
432                           char *address)
433 {
434     XSpecRec *spec;
435 
436     if (!(spec = (XSpecRec *) malloc (sizeof (XSpecRec))))
437         return False;
438     /*endif*/
439 
440     i18n_core->address.connect_addr = (XSpecRec *) spec;
441     i18n_core->methods.begin = Xi18nXBegin;
442     i18n_core->methods.end = Xi18nXEnd;
443     i18n_core->methods.send = Xi18nXSend;
444     i18n_core->methods.wait = Xi18nXWait;
445     i18n_core->methods.disconnect = Xi18nXDisconnect;
446     return True;
447 }
448 
WaitXConnectMessage(Display * dpy,Window win,XEvent * ev,XPointer client_data)449 static Bool WaitXConnectMessage (Display *dpy,
450                                  Window win,
451                                  XEvent *ev,
452                                  XPointer client_data)
453 {
454     XIMS ims = (XIMS)client_data;
455     Xi18n i18n_core = ims->protocol;
456     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
457 
458     if (((XClientMessageEvent *) ev)->message_type
459         == spec->connect_request)
460     {
461         ReadXConnectMessage (ims, (XClientMessageEvent *) ev);
462         return True;
463     }
464     /*endif*/
465     return False;
466 }
467 
WaitXIMProtocol(Display * dpy,Window win,XEvent * ev,XPointer client_data)468 static Bool WaitXIMProtocol (Display *dpy,
469                              Window win,
470                              XEvent *ev,
471                              XPointer client_data)
472 {
473     extern void _Xi18nMessageHandler (XIMS, CARD16, unsigned char *, Bool *);
474     XIMS ims = (XIMS) client_data;
475     Xi18n i18n_core = ims->protocol;
476     XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
477     Bool delete = True;
478     unsigned char *packet;
479     int connect_id;
480 
481     if (((XClientMessageEvent *) ev)->message_type
482         == spec->xim_request)
483     {
484         if ((packet = ReadXIMMessage (ims,
485                                       (XClientMessageEvent *) ev,
486                                       &connect_id))
487             == (unsigned char *)  NULL)
488         {
489             return False;
490         }
491         /*endif*/
492         _Xi18nMessageHandler (ims, connect_id, packet, &delete);
493         if (delete == True)
494             XFree (packet);
495         /*endif*/
496         return True;
497     }
498     /*endif*/
499     return False;
500 }
501