1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
2 /******************************************************************
3 
4          Copyright (C) 1994-1995 Sun Microsystems, Inc.
5          Copyright (C) 1993-1994 Hewlett-Packard Company
6          Copyright (C) 2014 Peng Huang <shawn.p.huang@gmail.com>
7          Copyright (C) 2014 Red Hat, Inc.
8 
9 Permission to use, copy, modify, distribute, and sell this software
10 and its documentation for any purpose is hereby granted without fee,
11 provided that the above copyright notice appear in all copies and
12 that both that copyright notice and this permission notice appear
13 in supporting documentation, and that the name of Sun Microsystems, Inc.
14 and Hewlett-Packard not be used in advertising or publicity pertaining to
15 distribution of the software without specific, written prior permission.
16 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
17 the suitability of this software for any purpose.  It is provided "as is"
18 without express or implied warranty.
19 
20 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
21 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
24 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
25 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
26 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
27 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 
29   Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
30 
31     This version tidied and debugged by Steve Underwood May 1999
32 
33 ******************************************************************/
34 
35 #include "i18nX.h"
36 #include "FrameMgr.h"
37 #include "Xi18n.h"
38 #include "XimFunc.h"
39 
40 extern Xi18nClient *_Xi18nFindClient (NimfXim *, CARD16);
41 extern Xi18nClient *_Xi18nNewClient (NimfXim *);
42 extern void _Xi18nDeleteClient (NimfXim *, CARD16);
43 extern unsigned long _Xi18nLookupPropertyOffset (Xi18nOffsetCache *, Atom);
44 extern void _Xi18nSetPropertyOffset (Xi18nOffsetCache *, Atom, unsigned long);
45 
46 #define XCM_DATA_LIMIT		20
47 
48 typedef struct _XClient
49 {
50     Window	client_win;	/* client window */
51     Window	accept_win;	/* accept window */
52 } XClient;
53 
NewXClient(NimfXim * xim,Window new_client)54 static XClient *NewXClient (NimfXim *xim, Window new_client)
55 {
56     Xi18nClient *client = _Xi18nNewClient (xim);
57     XClient *x_client;
58 
59     x_client = (XClient *) malloc (sizeof (XClient));
60     x_client->client_win = new_client;
61     x_client->accept_win = XCreateSimpleWindow (xim->display,
62                                                 DefaultRootWindow (xim->display),
63                                                 0, 0, 1, 1, 0, 0, 0);
64     client->trans_rec = x_client;
65     return ((XClient *) x_client);
66 }
67 
ReadXIMMessage(NimfXim * xim,XClientMessageEvent * ev,int * connect_id)68 static unsigned char *ReadXIMMessage (NimfXim *xim,
69                                       XClientMessageEvent *ev,
70                                       int *connect_id)
71 {
72     Xi18nClient *client = xim->address.clients;
73     XClient *x_client = NULL;
74     FrameMgr fm;
75     extern XimFrameRec packet_header_fr[];
76     unsigned char *p = NULL;
77     unsigned char *p1;
78 
79     while (client != NULL) {
80         x_client = (XClient *) client->trans_rec;
81         if (x_client->accept_win == ev->window) {
82             *connect_id = client->connect_id;
83             break;
84         }
85         client = client->next;
86     }
87 
88     if (ev->format == 8) {
89         /* ClientMessage only */
90         XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
91         unsigned char *rec = (unsigned char *) (hdr + 1);
92         register int total_size;
93         CARD8 major_opcode;
94         CARD8 minor_opcode;
95         CARD16 length;
96         extern int _Xi18nNeedSwap (NimfXim *, CARD16);
97 
98         if (client->byte_order == '?')
99         {
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 (xim, *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         memmove (p1, &major_opcode, sizeof (CARD8));
120         p1 += sizeof (CARD8);
121         memmove (p1, &minor_opcode, sizeof (CARD8));
122         p1 += sizeof (CARD8);
123         memmove (p1, &length, sizeof (CARD16));
124         p1 += sizeof (CARD16);
125         memmove (p1, rec, length * 4);
126     }
127     else if (ev->format == 32) {
128         /* ClientMessage and WindowProperty */
129         unsigned long length = (unsigned long) ev->data.l[0];
130         Atom atom = (Atom) ev->data.l[1];
131         int return_code;
132         Atom actual_type_ret;
133         int actual_format_ret;
134         unsigned long bytes_after_ret;
135         unsigned char *prop;
136         unsigned long nitems;
137         Xi18nOffsetCache *offset_cache = &client->offset_cache;
138         unsigned long offset;
139         unsigned long end;
140         unsigned long long_begin;
141         unsigned long long_end;
142 
143         if (length == 0) {
144             fprintf (stderr, "%s: invalid length 0\n", __func__);
145             return NULL;
146         }
147 
148         offset = _Xi18nLookupPropertyOffset (offset_cache, atom);
149         end = offset + length;
150 
151         /* The property data is retrieved in 32-bit chunks */
152         long_begin = offset / 4;
153         long_end = (end + 3) / 4;
154         return_code = XGetWindowProperty (xim->display,
155                                           x_client->accept_win,
156                                           atom,
157                                           long_begin,
158                                           long_end - long_begin,
159                                           True,
160                                           AnyPropertyType,
161                                           &actual_type_ret,
162                                           &actual_format_ret,
163                                           &nitems,
164                                           &bytes_after_ret,
165                                           &prop);
166         if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
167             if (return_code == Success)
168                 XFree (prop);
169             fprintf (stderr,
170                     "(XIM-IMdkit) ERROR: XGetWindowProperty failed.\n"
171                     "Protocol data is likely to be inconsistent.\n");
172             _Xi18nSetPropertyOffset (offset_cache, atom, 0);
173             return (unsigned char *) NULL;
174         }
175         /* Update the offset to read next time as needed */
176         if (bytes_after_ret > 0)
177             _Xi18nSetPropertyOffset (offset_cache, atom, offset + length);
178         else
179             _Xi18nSetPropertyOffset (offset_cache, atom, 0);
180         /* if hit, it might be an error */
181         if ((p = (unsigned char *) malloc (length)) == NULL)
182             return (unsigned char *) NULL;
183 
184         memcpy (p, prop + (offset % 4), length);
185         XFree (prop);
186     }
187     return (unsigned char *) p;
188 }
189 
ReadXConnectMessage(NimfXim * xim,XClientMessageEvent * ev)190 void ReadXConnectMessage (NimfXim *xim, XClientMessageEvent *ev)
191 {
192     XEvent event;
193     Window new_client = ev->data.l[0];
194     CARD32 major_version = ev->data.l[1];
195     CARD32 minor_version = ev->data.l[2];
196     XClient *x_client = NewXClient (xim, new_client);
197 
198     if (ev->window != xim->im_window)
199         return; /* incorrect connection request */
200 
201     if (major_version != 0  ||  minor_version != 0)
202     {
203         major_version =
204         minor_version = 0;
205         /* Only supporting only-CM & Property-with-CM method */
206     }
207     /*endif*/
208     event.xclient.type = ClientMessage;
209     event.xclient.display = xim->display;
210     event.xclient.window = new_client;
211     event.xclient.message_type = xim->_xconnect;
212     event.xclient.format = 32;
213     event.xclient.data.l[0] = x_client->accept_win;
214     event.xclient.data.l[1] = major_version;
215     event.xclient.data.l[2] = minor_version;
216     event.xclient.data.l[3] = XCM_DATA_LIMIT;
217 
218     XSendEvent (xim->display,
219                 new_client,
220                 False,
221                 NoEventMask,
222                 &event);
223     XFlush (xim->display);
224 }
225 
MakeNewAtom(CARD16 connect_id,char * atomName)226 static char *MakeNewAtom (CARD16 connect_id, char *atomName)
227 {
228     static uint8_t sequence = 0;
229 
230     sprintf (atomName,
231              "_server%d_%d",
232              connect_id,
233              ((sequence > 20)  ?  (sequence = 0)  :  (0x1f & sequence)));
234     sequence++;
235     return atomName;
236 }
237 
Xi18nXSend(NimfXim * xim,CARD16 connect_id,unsigned char * reply,long length)238 Bool Xi18nXSend (NimfXim *xim,
239                  CARD16 connect_id,
240                  unsigned char *reply,
241                  long length)
242 {
243     Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
244     XClient *x_client = (XClient *) client->trans_rec;
245     XEvent event;
246 
247     event.type = ClientMessage;
248     event.xclient.window = x_client->client_win;
249     event.xclient.message_type = xim->_protocol;
250 
251     if (length > XCM_DATA_LIMIT)
252     {
253         Atom atom;
254         char atomName[16];
255         Atom actual_type_ret;
256         int actual_format_ret;
257         int return_code;
258         unsigned long nitems_ret;
259         unsigned long bytes_after_ret;
260         unsigned char *win_data;
261 
262         event.xclient.format = 32;
263         atom = XInternAtom (xim->display,
264                             MakeNewAtom (connect_id, atomName),
265                             False);
266         return_code = XGetWindowProperty (xim->display,
267                                           x_client->client_win,
268                                           atom,
269                                           0L,
270                                           10000L,
271                                           False,
272                                           XA_STRING,
273                                           &actual_type_ret,
274                                           &actual_format_ret,
275                                           &nitems_ret,
276                                           &bytes_after_ret,
277                                           &win_data);
278         if (return_code != Success)
279             return False;
280         /*endif*/
281         if (win_data)
282             XFree ((char *) win_data);
283         /*endif*/
284         XChangeProperty (xim->display,
285                          x_client->client_win,
286                          atom,
287                          XA_STRING,
288                          8,
289                          PropModeAppend,
290                          (unsigned char *) reply,
291                          length);
292         event.xclient.data.l[0] = length;
293         event.xclient.data.l[1] = atom;
294     }
295     else
296     {
297         unsigned char buffer[XCM_DATA_LIMIT];
298         int i;
299 
300         event.xclient.format = 8;
301 
302         /* Clear unused field with NULL */
303         memmove(buffer, reply, length);
304         for (i = length; i < XCM_DATA_LIMIT; i++)
305             buffer[i] = (char) 0;
306         /*endfor*/
307         length = XCM_DATA_LIMIT;
308         memmove (event.xclient.data.b, buffer, length);
309     }
310     XSendEvent (xim->display,
311                 x_client->client_win,
312                 False,
313                 NoEventMask,
314                 &event);
315     XFlush (xim->display);
316     return True;
317 }
318 
CheckCMEvent(Display * display,XEvent * event,XPointer arg)319 static Bool CheckCMEvent (Display *display, XEvent *event, XPointer arg)
320 {
321   NimfXim *xim = NIMF_XIM (arg);
322 
323   if ((event->type == ClientMessage) &&
324     (event->xclient.message_type == xim->_protocol))
325     return  True;
326 
327   return  False;
328 }
329 
Xi18nXWait(NimfXim * xim,CARD16 connect_id,CARD8 major_opcode,CARD8 minor_opcode)330 Bool Xi18nXWait (NimfXim *xim,
331                  CARD16 connect_id,
332                  CARD8 major_opcode,
333                  CARD8 minor_opcode)
334 {
335     XEvent event;
336     Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
337     XClient *x_client = (XClient *) client->trans_rec;
338 
339     for (;;)
340     {
341         unsigned char *packet;
342         XimProtoHdr *hdr;
343         int connect_id_ret = 0;
344 
345         XIfEvent (xim->display,
346                   &event,
347                   CheckCMEvent,
348                   (XPointer) xim);
349         if (event.xclient.window == x_client->accept_win)
350         {
351             if ((packet = ReadXIMMessage (xim,
352                                           (XClientMessageEvent *) & event,
353                                           &connect_id_ret))
354                 == (unsigned char*) NULL)
355             {
356                 return False;
357             }
358             /*endif*/
359             hdr = (XimProtoHdr *)packet;
360 
361             if ((hdr->major_opcode == major_opcode)
362                 &&
363                 (hdr->minor_opcode == minor_opcode))
364             {
365                 XFree (packet);
366                 return True;
367             }
368             else if (hdr->major_opcode == XIM_ERROR)
369             {
370                 XFree (packet);
371                 return False;
372             }
373 
374             XFree (packet);
375         }
376         /*endif*/
377     }
378     /*endfor*/
379 }
380 
Xi18nXDisconnect(NimfXim * xim,CARD16 connect_id)381 Bool Xi18nXDisconnect (NimfXim *xim, CARD16 connect_id)
382 {
383     Xi18nClient *client = _Xi18nFindClient (xim, connect_id);
384     XClient *x_client = (XClient *) client->trans_rec;
385 
386     XDestroyWindow (xim->display, x_client->accept_win);
387     XFree (x_client);
388     _Xi18nDeleteClient (xim, connect_id);
389     return True;
390 }
391 
WaitXIMProtocol(NimfXim * xim,XEvent * ev)392 Bool WaitXIMProtocol (NimfXim *xim,
393                       XEvent  *ev)
394 {
395     extern void _Xi18nMessageHandler (NimfXim *, CARD16, unsigned char *, Bool *);
396     Bool delete = True;
397     unsigned char *packet;
398     int connect_id = 0;
399 
400     if (((XClientMessageEvent *) ev)->message_type
401         == xim->_protocol)
402     {
403         if ((packet = ReadXIMMessage (xim,
404                                       (XClientMessageEvent *) ev,
405                                       &connect_id))
406             == (unsigned char *)  NULL)
407         {
408             return False;
409         }
410         /*endif*/
411         _Xi18nMessageHandler (xim, connect_id, packet, &delete);
412         if (delete == True)
413             XFree (packet);
414         /*endif*/
415         return True;
416     }
417     /*endif*/
418     return False;
419 }
420