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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.63 - (hide annotations)
Tue Nov 4 14:58:56 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.62: +1 -1 lines
Content type: text/x-csrc
Refine file header information comments

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

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