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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.77 - (hide annotations)
Thu Dec 18 11:18:29 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.76: +78 -24 lines
Content type: text/x-csrc
Refine and fix bugs

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

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