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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.65 - (hide annotations)
Tue Nov 11 00:28:05 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.64: +4 -0 lines
Content type: text/x-csrc
Use config.h

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

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