1 /*
2 * Copyright (C) 2020 The HIME team, Taiwan
3 * Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation version 2.1
8 * of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <string.h>
21
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 #include <pwd.h>
25 #include <unistd.h>
26
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30
31 #include "hime.h"
32
33 #include "hime-im-client.h"
34 #include "hime-protocol.h"
35 #include "im-srv.h"
36
37 #define DBG 0
38
39 HIME_ENT *hime_clients;
40 int hime_clientsN;
41
42 static gboolean is_init_im_enabled = FALSE;
43
44 // from eve.c
45 extern char *output_buffer;
46 extern uint32_t output_bufferN;
47
read_enc(const int fd,void * p,const size_t n)48 static ssize_t read_enc (const int fd, void *p, const size_t n) {
49 if (!fd) {
50 return 0;
51 }
52
53 if (!p || n == 0) {
54 return 0;
55 }
56
57 const ssize_t r = read (fd, p, n);
58 if (r <= 0) {
59 return r;
60 }
61
62 if (hime_clients[fd].type == Connection_type_tcp) {
63 __hime_enc_mem ((unsigned char *) p,
64 n,
65 &srv_ip_port.passwd,
66 &hime_clients[fd].seed);
67 }
68
69 return r;
70 }
71
write_enc(const int fd,const void * p,const size_t n)72 static ssize_t write_enc (const int fd, const void *p, const size_t n) {
73 if (!fd) {
74 return 0;
75 }
76
77 if (!p || n == 0) {
78 return 0;
79 }
80
81 unsigned char *tmp = malloc (n);
82 if (!tmp) {
83 perror ("write_enc: malloc failed");
84 return 0;
85 }
86
87 memcpy (tmp, p, n);
88
89 if (hime_clients[fd].type == Connection_type_tcp) {
90 __hime_enc_mem (tmp, n, &srv_ip_port.passwd, &hime_clients[fd].seed);
91 }
92
93 const ssize_t r = write (fd, tmp, n);
94 if (r < 0) {
95 perror ("write_enc: failed to write into fd");
96 }
97
98 free (tmp);
99
100 return r;
101 }
102
shutdown_client(const int fd)103 static void shutdown_client (const int fd) {
104 const int idx = fd;
105
106 g_source_remove (hime_clients[idx].tag);
107
108 if (hime_clients[idx].cs == current_CS) {
109 hide_in_win (current_CS);
110 current_CS = NULL;
111 }
112
113 free (hime_clients[idx].cs);
114 hime_clients[idx].cs = NULL;
115 hime_clients[idx].fd = 0;
116
117 close (fd);
118 }
119
parse_client_req(HIME_req * req)120 static void parse_client_req (HIME_req *req) {
121 to_hime_endian_4 (&req->req_no);
122 to_hime_endian_4 (&req->client_win);
123 to_hime_endian_4 (&req->flag);
124 to_hime_endian_2 (&req->spot_location.x);
125 to_hime_endian_2 (&req->spot_location.y);
126 }
127
write_reply(HIME_reply * reply,const int fd)128 static void write_reply (HIME_reply *reply, const int fd) {
129
130 const uint32_t datalen = reply->datalen =
131 output_bufferN ? output_bufferN + 1 : 0; // include '\0'
132
133 to_hime_endian_4 (&reply->flag);
134 to_hime_endian_4 (&reply->datalen);
135
136 write_enc (fd, reply, sizeof (*reply));
137
138 if (output_bufferN) {
139 write_enc (fd, output_buffer, datalen);
140 clear_output_buffer ();
141 }
142 }
143
do_process_key(HIME_req * req,HIME_reply * reply,const int fd,ClientState * cs)144 static void do_process_key (HIME_req *req,
145 HIME_reply *reply,
146 const int fd,
147 ClientState *cs) {
148
149 current_CS = cs;
150 save_CS_temp_to_current ();
151
152 to_hime_endian_4 (&req->key_event.key);
153 to_hime_endian_4 (&req->key_event.state);
154
155 char *typed = NULL;
156 gboolean status = FALSE;
157
158 if (req->req_no == HIME_req_key_press) {
159 status = ProcessKeyPress (req->key_event.key, req->key_event.state);
160 typed = "press";
161 } else {
162 status = ProcessKeyRelease (req->key_event.key, req->key_event.state);
163 typed = "release";
164 }
165
166 if (status) {
167 reply->flag |= HIME_reply_key_processed;
168 }
169
170 dbg ("%s srv flag:%x status:%d len:%d %x %c\n",
171 typed,
172 reply->flag,
173 status,
174 output_bufferN,
175 req->key_event.key,
176 req->key_event.key & 0x7f);
177
178 write_reply (reply, fd);
179 }
180
do_set_flags(HIME_req * req,const int fd,ClientState * cs)181 static void do_set_flags (HIME_req *req,
182 const int fd,
183 ClientState *cs) {
184
185 if (BITON (req->flag, FLAG_HIME_client_handle_raise_window)) {
186 dbg ("********* raise * window\n");
187 if (!hime_pop_up_win) {
188 cs->b_raise_window = TRUE;
189 }
190 }
191
192 if (req->flag & FLAG_HIME_client_handle_use_preedit) {
193 cs->use_preedit = TRUE;
194 }
195
196 int rflags = 0;
197 if (hime_pop_up_win) {
198 rflags = FLAG_HIME_srv_ret_status_use_pop_up;
199 }
200
201 write_enc (fd, &rflags, sizeof (rflags));
202 }
203
do_get_preedit(const int fd,ClientState * cs)204 static void do_get_preedit (const int fd, ClientState *cs) {
205
206 dbg ("svr HIME_req_get_preedit %x\n", cs);
207
208 char str[HIME_PREEDIT_MAX_STR];
209 HIME_PREEDIT_ATTR attr[HIME_PREEDIT_ATTR_MAX_N];
210 int cursor = 0;
211 int sub_comp_len = 0;
212
213 int attrN = hime_get_preedit (cs, str, attr, &cursor, &sub_comp_len);
214
215 if (hime_edit_display & (HIME_EDIT_DISPLAY_BOTH | HIME_EDIT_DISPLAY_OVER_THE_SPOT)) {
216 cursor = 0;
217 }
218
219 if (hime_edit_display & HIME_EDIT_DISPLAY_OVER_THE_SPOT) {
220 attrN = 0;
221 str[0] = '\0';
222 }
223
224 // XXX(xatier): should use size_t
225 const int len = strlen (str) + 1; // including \0
226
227 write_enc (fd, &len, sizeof (len));
228 write_enc (fd, str, len);
229 write_enc (fd, &attrN, sizeof (attrN));
230
231 if (attrN > 0) {
232 write_enc (fd, attr, sizeof (HIME_PREEDIT_ATTR) * attrN);
233 }
234
235 write_enc (fd, &cursor, sizeof (cursor));
236 write_enc (fd, &sub_comp_len, sizeof (sub_comp_len));
237 }
238
do_req_message(const int fd)239 static void do_req_message (const int fd) {
240
241 // XXX(xatier): should use size_t
242 short len = 0;
243 if (read (fd, &len, sizeof (len)) <= 0) {
244 shutdown_client (fd);
245 return;
246 }
247
248 // only unix socket, no decrypt
249 // message should include '\0'
250 char buf[512];
251 if (len > 0 && len < sizeof (buf)) {
252 if (read (fd, buf, len) <= 0) {
253 shutdown_client (fd);
254 return;
255 }
256 message_cb (buf);
257 }
258 }
259
do_invalid_req(const int fd)260 static void do_invalid_req (const int fd) {
261 struct sockaddr_in addr;
262 memset (&addr, 0, sizeof (addr));
263
264 socklen_t len = sizeof (addr);
265 if (!getpeername (fd, (struct sockaddr *) &addr, &len)) {
266 dbg ("%s\n", inet_ntoa (addr.sin_addr));
267 } else {
268 perror ("getpeername\n");
269 }
270
271 shutdown_client (fd);
272 }
273
process_client_req(const int fd)274 void process_client_req (const int fd) {
275
276 dbg ("svr--> process_client_req %d\n", fd);
277
278 HIME_req req;
279 const ssize_t r = read_enc (fd, &req, sizeof (req));
280 if (r <= 0) {
281 shutdown_client (fd);
282 return;
283 }
284
285 parse_client_req (&req);
286
287 ClientState *cs = NULL;
288 if (current_CS && (req.client_win == current_CS->client_win)) {
289 cs = current_CS;
290 } else {
291 cs = hime_clients[fd].cs;
292
293 int new_cli = 0;
294 if (!cs) {
295 cs = hime_clients[fd].cs = tzmalloc (ClientState, 1);
296 new_cli = 1;
297 }
298
299 cs->client_win = req.client_win;
300 cs->b_hime_protocol = TRUE;
301 cs->input_style = InputStyleOverSpot;
302
303 if (hime_init_im_enabled) {
304 if (
305 (hime_single_state && !is_init_im_enabled) ||
306 (!hime_single_state && new_cli)) {
307
308 dbg ("new_cli default_input_method:%d\n", default_input_method);
309
310 is_init_im_enabled = TRUE;
311 current_CS = cs;
312 save_CS_temp_to_current ();
313 init_state_chinese (cs);
314 }
315 }
316 }
317
318 if (!cs) {
319 p_err ("bad cs\n");
320 }
321
322 if (req.req_no != HIME_req_message) {
323 cs->spot_location.x = req.spot_location.x;
324 cs->spot_location.y = req.spot_location.y;
325 }
326
327 HIME_reply reply;
328 memset (&reply, 0, sizeof (reply));
329
330 switch (req.req_no) {
331 case HIME_req_key_press:
332 case HIME_req_key_release:
333 do_process_key (&req, &reply, fd, cs);
334 break;
335
336 case HIME_req_focus_in:
337 dbg_time ("HIME_req_focus_in %x %d %d\n", cs, cs->spot_location.x, cs->spot_location.y);
338 hime_FocusIn (cs);
339 break;
340
341 case HIME_req_focus_out:
342 dbg_time ("HIME_req_focus_out %x\n", cs);
343 hime_FocusOut (cs);
344 break;
345
346 case HIME_req_focus_out2:
347 dbg_time ("HIME_req_focus_out2 %x\n", cs);
348 if (hime_FocusOut (cs)) {
349 flush_edit_buffer ();
350 }
351
352 write_reply (&reply, fd);
353 break;
354
355 case HIME_req_set_cursor_location:
356 dbg_time ("set_cursor_location %x %d %d\n", cs,
357 cs->spot_location.x, cs->spot_location.y);
358 update_in_win_pos ();
359 break;
360
361 case HIME_req_set_flags:
362 do_set_flags (&req, fd, cs);
363 break;
364
365 case HIME_req_get_preedit:
366 do_get_preedit (fd, cs);
367 break;
368
369 case HIME_req_reset:
370 hime_reset ();
371 break;
372
373 case HIME_req_message:
374 do_req_message (fd);
375 break;
376
377 default:
378 dbg_time ("Invalid request %x from:", req.req_no);
379 do_invalid_req (fd);
380 break;
381 }
382 }
383