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