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