1 #if UNIX
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <sys/un.h>
5 #include <netinet/in.h>
6 #include <arpa/inet.h>
7 #endif
8 
9 #include <string.h>
10 #include "gcin.h"
11 #include "gcin-protocol.h"
12 #include "gcin-im-client.h"
13 #include "im-srv.h"
14 #include <gtk/gtk.h>
15 #include "util.h"
16 
17 #define DBG 0
18 
19 #if UNIX
myread(int fd,void * buf,int bufN)20 static int myread(int fd, void *buf, int bufN)
21 #else
22 #if SHARED_MEMORY
23 static int myread(GCIN_SHM fd, void *buf, int bufN)
24 #else
25 static int myread(HANDLE fd, void *buf, int bufN)
26 #endif
27 #endif
28 {
29   int ofs=0, toN = bufN;
30 
31 #if UNIX
32   while (toN) {
33     fd_set rfds;
34     struct timeval tv;
35     int retval;
36 
37     FD_ZERO(&rfds);
38     FD_SET(fd, &rfds);
39 
40     tv.tv_sec = 5;
41     tv.tv_usec = 0;
42 
43     retval = select(fd+1, &rfds, NULL, NULL, &tv);
44 
45     if (retval <= 0) {
46       dbg("select error\n");
47       return -1;
48     }
49 
50     int rn;
51     if ((rn=read(fd, ((char *)buf) + ofs, toN)) < 0) {
52       dbg("read error");
53       return -1;
54     }
55 
56     if (rn==0)
57       break;
58 
59     ofs+=rn;
60     toN-=rn;
61   };
62   return ofs;
63 #else
64 #if SHARED_MEMORY
65   return gcin_shm_read(fd, buf, bufN);
66 #else
67   while (toN) {
68     DWORD bytes = 0;
69      for(int loop=0;loop < 10000; loop++) {
70        bytes = 0;
71        if (PeekNamedPipe(fd, NULL, 0, NULL, &bytes, NULL)) {
72 //         dbg("bytes %d\n", bytes);
73        } else
74          dbg("PeekNamedPipe failed %s", sys_err_strA());
75 
76        if (bytes > 0)
77          break;
78 
79        Sleep(10);
80      }
81 
82      if (!bytes)
83        return -1;
84 
85 	dbg("bytes:%d %d\n", bytes, toN);
86 
87 	if (bytes > toN)
88 		bytes = toN;
89 
90     DWORD rn;
91     BOOL r = ReadFile(fd, ((char *)buf) + ofs, bytes, &rn, 0);
92     if (!r)
93       return -1;
94     ofs+=rn;
95     toN-=rn;
96   };
97   return bufN;
98 #endif
99 #endif
100 }
101 
102 
103 GCIN_ENT *gcin_clients;
104 int gcin_clientsN;
105 
106 #if WIN32
107 // need to use Enter/Leave CriticalSection in the future
find_im_client(HANDLE hand)108 int find_im_client(HANDLE hand)
109 {
110 	int i;
111 	for(i=0;i<gcin_clientsN;i++)
112 		if (gcin_clients[i].fd == hand)
113 			break;
114 	if (i==gcin_clientsN)
115 		return -1;
116 	return i;
117 }
118 
119 #if SHARED_MEMORY
add_im_client(GCIN_SHM hand,int i,DWORD pid)120 void add_im_client(GCIN_SHM hand, int i, DWORD pid)
121 {
122 	if (i==gcin_clientsN) {
123 		gcin_clientsN++;
124 		gcin_clients=trealloc(gcin_clients, GCIN_ENT, gcin_clientsN);
125 	}
126 
127 	ZeroMemory(&gcin_clients[i], sizeof(GCIN_ENT));
128 	gcin_clients[i].fd = hand;
129 	gcin_clients[i].pid = pid;
130 }
131 #else
add_im_client(HANDLE hand)132 int add_im_client(HANDLE hand)
133 {
134 	int i = find_im_client(0);
135 	if (i<0) {
136 		gcin_clients=trealloc(gcin_clients, GCIN_ENT, gcin_clientsN);
137 		i=gcin_clientsN++;
138 	}
139 
140 	ZeroMemory(&gcin_clients[i], sizeof(GCIN_ENT));
141 	gcin_clients[i].fd = hand;
142 	return i;
143 }
144 #endif
145 #endif
146 
147 extern GCIN_PASSWD my_passwd;
148 
149 gboolean ProcessKeyPress(KeySym keysym, u_int kev_state);
150 gboolean ProcessTestKeyPress(KeySym keysym, u_int kev_state);
151 gboolean ProcessKeyRelease(KeySym keysym, u_int kev_state);
152 gboolean ProcessTestKeyRelease(KeySym keysym, u_int kev_state);
153 int gcin_FocusIn(ClientState *cs);
154 int gcin_FocusOut(ClientState *cs);
155 void update_in_win_pos();
156 void hide_in_win(ClientState *cs);
157 void init_state_chinese(ClientState *cs, gboolean tsin_pho_mode);
158 void clear_output_buffer();
159 void flush_edit_buffer();
160 int gcin_get_preedit(ClientState *cs, char *str, GCIN_PREEDIT_ATTR attr[], int *cursor, int *sub_comp_len);
161 void gcin_reset();
162 void dbg_time(char *fmt,...);
163 
164 extern char *output_buffer;
165 extern int output_bufferN;
166 
167 #if UNIX
write_enc(int fd,void * p,int n)168 int write_enc(int fd, void *p, int n)
169 #else
170 #if SHARED_MEMORY
171 int write_enc(GCIN_SHM fd, void *p, int n)
172 #else
173 int write_enc(HANDLE fd, void *p, int n)
174 #endif
175 #endif
176 {
177 #if WIN32
178 #if SHARED_MEMORY
179   return gcin_shm_write(fd, p, n);
180 #else
181   int loop=0;
182   int twN=0;
183   while (n > 0 && loop < 50) {
184     DWORD wn;
185      BOOL r = WriteFile(fd, (char *)p, n, &wn, 0);
186      if (!r) {
187        dbg("write_enc %s\n", sys_err_strA());
188 	   return -1;
189      }
190 
191 	 twN+=wn;
192 	 n-=wn;
193 	 loop++;
194 	 p=(char *)p+wn;
195   }
196 
197   return twN;
198 #endif
199 #else
200   if (!fd)
201     return 0;
202 
203   unsigned char *tmp = (unsigned char *)malloc(n);
204   memcpy(tmp, p, n);
205   if (gcin_clients[fd].type == Connection_type_tcp) {
206     __gcin_enc_mem(tmp, n, &srv_ip_port.passwd, &gcin_clients[fd].seed);
207   }
208 
209   int r = 0;
210   for(int i=0;i<10;i++) {
211 	  r =  write(fd, tmp, n);
212 	  if (r>=0)
213 		  break;
214 	  else
215 		  usleep(100000);
216   }
217 
218   free(tmp);
219 
220   return r;
221 #endif
222 }
223 
224 #ifdef __cplusplus
225 extern "C" void gdk_input_remove	  (gint		     tag);
226 #endif
227 
228 #if WIN32
229 typedef int socklen_t;
230 #else
231 #include <pwd.h>
232 #endif
233 
234 #if UNIX
shutdown_client(int fd)235 static void shutdown_client(int fd)
236 #else
237 #if SHARED_MEMORY
238 void shutdown_client(GCIN_SHM fd)
239 #else
240 static void shutdown_client(HANDLE fd)
241 #endif
242 #endif
243 {
244   dbg("client shutdown fd %d\n", fd);
245 #if UNIX
246   g_source_remove(gcin_clients[fd].tag);
247   int idx = fd;
248 #else
249   int idx = find_im_client(fd);
250 #endif
251 
252   if (gcin_clients[idx].cs == current_CS) {
253     hide_in_win(current_CS);
254     current_CS = NULL;
255   }
256 
257 dbg("llllll\n");
258 
259   free(gcin_clients[idx].cs);
260   gcin_clients[idx].cs = NULL;
261 #if UNIX
262   g_io_channel_unref(gcin_clients[idx].channel);
263   dbg("after g_object_unref\n");
264   gcin_clients[idx].fd = 0;
265 #else
266   gcin_clients[idx].fd = NULL;
267 #endif
268 
269 #if UNIX && 0
270   int uid = getuid();
271   struct passwd *pwd;
272   if (uid>0 && uid<500)
273     exit(0);
274 #endif
275 #if UNIX
276   close(fd);
277 #else
278 #if SHARED_MEMORY
279   gcin_shm_close(fd);
280 #else
281   CloseHandle(fd);
282 #endif
283 //  CloseHandle(handle);
284 #endif
285 }
286 
287 void message_cb(char *message);
288 void save_CS_temp_to_current();
289 void disp_tray_icon();
290 void gcin_set_tsin_pho_mode(ClientState *cs, gboolean pho_mode);
291 #if WIN32
292 extern int dpy_x_ofs, dpy_y_ofs;
293 #endif
294 
295 #if UNIX
process_client_req(int fd)296 void process_client_req(int fd)
297 #else
298 #if SHARED_MEMORY
299 void process_client_req(GCIN_SHM fd)
300 #else
301 void process_client_req(HANDLE fd)
302 #endif
303 #endif
304 {
305   GCIN_req req;
306 #if DBG
307   dbg("svr--> process_client_req %d\n", fd);
308 #endif
309 
310 #if SHARED_MEMORY
311   gcin_start_shm_read(fd);
312 #endif
313   int rn = myread(fd, &req, sizeof(req));
314 
315   if (rn <= 0) {
316     shutdown_client(fd);
317     return;
318   }
319 #if UNIX
320   if (gcin_clients[fd].type == Connection_type_tcp) {
321     __gcin_enc_mem((u_char *)&req, sizeof(req), &srv_ip_port.passwd, &gcin_clients[fd].seed);
322   }
323 #endif
324   to_gcin_endian_4(&req.req_no);
325   to_gcin_endian_4(&req.client_win);
326   to_gcin_endian_4(&req.flag);
327   to_gcin_endian_2(&req.spot_location.x);
328   to_gcin_endian_2(&req.spot_location.y);
329 
330 //  dbg("spot %d %d\n", req.spot_location.x, req.spot_location.y);
331 
332   ClientState *cs = NULL;
333 
334   if (current_CS && req.client_win == current_CS->client_win) {
335     cs = current_CS;
336   } else {
337 #if UNIX
338     int idx = fd;
339     cs = gcin_clients[fd].cs;
340 #else
341     int idx = find_im_client(fd);
342     cs = gcin_clients[idx].cs;
343 #endif
344 
345     int new_cli = 0;
346     if (!cs) {
347       cs = gcin_clients[idx].cs = tzmalloc(ClientState, 1);
348       new_cli = 1;
349     }
350 
351     cs->client_win = req.client_win;
352     cs->b_gcin_protocol = TRUE;
353     cs->input_style = InputStyleOverSpot;
354 
355 #if WIN32
356     cs->use_preedit = TRUE;
357 #endif
358 
359 #if UNIX
360     if (gcin_init_im_enabled && new_cli)
361 #else
362     if (new_cli)
363 #endif
364     {
365       dbg("new_cli default_input_method:%d cs:%x\n", default_input_method, cs);
366 #if UNIX
367       if (!current_CS)
368 #endif
369       {
370         current_CS = cs;
371         save_CS_temp_to_current();
372       }
373 
374       init_state_chinese(cs, ini_tsin_pho_mode);
375       disp_tray_icon();
376     }
377   }
378 
379   if (!cs)
380     p_err("bad cs\n");
381 
382   if (req.req_no != GCIN_req_message) {
383 #if UNIX
384     cs->spot_location.x = req.spot_location.x;
385     cs->spot_location.y = req.spot_location.y;
386 #else
387     cs->spot_location.x = req.spot_location.x - dpy_x_ofs;
388     cs->spot_location.y = req.spot_location.y - dpy_y_ofs;
389 
390 	dbg("req.spot_location.x %d %d\n", req.spot_location.x, dpy_x_ofs);
391 #endif
392   }
393 
394   gboolean status;
395   GCIN_reply reply;
396   bzero(&reply, sizeof(reply));
397 
398   switch (req.req_no) {
399     case GCIN_req_key_press:
400     case GCIN_req_key_release:
401       current_CS = cs;
402       save_CS_temp_to_current();
403 
404 #if DBG && 0
405       {
406         char tt[128];
407 
408         if (req.keyeve.key < 127) {
409           sprintf(tt,"'%c'", req.keyeve.key);
410         } else {
411           strcpy(tt, XKeysymToString(req.keyeve.key));
412         }
413 
414         dbg_time("GCIN_key_press  %x %s\n", cs, tt);
415       }
416 #endif
417       to_gcin_endian_4(&req.keyeve.key);
418       to_gcin_endian_4(&req.keyeve.state);
419 
420 //	  dbg("serv key eve %x %x predit:%d\n",req.keyeve.key, req.keyeve.state, cs->use_preedit);
421 
422 #if DBG
423 	  char *typ;
424       typ="press";
425 #endif
426 #if 0
427       if (req.req_no==GCIN_req_key_press)
428         status = Process2KeyPress(req.keyeve.key, req.keyeve.state);
429       else {
430         status = Process2KeyRelease(req.keyeve.key, req.keyeve.state);
431 #else
432       if (req.req_no==GCIN_req_key_press)
433         status = ProcessKeyPress(req.keyeve.key, req.keyeve.state);
434       else {
435         status = ProcessKeyRelease(req.keyeve.key, req.keyeve.state);
436 #endif
437 
438 #if DBG
439         typ="rele";
440 #endif
441       }
442 
443       if (status)
444         reply.flag |= GCIN_reply_key_processed;
445 #if DBG
446       dbg("%s srv flag:%x status:%d len:%d %x %c\n",typ, reply.flag, status, output_bufferN, req.keyeve.key,req.keyeve.key & 0x7f);
447 #endif
448       int datalen;
449       datalen = reply.datalen =
450         output_bufferN ? output_bufferN + 1 : 0; // include '\0'
451       to_gcin_endian_4(&reply.flag);
452       to_gcin_endian_4(&reply.datalen);
453 
454 #if SHARED_MEMORY
455 	  gcin_start_shm_write(fd);
456 #endif
457       write_enc(fd, &reply, sizeof(reply));
458 
459 //      dbg("server reply.flag %x\n", reply.flag);
460 
461       if (output_bufferN) {
462         write_enc(fd, output_buffer, datalen);
463         clear_output_buffer();
464       }
465 
466       break;
467 #if WIN32
468     case GCIN_req_test_key_press:
469     case GCIN_req_test_key_release:
470       current_CS = cs;
471       save_CS_temp_to_current();
472       to_gcin_endian_4(&req.keyeve.key);
473       to_gcin_endian_4(&req.keyeve.state);
474 
475 #if   DBG
476 	  dbg("%s %x %x predit:%d\n", req.req_no == GCIN_req_test_key_press?"key_press":"key_release",
477 	  req.keyeve.key, req.keyeve.state, cs->use_preedit);
478 #endif
479 
480       if (req.req_no==GCIN_req_test_key_press)
481         status = ProcessTestKeyPress(req.keyeve.key, req.keyeve.state);
482       else
483         status = ProcessTestKeyRelease(req.keyeve.key, req.keyeve.state);
484 
485       if (status)
486         reply.flag |= GCIN_reply_key_processed;
487 
488       reply.datalen = 0;
489       to_gcin_endian_4(&reply.flag);
490       to_gcin_endian_4(&reply.datalen);
491 
492 #if SHARED_MEMORY
493 	  gcin_start_shm_write(fd);
494 #endif
495       write_enc(fd, &reply, sizeof(reply));
496       break;
497 #endif
498     case GCIN_req_focus_in:
499 #if DBG
500       dbg_time("GCIN_req_focus_in  %x %d %d\n",cs, cs->spot_location.x, cs->spot_location.y);
501 #endif
502 #if 1
503       current_CS = cs;
504 #endif
505       gcin_FocusIn(cs);
506       break;
507     case GCIN_req_focus_out:
508 #if DBG
509       dbg_time("GCIN_req_focus_out  %x\n", cs);
510 #endif
511       gcin_FocusOut(cs);
512       break;
513 #if UNIX
514     case GCIN_req_focus_out2:
515       {
516 #if DBG
517       dbg_time("GCIN_req_focus_out2  %x\n", cs);
518 #endif
519       if (gcin_FocusOut(cs))
520         flush_edit_buffer();
521 
522       GCIN_reply reply;
523       bzero(&reply, sizeof(reply));
524 
525       int datalen = reply.datalen =
526         output_bufferN ? output_bufferN + 1 : 0; // include '\0'
527       to_gcin_endian_4(&reply.flag);
528       to_gcin_endian_4(&reply.datalen);
529       write_enc(fd, &reply, sizeof(reply));
530 
531 //      dbg("server reply.flag %x\n", reply.flag);
532 
533       if (output_bufferN) {
534         write_enc(fd, output_buffer, datalen);
535         clear_output_buffer();
536       }
537       }
538       break;
539 #endif
540     case GCIN_req_set_cursor_location:
541 #if DBG || 0
542       dbg_time("set_cursor_location %p %d %d\n", cs,
543          cs->spot_location.x, cs->spot_location.y);
544 #endif
545       update_in_win_pos();
546       break;
547     case GCIN_req_set_flags:
548 #if DBG
549       dbg("GCIN_req_set_flags\n");
550 #endif
551       if (BITON(req.flag, FLAG_GCIN_client_handle_raise_window)) {
552 #if DBG
553         dbg("********* raise * window\n");
554 #endif
555         if (!gcin_pop_up_win)
556           cs->b_raise_window = TRUE;
557       }
558 
559 	  if (req.flag & FLAG_GCIN_client_handle_use_preedit)
560         cs->use_preedit = TRUE;
561 
562       int rflags;
563       rflags = 0;
564       if (gcin_pop_up_win)
565         rflags = FLAG_GCIN_srv_ret_status_use_pop_up;
566 #if SHARED_MEMORY
567 	  gcin_start_shm_write(fd);
568 #endif
569       write_enc(fd, &rflags, sizeof(rflags));
570       break;
571     case GCIN_req_get_preedit:
572       {
573 #if DBG
574       dbg("svr GCIN_req_get_preedit %x\n", cs);
575 #endif
576       char str[GCIN_PREEDIT_MAX_STR];
577       GCIN_PREEDIT_ATTR attr[GCIN_PREEDIT_ATTR_MAX_N];
578       int cursor, sub_comp_len;
579       int attrN = gcin_get_preedit(cs, str, attr, &cursor, &sub_comp_len);
580       if (gcin_edit_display&(GCIN_EDIT_DISPLAY_BOTH|GCIN_EDIT_DISPLAY_OVER_THE_SPOT))
581         cursor=0;
582       if (gcin_edit_display&GCIN_EDIT_DISPLAY_OVER_THE_SPOT) {
583         attrN=0;
584         str[0]=0;
585       }
586 
587 #if SHARED_MEMORY
588 	  gcin_start_shm_write(fd);
589 #endif
590       int len = strlen(str)+1; // including \0
591       if (write_enc(fd, &len, sizeof(len)) < 0)
592 		  break;
593       if (write_enc(fd, str, len) < 0)
594 		  break;
595 //      dbg("attrN:%d\n", attrN);
596       if (write_enc(fd, &attrN, sizeof(attrN)) < 0)
597 		  break;
598       if (attrN > 0) {
599         if (write_enc(fd, attr, sizeof(GCIN_PREEDIT_ATTR)*attrN) < 0)
600 			break;
601 	  }
602       if (write_enc(fd, &cursor, sizeof(cursor)) < 0)
603 		  break;
604 #if WIN32 || 1
605       if (write_enc(fd, &sub_comp_len, sizeof(sub_comp_len)) < 0)
606 		  break;
607 #endif
608 //      dbg("uuuuuuuuuuuuuuuuu len:%d %d cursor:%d\n", len, attrN, cursor);
609       }
610       break;
611     case GCIN_req_reset:
612 #if DBG
613       dbg("GCIN_req_reset\n");
614 #endif
615       gcin_reset();
616       break;
617     case GCIN_req_message:
618       {
619 //        dbg("GCIN_req_message\n");
620         short len=0;
621         int rn = myread(fd, &len, sizeof(len));
622         if (rn <= 0) {
623 cli_down:
624           shutdown_client(fd);
625           return;
626         }
627 
628         // only unix socket, no decrypt
629         char buf[512];
630         // message should include '\0'
631         if (len > 0 && len < sizeof(buf)) {
632           if (myread(fd, buf, len)<=0)
633             goto cli_down;
634           message_cb(buf);
635         }
636       }
637       break;
638 #if WIN32
639 	case GCIN_req_set_tsin_pho_mode:
640 	  gcin_set_tsin_pho_mode(cs, req.flag);
641 	  break;
642 #endif
643     default:
644       dbg_time("Invalid request %x from:", req.req_no);
645 #if UNIX
646       struct sockaddr_in addr;
647       socklen_t len=sizeof(addr);
648       bzero(&addr, sizeof(addr));
649 
650       if (!getpeername(fd, (struct sockaddr *)&addr, &len)) {
651         dbg("%s\n", inet_ntoa(addr.sin_addr));
652       } else {
653         perror("getpeername\n");
654       }
655 #endif
656       shutdown_client(fd);
657       break;
658   }
659 }
660