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

Contents of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.78 - (show annotations)
Thu Dec 18 11:37:08 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.77: +12 -10 lines
Content type: text/x-csrc
Refine

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

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