/[LeafOK_CVS]/lbbs/src/io.c
ViewVC logotype

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.61 - (hide annotations)
Tue Nov 4 05:24:09 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.60: +71 -57 lines
Content type: text/x-csrc
Fix bug: remaining input data in SSH read buffer could not be detected by epoll_wait on STDIN
Add stdin_read_wait to indicate the last read state in igetch()
When stdin_read_wait = 1, ssh_channel_read_nonblocking / read will be performed directly without check with epoll_wait

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.14 io.c - description
3     -------------------
4 sysadm 1.20 Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12 sysadm 1.20 * the Free Software Foundation; either version 3 of the License, or *
13 sysadm 1.1 * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17 sysadm 1.47 #include "common.h"
18 sysadm 1.1 #include "io.h"
19 sysadm 1.16 #include "log.h"
20 sysadm 1.22 #include <errno.h>
21 sysadm 1.47 #include <fcntl.h>
22     #include <stdarg.h>
23 sysadm 1.1 #include <stdio.h>
24 sysadm 1.28 #include <string.h>
25 sysadm 1.9 #include <time.h>
26     #include <unistd.h>
27 sysadm 1.47 #include <sys/epoll.h>
28     #include <sys/ioctl.h>
29 sysadm 1.22 #include <sys/select.h>
30 sysadm 1.47 #include <libssh/callbacks.h>
31 sysadm 1.39 #include <libssh/libssh.h>
32     #include <libssh/server.h>
33 sysadm 1.1
34 sysadm 1.58 char stdio_charset[20] = BBS_DEFAULT_CHARSET;
35 sysadm 1.55
36     // static input / output buffer
37     static char stdin_buf[LINE_BUFFER_LEN];
38 sysadm 1.57 static char stdout_buf[BUFSIZ];
39 sysadm 1.55 static int stdin_buf_len = 0;
40 sysadm 1.57 static int stdout_buf_len = 0;
41 sysadm 1.55 static int stdin_buf_offset = 0;
42 sysadm 1.57 static int stdout_buf_offset = 0;
43 sysadm 1.55
44 sysadm 1.57 static char stdin_conv[LINE_BUFFER_LEN * 2];
45     static char stdout_conv[BUFSIZ * 2];
46     static int stdin_conv_len = 0;
47 sysadm 1.55 static int stdout_conv_len = 0;
48 sysadm 1.57 static int stdin_conv_offset = 0;
49 sysadm 1.55 static int stdout_conv_offset = 0;
50    
51     static iconv_t stdin_cd = NULL;
52     static iconv_t stdout_cd = NULL;
53 sysadm 1.1
54 sysadm 1.14 int prints(const char *format, ...)
55 sysadm 1.1 {
56 sysadm 1.28 char buf[BUFSIZ];
57 sysadm 1.14 va_list args;
58 sysadm 1.28 int ret;
59 sysadm 1.1
60 sysadm 1.14 va_start(args, format);
61 sysadm 1.28 ret = vsnprintf(buf, sizeof(buf), format, args);
62 sysadm 1.14 va_end(args);
63 sysadm 1.1
64 sysadm 1.30 if (ret > 0)
65 sysadm 1.28 {
66 sysadm 1.30 if (stdout_buf_len + ret > BUFSIZ)
67     {
68     iflush();
69     }
70 sysadm 1.31
71 sysadm 1.30 if (stdout_buf_len + ret <= BUFSIZ)
72     {
73     memcpy(stdout_buf + stdout_buf_len, buf, (size_t)ret);
74     stdout_buf_len += ret;
75     }
76     else
77     {
78     errno = EAGAIN;
79     ret = (BUFSIZ - stdout_buf_len - ret);
80 sysadm 1.35 log_error("Output buffer is full, additional %d is required\n", ret);
81 sysadm 1.30 }
82 sysadm 1.28 }
83 sysadm 1.30
84     return ret;
85     }
86    
87     int outc(char c)
88     {
89     int ret;
90    
91     if (stdout_buf_len + 1 > BUFSIZ)
92 sysadm 1.28 {
93 sysadm 1.30 iflush();
94     }
95    
96     if (stdout_buf_len + 1 <= BUFSIZ)
97     {
98     stdout_buf[stdout_buf_len] = c;
99     stdout_buf_len++;
100     }
101     else
102     {
103     errno = EAGAIN;
104     ret = -1;
105 sysadm 1.28 }
106    
107     return ret;
108 sysadm 1.1 }
109    
110 sysadm 1.43 int iflush(void)
111 sysadm 1.1 {
112 sysadm 1.28 int flags;
113 sysadm 1.29 struct epoll_event ev, events[MAX_EVENTS];
114     int nfds, epollfd;
115 sysadm 1.30 int retry;
116 sysadm 1.28 int ret = 0;
117    
118 sysadm 1.29 epollfd = epoll_create1(0);
119     if (epollfd < 0)
120     {
121     log_error("epoll_create1() error (%d)\n", errno);
122     return -1;
123     }
124    
125     ev.events = EPOLLOUT;
126     ev.data.fd = STDOUT_FILENO;
127     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
128     {
129     log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
130 sysadm 1.31 if (close(epollfd) < 0)
131     {
132     log_error("close(epoll) error (%d)\n");
133     }
134 sysadm 1.29 return -1;
135     }
136    
137 sysadm 1.28 // Set STDOUT as non-blocking
138     flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
139     fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
140    
141 sysadm 1.30 // Retry wait / flush for at most 3 times
142     retry = 3;
143     while (retry > 0 && !SYS_server_exit)
144 sysadm 1.28 {
145 sysadm 1.30 retry--;
146    
147 sysadm 1.29 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
148 sysadm 1.28
149 sysadm 1.29 if (nfds < 0)
150 sysadm 1.28 {
151 sysadm 1.29 if (errno != EINTR)
152     {
153     log_error("epoll_wait() error (%d)\n", errno);
154     break;
155     }
156 sysadm 1.28 continue;
157     }
158 sysadm 1.29 else if (nfds == 0) // timeout
159 sysadm 1.28 {
160 sysadm 1.29 continue;
161 sysadm 1.28 }
162 sysadm 1.29
163     for (int i = 0; i < nfds; i++)
164 sysadm 1.28 {
165 sysadm 1.29 if (events[i].data.fd == STDOUT_FILENO)
166 sysadm 1.28 {
167 sysadm 1.55 if (stdout_buf_offset < stdout_buf_len)
168     {
169     ret = io_buf_conv(stdout_cd, stdout_buf, &stdout_buf_len, &stdout_buf_offset, stdout_conv, sizeof(stdout_conv), &stdout_conv_len);
170     if (ret < 0)
171     {
172     log_error("io_buf_conv(stdout, %d, %d, %d) error\n", stdout_buf_len, stdout_buf_offset, stdout_conv_len);
173 sysadm 1.60 stdout_buf_len = stdout_buf_offset; // Discard invalid sequence
174 sysadm 1.55 }
175     }
176    
177     while (stdout_conv_offset < stdout_conv_len && !SYS_server_exit) // write until complete or error
178 sysadm 1.28 {
179 sysadm 1.39 if (SSH_v2)
180     {
181 sysadm 1.55 ret = ssh_channel_write(SSH_channel, stdout_conv + stdout_conv_offset, (uint32_t)(stdout_conv_len - stdout_conv_offset));
182 sysadm 1.39 if (ret == SSH_ERROR)
183     {
184     log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));
185     retry = 0;
186     break;
187     }
188     }
189     else
190     {
191 sysadm 1.55 ret = (int)write(STDOUT_FILENO, stdout_conv + stdout_conv_offset, (size_t)(stdout_conv_len - stdout_conv_offset));
192 sysadm 1.39 }
193 sysadm 1.29 if (ret < 0)
194     {
195     if (errno == EAGAIN || errno == EWOULDBLOCK)
196     {
197     break;
198     }
199     else if (errno == EINTR)
200     {
201     continue;
202     }
203     else
204     {
205 sysadm 1.46 #ifdef _DEBUG
206 sysadm 1.29 log_error("write(STDOUT) error (%d)\n", errno);
207 sysadm 1.46 #endif
208 sysadm 1.30 retry = 0;
209 sysadm 1.29 break;
210     }
211     }
212     else if (ret == 0) // broken pipe
213     {
214 sysadm 1.30 retry = 0;
215 sysadm 1.29 break;
216     }
217     else
218     {
219 sysadm 1.55 stdout_conv_offset += ret;
220     if (stdout_conv_offset >= stdout_conv_len) // flush buffer completely
221 sysadm 1.29 {
222     ret = 0;
223 sysadm 1.55 stdout_conv_offset = 0;
224     stdout_conv_len = 0;
225 sysadm 1.30 retry = 0;
226 sysadm 1.29 break;
227     }
228     continue;
229     }
230 sysadm 1.28 }
231     }
232     }
233     }
234 sysadm 1.6
235 sysadm 1.28 // Restore STDOUT flags
236     fcntl(STDOUT_FILENO, F_SETFL, flags);
237 sysadm 1.6
238 sysadm 1.31 if (close(epollfd) < 0)
239     {
240     log_error("close(epoll) error (%d)\n");
241     }
242    
243 sysadm 1.28 return ret;
244 sysadm 1.1 }
245    
246 sysadm 1.31 int igetch(int timeout)
247 sysadm 1.1 {
248 sysadm 1.61 static int stdin_read_wait = 0;
249    
250 sysadm 1.29 struct epoll_event ev, events[MAX_EVENTS];
251     int nfds, epollfd;
252 sysadm 1.31 int ret;
253     int loop;
254 sysadm 1.21
255 sysadm 1.22 unsigned char tmp[LINE_BUFFER_LEN];
256 sysadm 1.31 int out = KEY_NULL;
257 sysadm 1.18 int in_esc = 0;
258     int in_ascii = 0;
259     int in_control = 0;
260     int i = 0;
261 sysadm 1.26 int flags;
262 sysadm 1.1
263 sysadm 1.55 if (stdin_conv_offset >= stdin_conv_len)
264 sysadm 1.29 {
265 sysadm 1.55 stdin_conv_len = 0;
266     stdin_conv_offset = 0;
267 sysadm 1.31
268 sysadm 1.48 epollfd = epoll_create1(0);
269     if (epollfd < 0)
270 sysadm 1.31 {
271 sysadm 1.48 log_error("epoll_create1() error (%d)\n", errno);
272     return -1;
273 sysadm 1.31 }
274 sysadm 1.9
275 sysadm 1.48 ev.events = EPOLLIN;
276     ev.data.fd = STDIN_FILENO;
277     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
278     {
279     log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
280 sysadm 1.9
281 sysadm 1.48 if (close(epollfd) < 0)
282     {
283     log_error("close(epoll) error (%d)\n");
284     }
285     return -1;
286     }
287 sysadm 1.31
288 sysadm 1.48 flags = fcntl(STDIN_FILENO, F_GETFL, 0);
289     fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
290 sysadm 1.31
291 sysadm 1.57 for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
292 sysadm 1.39 {
293 sysadm 1.48 if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
294     {
295     log_error("SSH channel is closed\n");
296     loop = 0;
297     break;
298     }
299 sysadm 1.39
300 sysadm 1.61 if (!stdin_read_wait)
301     {
302     nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);
303 sysadm 1.9
304 sysadm 1.61 if (nfds < 0)
305     {
306     if (errno != EINTR)
307     {
308     log_error("epoll_wait() error (%d)\n", errno);
309     break;
310     }
311     continue;
312     }
313     else if (nfds == 0) // timeout
314 sysadm 1.48 {
315 sysadm 1.61 out = KEY_TIMEOUT;
316 sysadm 1.48 break;
317     }
318 sysadm 1.61
319     for (int i = 0; i < nfds; i++)
320     {
321     if (events[i].data.fd == STDIN_FILENO)
322     {
323     stdin_read_wait = 1;
324     }
325     }
326 sysadm 1.21 }
327    
328 sysadm 1.61 if (stdin_read_wait)
329 sysadm 1.26 {
330 sysadm 1.61 while (stdin_buf_len < sizeof(stdin_buf) && !SYS_server_exit) // read until complete or error
331 sysadm 1.26 {
332 sysadm 1.61 if (SSH_v2)
333 sysadm 1.39 {
334 sysadm 1.61 ret = ssh_channel_read_nonblocking(SSH_channel, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (uint32_t)stdin_buf_len, 0);
335     if (ret == SSH_ERROR)
336 sysadm 1.39 {
337 sysadm 1.61 log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));
338     loop = 0;
339     break;
340 sysadm 1.39 }
341 sysadm 1.61 else if (ret == SSH_EOF)
342 sysadm 1.39 {
343 sysadm 1.61 stdin_read_wait = 0;
344     loop = 0;
345     break;
346 sysadm 1.39 }
347 sysadm 1.61 else if (ret == 0)
348 sysadm 1.39 {
349 sysadm 1.61 out = 0;
350     stdin_read_wait = 0;
351     loop = 0;
352     break;
353 sysadm 1.39 }
354 sysadm 1.61 }
355     else
356     {
357     ret = (int)read(STDIN_FILENO, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (size_t)stdin_buf_len);
358     }
359     if (ret < 0)
360     {
361     if (errno == EAGAIN || errno == EWOULDBLOCK)
362 sysadm 1.29 {
363 sysadm 1.61 out = 0;
364     stdin_read_wait = 0;
365 sysadm 1.31 loop = 0;
366     break;
367 sysadm 1.29 }
368 sysadm 1.61 else if (errno == EINTR)
369     {
370     continue;
371     }
372 sysadm 1.48 else
373 sysadm 1.29 {
374 sysadm 1.61 #ifdef _DEBUG
375     log_error("read(STDIN) error (%d)\n", errno);
376     #endif
377     loop = 0;
378     break;
379 sysadm 1.29 }
380     }
381 sysadm 1.61 else if (ret == 0) // broken pipe
382     {
383     stdin_read_wait = 0;
384     loop = 0;
385     break;
386     }
387     else
388     {
389     stdin_buf_len += ret;
390     continue;
391     }
392 sysadm 1.26 }
393     }
394 sysadm 1.48
395     // For debug
396     #ifdef _DEBUG
397 sysadm 1.55 for (int j = stdin_buf_offset; j < stdin_buf_len; j++)
398 sysadm 1.48 {
399 sysadm 1.56 log_error("Debug input: <--[%u]\n", (stdin_buf[j] + 256) % 256);
400 sysadm 1.48 }
401     #endif
402 sysadm 1.14 }
403    
404 sysadm 1.48 fcntl(STDIN_FILENO, F_SETFL, flags);
405    
406     if (close(epollfd) < 0)
407 sysadm 1.45 {
408 sysadm 1.48 log_error("close(epoll) error (%d)\n");
409 sysadm 1.45 }
410 sysadm 1.55
411     if (stdin_buf_offset < stdin_buf_len)
412     {
413     ret = io_buf_conv(stdin_cd, stdin_buf, &stdin_buf_len, &stdin_buf_offset, stdin_conv, sizeof(stdin_conv), &stdin_conv_len);
414     if (ret < 0)
415     {
416     log_error("io_buf_conv(stdin, %d, %d, %d) error\n", stdin_buf_len, stdin_buf_offset, stdin_conv_len);
417 sysadm 1.60 stdin_buf_len = stdin_buf_offset; // Discard invalid sequence
418 sysadm 1.55 }
419 sysadm 1.56
420     // For debug
421     #ifdef _DEBUG
422     for (int j = stdin_conv_offset; j < stdin_conv_len; j++)
423     {
424     log_error("Debug input_conv: <--[%u]\n", (stdin_conv[j] + 256) % 256);
425     }
426     #endif
427 sysadm 1.55 }
428 sysadm 1.11 }
429 sysadm 1.14
430 sysadm 1.55 while (stdin_conv_offset < stdin_conv_len)
431 sysadm 1.11 {
432 sysadm 1.55 unsigned char c = (unsigned char)stdin_conv[stdin_conv_offset++];
433 sysadm 1.5
434 sysadm 1.51 // Convert \r\n to \r
435 sysadm 1.55 if (c == CR && stdin_conv_offset < stdin_conv_len && stdin_conv[stdin_conv_offset] == LF)
436 sysadm 1.51 {
437 sysadm 1.55 stdin_conv_offset++;
438 sysadm 1.51 }
439    
440     // Convert single \n to \r
441     if (c == LF)
442     {
443     c = CR;
444     }
445    
446 sysadm 1.14 if (c == KEY_CONTROL)
447     {
448     if (in_control == 0)
449     {
450     in_control = 1;
451     i = 0;
452     continue;
453     }
454     }
455 sysadm 1.1
456 sysadm 1.14 if (in_control)
457     {
458     tmp[i++] = c;
459     if (i >= 2)
460     {
461     out = (int)tmp[0] * 256 + tmp[1];
462     in_control = 0;
463     break;
464     }
465     continue;
466     }
467 sysadm 1.6
468 sysadm 1.37 if (c == KEY_ESC)
469 sysadm 1.14 {
470     if (in_esc == 0)
471     {
472     in_esc = 1;
473     in_ascii = 1;
474     i = 0;
475     continue;
476     }
477     else
478     {
479 sysadm 1.37 out = KEY_CSI;
480 sysadm 1.14 in_esc = 0;
481     break;
482     }
483     }
484 sysadm 1.3
485 sysadm 1.14 in_esc = 0;
486 sysadm 1.1
487 sysadm 1.14 if (in_ascii)
488     {
489     tmp[i++] = c;
490 sysadm 1.33 if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
491 sysadm 1.14 {
492     in_ascii = 0;
493 sysadm 1.33 switch (tmp[1])
494 sysadm 1.14 {
495 sysadm 1.33 case 65:
496 sysadm 1.14 out = KEY_UP;
497     break;
498 sysadm 1.33 case 66:
499 sysadm 1.14 out = KEY_DOWN;
500     break;
501 sysadm 1.33 case 67:
502 sysadm 1.14 out = KEY_RIGHT;
503     break;
504 sysadm 1.33 case 68:
505 sysadm 1.14 out = KEY_LEFT;
506     break;
507 sysadm 1.33 default:
508     in_ascii = 1;
509     }
510     if (!in_ascii)
511     {
512     break;
513     }
514     }
515     if (i == 2 && tmp[0] == 91) // Fterm
516     {
517     in_ascii = 0;
518     switch (tmp[1])
519     {
520     case 86:
521     out = KEY_SHIFT_F1;
522     break;
523     case 90:
524     out = KEY_SHIFT_F2;
525     break;
526     case 97:
527     out = KEY_SHIFT_F3;
528     break;
529     case 98:
530     out = KEY_SHIFT_F4;
531     break;
532     case 99:
533     out = KEY_SHIFT_F5;
534     break;
535     case 100:
536     out = KEY_SHIFT_F6;
537     break;
538     case 101:
539     out = KEY_SHIFT_F7;
540     break;
541     case 102:
542     out = KEY_SHIFT_F8;
543     break;
544     case 103:
545     out = KEY_SHIFT_F9;
546     break;
547     case 104:
548     out = KEY_SHIFT_F10;
549     break;
550     case 107:
551     out = KEY_CTRL_F1;
552     break;
553     case 108:
554     out = KEY_CTRL_F2;
555     break;
556     case 109:
557     out = KEY_CTRL_F3;
558     break;
559     case 112:
560     out = KEY_CTRL_F6;
561     break;
562     case 113:
563     out = KEY_CTRL_F7;
564     break;
565     case 114:
566     out = KEY_CTRL_F8;
567     break;
568     case 115:
569     out = KEY_CTRL_F9;
570     break;
571     case 116:
572     out = KEY_CTRL_F10;
573     break;
574     default:
575     in_ascii = 1;
576     }
577     if (!in_ascii)
578     {
579     break;
580     }
581     }
582     if (i == 2 && tmp[0] == 79) // Xterm
583     {
584     in_ascii = 0;
585     switch (tmp[1])
586     {
587     case 80:
588     out = KEY_F1;
589     break;
590     case 81:
591     out = KEY_F2;
592     break;
593     case 82:
594     out = KEY_F3;
595     break;
596     case 83:
597     out = KEY_F4;
598     break;
599     default:
600     in_ascii = 1;
601     }
602     if (!in_ascii)
603     {
604     break;
605 sysadm 1.14 }
606     }
607     if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
608     {
609     in_ascii = 0;
610     switch (tmp[1])
611     {
612     case 49:
613     out = KEY_HOME;
614     break;
615 sysadm 1.42 case 50:
616     out = KEY_INS;
617     break;
618 sysadm 1.14 case 51:
619     out = KEY_DEL;
620     break;
621     case 52:
622     out = KEY_END;
623     break;
624     case 53:
625     out = KEY_PGUP;
626     break;
627     case 54:
628     out = KEY_PGDN;
629     break;
630 sysadm 1.33 default:
631     in_ascii = 1;
632     }
633     if (!in_ascii)
634     {
635     break;
636     }
637     }
638 sysadm 1.39 if (i == 4 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 126) // Fterm
639 sysadm 1.33 {
640     in_ascii = 0;
641     switch (tmp[2])
642     {
643     case 49:
644     out = KEY_F1;
645     break;
646     case 50:
647     out = KEY_F2;
648     break;
649     case 51:
650     out = KEY_F3;
651     break;
652     case 52:
653     out = KEY_F4;
654     break;
655     case 53:
656     out = KEY_F5;
657     break;
658     case 55:
659     out = KEY_F6;
660     break;
661     case 56:
662     out = KEY_F7;
663     break;
664     case 57:
665     out = KEY_F8;
666     break;
667     default:
668     in_ascii = 1;
669     }
670     if (!in_ascii)
671     {
672     break;
673     }
674     }
675     if (i == 4 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 126) // Fterm
676     {
677     in_ascii = 0;
678     switch (tmp[2])
679     {
680     case 48:
681     out = KEY_F9;
682     break;
683     case 49:
684     out = KEY_F10;
685     break;
686     case 50:
687     out = KEY_F11; // Fterm
688     break;
689     case 51:
690     out = KEY_F11; // Xterm
691     break;
692     case 52:
693     out = KEY_F12; // Xterm
694     break;
695     default:
696     in_ascii = 1;
697     }
698     if (!in_ascii)
699     {
700     break;
701     }
702     }
703     if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 53) // Xterm
704     {
705     in_ascii = 0;
706     switch (tmp[4])
707     {
708 sysadm 1.41 case 65:
709     out = KEY_CTRL_UP;
710     break;
711     case 66:
712     out = KEY_CTRL_DOWN;
713     break;
714     case 67:
715     out = KEY_CTRL_RIGHT;
716     break;
717     case 68:
718     out = KEY_CTRL_LEFT;
719     break;
720     case 70:
721     out = KEY_CTRL_END;
722     break;
723     case 72:
724     out = KEY_CTRL_HOME;
725     break;
726 sysadm 1.33 case 80:
727     out = KEY_CTRL_F1;
728     break;
729     case 81:
730     out = KEY_CTRL_F2;
731     break;
732     case 82:
733     out = KEY_CTRL_F3;
734     break;
735     default:
736     in_ascii = 1;
737     }
738     if (!in_ascii)
739     {
740     break;
741     }
742     }
743     if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
744     {
745     in_ascii = 0;
746     switch (tmp[2])
747     {
748     case 53:
749     out = KEY_CTRL_F5;
750     break;
751     case 55:
752     out = KEY_CTRL_F6;
753     break;
754     case 56:
755     out = KEY_CTRL_F7;
756     break;
757     case 57:
758     out = KEY_CTRL_F8;
759     break;
760     default:
761     in_ascii = 1;
762     }
763     if (!in_ascii)
764     {
765     break;
766     }
767     }
768     if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 53 && tmp[5] == 126) // Xterm
769     {
770     in_ascii = 0;
771     switch (tmp[2])
772     {
773     case 48:
774     out = KEY_CTRL_F9;
775     break;
776     case 49:
777     out = KEY_CTRL_F10;
778     break;
779     case 51:
780     out = KEY_CTRL_F11;
781     break;
782     case 52:
783     out = KEY_CTRL_F12;
784     break;
785     default:
786     in_ascii = 1;
787     }
788     if (!in_ascii)
789     {
790     break;
791     }
792     }
793     if (i == 5 && tmp[0] == 91 && tmp[1] == 49 && tmp[2] == 59 && tmp[3] == 50) // Xterm
794     {
795     in_ascii = 0;
796     switch (tmp[4])
797     {
798     case 80:
799     out = KEY_SHIFT_F1;
800     break;
801     case 81:
802     out = KEY_SHIFT_F2;
803     break;
804     case 82:
805     out = KEY_SHIFT_F3;
806     break;
807     case 83:
808     out = KEY_SHIFT_F4;
809     break;
810     default:
811     in_ascii = 1;
812     }
813     if (!in_ascii)
814     {
815     break;
816 sysadm 1.14 }
817 sysadm 1.33 }
818     if (i == 6 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
819     {
820     in_ascii = 0;
821     switch (tmp[2])
822     {
823     case 53:
824     out = KEY_SHIFT_F5;
825     break;
826     case 55:
827     out = KEY_SHIFT_F6;
828     break;
829     case 56:
830     out = KEY_SHIFT_F7;
831     break;
832     case 57:
833     out = KEY_SHIFT_F8;
834     break;
835     default:
836     in_ascii = 1;
837     }
838     if (!in_ascii)
839     {
840     break;
841     }
842     }
843     if (i == 6 && tmp[0] == 91 && tmp[1] == 50 && tmp[3] == 59 && tmp[4] == 50 && tmp[5] == 126) // Xterm
844     {
845     in_ascii = 0;
846     switch (tmp[2])
847     {
848     case 48:
849     out = KEY_SHIFT_F9;
850     break;
851     case 49:
852     out = KEY_SHIFT_F10;
853     break;
854     case 51:
855     out = KEY_SHIFT_F11;
856     break;
857     case 52:
858     out = KEY_SHIFT_F12;
859     break;
860     default:
861     in_ascii = 1;
862     }
863     if (!in_ascii)
864     {
865     break;
866     }
867     }
868    
869     if (c == 'm')
870     {
871     in_ascii = 0;
872 sysadm 1.14 }
873     continue;
874     }
875 sysadm 1.1
876 sysadm 1.14 out = ((int)c + 256) % 256;
877     break;
878 sysadm 1.1 }
879    
880 sysadm 1.36 // For ESC key
881     if (out == 0 && in_esc)
882     {
883     out = KEY_ESC;
884     }
885    
886 sysadm 1.33 // for debug
887 sysadm 1.45 #ifdef _DEBUG
888     if (out != KEY_TIMEOUT && out != KEY_NULL)
889     {
890 sysadm 1.56 log_error("Debug: -->[0x %x]\n", out);
891 sysadm 1.45 }
892     #endif
893 sysadm 1.33
894 sysadm 1.14 return out;
895 sysadm 1.1 }
896 sysadm 1.5
897 sysadm 1.31 int igetch_t(int sec)
898 sysadm 1.9 {
899 sysadm 1.14 int ch;
900 sysadm 1.44 time_t t_begin = time(NULL);
901 sysadm 1.10
902 sysadm 1.14 do
903     {
904 sysadm 1.31 ch = igetch(100);
905 sysadm 1.44 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec));
906 sysadm 1.9
907 sysadm 1.14 return ch;
908 sysadm 1.9 }
909 sysadm 1.31
910     void igetch_reset()
911     {
912     int ch;
913     do
914     {
915 sysadm 1.53 ch = igetch(100);
916 sysadm 1.31 } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
917     }
918 sysadm 1.54
919     int io_buf_conv(iconv_t cd, char *p_buf, int *p_buf_len, int *p_buf_offset, char *p_conv, size_t conv_size, int *p_conv_len)
920     {
921     char *in_buf;
922     char *out_buf;
923     size_t in_bytes;
924     size_t out_bytes;
925     int ret;
926 sysadm 1.56 int in_control = 0;
927     size_t i = 0;
928 sysadm 1.54
929 sysadm 1.55 if (cd == NULL || p_buf == NULL || p_buf_len == NULL || p_buf_offset == NULL || p_conv == NULL || p_conv_len == NULL)
930     {
931     log_error("NULL pointer error\n");
932     return -1;
933     }
934    
935 sysadm 1.54 in_buf = p_buf + *p_buf_offset;
936     in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
937     out_buf = p_conv + *p_conv_len;
938     out_bytes = conv_size - (size_t)(*p_conv_len);
939    
940     while (in_bytes > 0)
941     {
942 sysadm 1.56 if ((unsigned char)(*in_buf) == KEY_CONTROL)
943     {
944     if (in_control == 0)
945     {
946     in_control = 1;
947     i = 0;
948     }
949     }
950    
951     if (in_control)
952     {
953     if (out_bytes <= 0)
954     {
955 sysadm 1.60 log_error("No enough free space in p_conv, conv_len=%d, conv_size=%d\n", *p_conv_len, conv_size);
956 sysadm 1.56 return -2;
957     }
958    
959     *out_buf = *in_buf;
960     in_buf++;
961     out_buf++;
962     in_bytes--;
963     out_bytes--;
964    
965     (*p_buf_offset)++;
966     *p_conv_len = (int)(conv_size - out_bytes);
967    
968     i++;
969     if (i >= 2)
970     {
971     in_control = 0;
972     }
973     continue;
974     }
975    
976 sysadm 1.54 ret = (int)iconv(cd, &in_buf, &in_bytes, &out_buf, &out_bytes);
977     if (ret == -1)
978     {
979     if (errno == EINVAL) // Incomplete
980     {
981     #ifdef _DEBUG
982 sysadm 1.56 log_error("iconv(inbytes=%d, outbytes=%d) error: EINVAL, in_buf[0]=%d\n", in_bytes, out_bytes, in_buf[0]);
983 sysadm 1.54 #endif
984 sysadm 1.56 if (p_buf != in_buf)
985     {
986     *p_buf_len = (int)(p_buf + *p_buf_len - in_buf);
987     *p_buf_offset = 0;
988     *p_conv_len = (int)(conv_size - out_bytes);
989     memmove(p_buf, in_buf, (size_t)(*p_buf_len));
990     }
991 sysadm 1.54
992     break;
993     }
994     else if (errno == E2BIG)
995     {
996     log_error("iconv(inbytes=%d, outbytes=%d) error: E2BIG\n", in_bytes, out_bytes);
997     return -1;
998     }
999     else if (errno == EILSEQ)
1000     {
1001     if (in_bytes > out_bytes || out_bytes <= 0)
1002     {
1003     log_error("iconv(inbytes=%d, outbytes=%d) error: EILSEQ and E2BIG\n", in_bytes, out_bytes);
1004     return -2;
1005     }
1006    
1007 sysadm 1.59 // reset in_bytes when "//IGNORE" is applied
1008     if (in_bytes == 0)
1009     {
1010     in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
1011     }
1012    
1013 sysadm 1.54 *out_buf = *in_buf;
1014     in_buf++;
1015     out_buf++;
1016     in_bytes--;
1017     out_bytes--;
1018    
1019     continue;
1020     }
1021     }
1022     else
1023     {
1024     *p_buf_len = 0;
1025     *p_buf_offset = 0;
1026     *p_conv_len = (int)(conv_size - out_bytes);
1027    
1028     break;
1029     }
1030     }
1031    
1032     return 0;
1033     }
1034 sysadm 1.55
1035     int io_conv_init(const char *charset)
1036     {
1037 sysadm 1.58 char tocode[32];
1038    
1039 sysadm 1.55 if (charset == NULL)
1040     {
1041     log_error("NULL pointer error\n");
1042     return -1;
1043     }
1044    
1045     io_conv_cleanup();
1046    
1047 sysadm 1.58 strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);
1048     stdio_charset[sizeof(stdio_charset) - 1] = '\0';
1049 sysadm 1.55
1050 sysadm 1.60 snprintf(tocode, sizeof(tocode), "%s%s", BBS_DEFAULT_CHARSET,
1051     (strcasecmp(stdio_charset, BBS_DEFAULT_CHARSET) == 0 ? "" : "//IGNORE"));
1052     stdin_cd = iconv_open(tocode, stdio_charset);
1053 sysadm 1.55 if (stdin_cd == (iconv_t)(-1))
1054     {
1055 sysadm 1.60 log_error("iconv_open(%s->%s) error: %d\n", stdio_charset, tocode, errno);
1056 sysadm 1.55 return -2;
1057     }
1058 sysadm 1.58
1059 sysadm 1.60 snprintf(tocode, sizeof(tocode), "%s%s", stdio_charset,
1060     (strcasecmp(BBS_DEFAULT_CHARSET, stdio_charset) == 0 ? "" : "//TRANSLIT"));
1061 sysadm 1.58 stdout_cd = iconv_open(tocode, BBS_DEFAULT_CHARSET);
1062 sysadm 1.55 if (stdout_cd == (iconv_t)(-1))
1063     {
1064 sysadm 1.58 log_error("iconv_open(%s->%s) error: %d\n", BBS_DEFAULT_CHARSET, tocode, errno);
1065 sysadm 1.55 iconv_close(stdin_cd);
1066     return -2;
1067     }
1068    
1069     return 0;
1070     }
1071    
1072     int io_conv_cleanup(void)
1073     {
1074     if (stdin_cd != NULL)
1075     {
1076     iconv_close(stdin_cd);
1077     stdin_cd = NULL;
1078     }
1079     if (stdout_cd != NULL)
1080     {
1081     iconv_close(stdout_cd);
1082     stdout_cd = NULL;
1083     }
1084    
1085     return 0;
1086     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1