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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.78 - (hide 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 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 sysadm 1.78 log_error("close(stdout_epollfd) error (%d)\n", errno);
136 sysadm 1.66 }
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 sysadm 1.78 log_error("close(stdout_epollfd) error (%d)\n", errno);
218 sysadm 1.66 }
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.78 ret = -1;
266 sysadm 1.30 }
267 sysadm 1.28 }
268 sysadm 1.30
269     return ret;
270     }
271    
272     int outc(char c)
273     {
274 sysadm 1.77 int ret = 0;
275 sysadm 1.30
276 sysadm 1.68 if (stdout_buf_len + 1 > OUTPUT_BUF_SIZE)
277 sysadm 1.28 {
278 sysadm 1.30 iflush();
279     }
280    
281 sysadm 1.68 if (stdout_buf_len + 1 <= OUTPUT_BUF_SIZE)
282 sysadm 1.30 {
283     stdout_buf[stdout_buf_len] = c;
284     stdout_buf_len++;
285     }
286     else
287     {
288     errno = EAGAIN;
289     ret = -1;
290 sysadm 1.28 }
291    
292     return ret;
293 sysadm 1.1 }
294    
295 sysadm 1.43 int iflush(void)
296 sysadm 1.1 {
297 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
298 sysadm 1.66 struct epoll_event events[MAX_EVENTS];
299 sysadm 1.67 #else
300     struct pollfd pfds[1];
301     #endif
302    
303 sysadm 1.66 int nfds;
304 sysadm 1.28 int ret = 0;
305    
306 sysadm 1.30 // Retry wait / flush for at most 3 times
307 sysadm 1.74 for (int retry = 3; retry > 0 && !SYS_server_exit; retry--)
308 sysadm 1.28 {
309 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
310 sysadm 1.66 nfds = epoll_wait(stdout_epollfd, events, MAX_EVENTS, 100); // 0.1 second
311 sysadm 1.67 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 sysadm 1.28
319 sysadm 1.67 if (ret < 0)
320 sysadm 1.28 {
321 sysadm 1.29 if (errno != EINTR)
322     {
323 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
324 sysadm 1.29 log_error("epoll_wait() error (%d)\n", errno);
325 sysadm 1.67 #else
326     log_error("poll() error (%d)\n", errno);
327     #endif
328 sysadm 1.29 break;
329     }
330 sysadm 1.28 continue;
331     }
332 sysadm 1.67 else if (ret == 0) // timeout
333 sysadm 1.28 {
334 sysadm 1.29 continue;
335 sysadm 1.28 }
336 sysadm 1.29
337     for (int i = 0; i < nfds; i++)
338 sysadm 1.28 {
339 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
340 sysadm 1.76 if (events[i].data.fd == STDOUT_FILENO && (events[i].events & (EPOLLHUP | EPOLLERR)))
341 sysadm 1.74 #else
342 sysadm 1.76 if (pfds[i].fd == STDOUT_FILENO && (pfds[i].revents & (POLLHUP | POLLERR)))
343 sysadm 1.74 #endif
344     {
345     #ifdef HAVE_SYS_EPOLL_H
346 sysadm 1.75 log_debug("STDOUT error events (%d)\n", events[i].events);
347 sysadm 1.74 #else
348 sysadm 1.75 log_debug("STDOUT error events (%d)\n", pfds[i].revents);
349 sysadm 1.74 #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 sysadm 1.67 #else
357     if (pfds[i].fd == STDOUT_FILENO && (pfds[i].revents & POLLOUT))
358     #endif
359 sysadm 1.28 {
360 sysadm 1.55 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 sysadm 1.60 stdout_buf_len = stdout_buf_offset; // Discard invalid sequence
367 sysadm 1.55 }
368     }
369    
370     while (stdout_conv_offset < stdout_conv_len && !SYS_server_exit) // write until complete or error
371 sysadm 1.28 {
372 sysadm 1.39 if (SSH_v2)
373     {
374 sysadm 1.55 ret = ssh_channel_write(SSH_channel, stdout_conv + stdout_conv_offset, (uint32_t)(stdout_conv_len - stdout_conv_offset));
375 sysadm 1.39 if (ret == SSH_ERROR)
376     {
377 sysadm 1.75 log_debug("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));
378 sysadm 1.39 retry = 0;
379     break;
380     }
381     }
382     else
383     {
384 sysadm 1.55 ret = (int)write(STDOUT_FILENO, stdout_conv + stdout_conv_offset, (size_t)(stdout_conv_len - stdout_conv_offset));
385 sysadm 1.39 }
386 sysadm 1.29 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 sysadm 1.75 log_debug("write(STDOUT) error (%d)\n", errno);
399 sysadm 1.30 retry = 0;
400 sysadm 1.29 break;
401     }
402     }
403     else if (ret == 0) // broken pipe
404     {
405 sysadm 1.30 retry = 0;
406 sysadm 1.29 break;
407     }
408     else
409     {
410 sysadm 1.55 stdout_conv_offset += ret;
411     if (stdout_conv_offset >= stdout_conv_len) // flush buffer completely
412 sysadm 1.29 {
413     ret = 0;
414 sysadm 1.55 stdout_conv_offset = 0;
415     stdout_conv_len = 0;
416 sysadm 1.30 retry = 0;
417 sysadm 1.29 break;
418     }
419     continue;
420     }
421 sysadm 1.28 }
422     }
423     }
424     }
425 sysadm 1.6
426 sysadm 1.28 return ret;
427 sysadm 1.1 }
428    
429 sysadm 1.31 int igetch(int timeout)
430 sysadm 1.1 {
431 sysadm 1.61 static int stdin_read_wait = 0;
432    
433 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
434 sysadm 1.66 struct epoll_event events[MAX_EVENTS];
435 sysadm 1.67 #else
436     struct pollfd pfds[1];
437     #endif
438    
439 sysadm 1.66 int nfds;
440 sysadm 1.31 int ret;
441     int loop;
442 sysadm 1.21
443 sysadm 1.22 unsigned char tmp[LINE_BUFFER_LEN];
444 sysadm 1.31 int out = KEY_NULL;
445 sysadm 1.18 int in_esc = 0;
446     int in_ascii = 0;
447     int in_control = 0;
448     int i = 0;
449 sysadm 1.1
450 sysadm 1.55 if (stdin_conv_offset >= stdin_conv_len)
451 sysadm 1.29 {
452 sysadm 1.55 stdin_conv_len = 0;
453     stdin_conv_offset = 0;
454 sysadm 1.31
455 sysadm 1.57 for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
456 sysadm 1.39 {
457 sysadm 1.48 if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
458     {
459 sysadm 1.75 log_debug("SSH channel is closed\n");
460 sysadm 1.48 loop = 0;
461     break;
462     }
463 sysadm 1.39
464 sysadm 1.61 if (!stdin_read_wait)
465     {
466 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
467 sysadm 1.66 nfds = epoll_wait(stdin_epollfd, events, MAX_EVENTS, timeout);
468 sysadm 1.67 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 sysadm 1.9
476 sysadm 1.67 if (ret < 0)
477 sysadm 1.61 {
478     if (errno != EINTR)
479     {
480 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
481 sysadm 1.61 log_error("epoll_wait() error (%d)\n", errno);
482 sysadm 1.67 #else
483     log_error("poll() error (%d)\n", errno);
484     #endif
485 sysadm 1.61 break;
486     }
487     continue;
488     }
489 sysadm 1.67 else if (ret == 0) // timeout
490 sysadm 1.48 {
491 sysadm 1.61 out = KEY_TIMEOUT;
492 sysadm 1.48 break;
493     }
494 sysadm 1.61
495     for (int i = 0; i < nfds; i++)
496     {
497 sysadm 1.67 #ifdef HAVE_SYS_EPOLL_H
498 sysadm 1.76 if (events[i].data.fd == STDIN_FILENO && (events[i].events & (EPOLLHUP | EPOLLERR)))
499 sysadm 1.74 #else
500 sysadm 1.76 if (pfds[i].fd == STDIN_FILENO && (pfds[i].revents & (POLLHUP | POLLERR)))
501 sysadm 1.74 #endif
502     {
503     #ifdef HAVE_SYS_EPOLL_H
504 sysadm 1.75 log_debug("STDIN error events (%d)\n", events[i].events);
505 sysadm 1.74 #else
506 sysadm 1.75 log_debug("STDIN error events (%d)\n", pfds[i].revents);
507 sysadm 1.74 #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 sysadm 1.67 #else
515     if (pfds[i].fd == STDIN_FILENO && (pfds[i].revents & POLLIN))
516     #endif
517 sysadm 1.61 {
518     stdin_read_wait = 1;
519     }
520     }
521 sysadm 1.21 }
522    
523 sysadm 1.61 if (stdin_read_wait)
524 sysadm 1.26 {
525 sysadm 1.61 while (stdin_buf_len < sizeof(stdin_buf) && !SYS_server_exit) // read until complete or error
526 sysadm 1.26 {
527 sysadm 1.61 if (SSH_v2)
528 sysadm 1.39 {
529 sysadm 1.61 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 sysadm 1.39 {
532 sysadm 1.75 log_debug("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));
533 sysadm 1.61 loop = 0;
534     break;
535 sysadm 1.39 }
536 sysadm 1.61 else if (ret == SSH_EOF)
537 sysadm 1.39 {
538 sysadm 1.61 stdin_read_wait = 0;
539     loop = 0;
540     break;
541 sysadm 1.39 }
542 sysadm 1.61 else if (ret == 0)
543 sysadm 1.39 {
544 sysadm 1.61 out = 0;
545     stdin_read_wait = 0;
546     loop = 0;
547     break;
548 sysadm 1.39 }
549 sysadm 1.61 }
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 sysadm 1.29 {
558 sysadm 1.61 out = 0;
559     stdin_read_wait = 0;
560 sysadm 1.31 loop = 0;
561     break;
562 sysadm 1.29 }
563 sysadm 1.61 else if (errno == EINTR)
564     {
565     continue;
566     }
567 sysadm 1.48 else
568 sysadm 1.29 {
569 sysadm 1.75 log_debug("read(STDIN) error (%d)\n", errno);
570 sysadm 1.61 loop = 0;
571     break;
572 sysadm 1.29 }
573     }
574 sysadm 1.61 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 sysadm 1.26 }
586     }
587 sysadm 1.48
588     // For debug
589     #ifdef _DEBUG
590 sysadm 1.55 for (int j = stdin_buf_offset; j < stdin_buf_len; j++)
591 sysadm 1.48 {
592 sysadm 1.75 log_debug("input: <--[%u]\n", (stdin_buf[j] + 256) % 256);
593 sysadm 1.48 }
594     #endif
595 sysadm 1.14 }
596    
597 sysadm 1.55 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 sysadm 1.60 stdin_buf_len = stdin_buf_offset; // Discard invalid sequence
604 sysadm 1.55 }
605 sysadm 1.56
606     // For debug
607     #ifdef _DEBUG
608     for (int j = stdin_conv_offset; j < stdin_conv_len; j++)
609     {
610 sysadm 1.75 log_debug("input_conv: <--[%u]\n", (stdin_conv[j] + 256) % 256);
611 sysadm 1.56 }
612     #endif
613 sysadm 1.55 }
614 sysadm 1.11 }
615 sysadm 1.14
616 sysadm 1.55 while (stdin_conv_offset < stdin_conv_len)
617 sysadm 1.11 {
618 sysadm 1.55 unsigned char c = (unsigned char)stdin_conv[stdin_conv_offset++];
619 sysadm 1.5
620 sysadm 1.51 // Convert \r\n to \r
621 sysadm 1.55 if (c == CR && stdin_conv_offset < stdin_conv_len && stdin_conv[stdin_conv_offset] == LF)
622 sysadm 1.51 {
623 sysadm 1.55 stdin_conv_offset++;
624 sysadm 1.51 }
625    
626     // Convert single \n to \r
627     if (c == LF)
628     {
629     c = CR;
630     }
631    
632 sysadm 1.14 if (c == KEY_CONTROL)
633     {
634     if (in_control == 0)
635     {
636     in_control = 1;
637     i = 0;
638     continue;
639     }
640     }
641 sysadm 1.1
642 sysadm 1.14 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 sysadm 1.6
654 sysadm 1.37 if (c == KEY_ESC)
655 sysadm 1.14 {
656     if (in_esc == 0)
657     {
658     in_esc = 1;
659     in_ascii = 1;
660     i = 0;
661     continue;
662     }
663     else
664     {
665 sysadm 1.37 out = KEY_CSI;
666 sysadm 1.14 in_esc = 0;
667     break;
668     }
669     }
670 sysadm 1.3
671 sysadm 1.14 in_esc = 0;
672 sysadm 1.1
673 sysadm 1.14 if (in_ascii)
674     {
675     tmp[i++] = c;
676 sysadm 1.33 if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
677 sysadm 1.14 {
678     in_ascii = 0;
679 sysadm 1.33 switch (tmp[1])
680 sysadm 1.14 {
681 sysadm 1.33 case 65:
682 sysadm 1.14 out = KEY_UP;
683     break;
684 sysadm 1.33 case 66:
685 sysadm 1.14 out = KEY_DOWN;
686     break;
687 sysadm 1.33 case 67:
688 sysadm 1.14 out = KEY_RIGHT;
689     break;
690 sysadm 1.33 case 68:
691 sysadm 1.14 out = KEY_LEFT;
692     break;
693 sysadm 1.33 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 sysadm 1.14 }
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 sysadm 1.42 case 50:
802     out = KEY_INS;
803     break;
804 sysadm 1.14 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 sysadm 1.33 default:
817     in_ascii = 1;
818     }
819     if (!in_ascii)
820     {
821     break;
822     }
823     }
824 sysadm 1.39 if (i == 4 && tmp[0] == 91 && tmp[1] == 49 && tmp[3] == 126) // Fterm
825 sysadm 1.33 {
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 sysadm 1.41 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 sysadm 1.33 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 sysadm 1.14 }
1003 sysadm 1.33 }
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 sysadm 1.14 }
1059     continue;
1060     }
1061 sysadm 1.1
1062 sysadm 1.14 out = ((int)c + 256) % 256;
1063     break;
1064 sysadm 1.1 }
1065    
1066 sysadm 1.36 // For ESC key
1067     if (out == 0 && in_esc)
1068     {
1069     out = KEY_ESC;
1070     }
1071    
1072 sysadm 1.33 // for debug
1073 sysadm 1.45 #ifdef _DEBUG
1074     if (out != KEY_TIMEOUT && out != KEY_NULL)
1075     {
1076 sysadm 1.75 log_debug("output: -->[0x %x]\n", out);
1077 sysadm 1.45 }
1078     #endif
1079 sysadm 1.33
1080 sysadm 1.14 return out;
1081 sysadm 1.1 }
1082 sysadm 1.5
1083 sysadm 1.31 int igetch_t(int sec)
1084 sysadm 1.9 {
1085 sysadm 1.14 int ch;
1086 sysadm 1.44 time_t t_begin = time(NULL);
1087 sysadm 1.10
1088 sysadm 1.14 do
1089     {
1090 sysadm 1.31 ch = igetch(100);
1091 sysadm 1.44 } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec));
1092 sysadm 1.9
1093 sysadm 1.14 return ch;
1094 sysadm 1.9 }
1095 sysadm 1.31
1096     void igetch_reset()
1097     {
1098     int ch;
1099     do
1100     {
1101 sysadm 1.53 ch = igetch(100);
1102 sysadm 1.31 } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
1103     }
1104 sysadm 1.54
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 sysadm 1.56 int in_control = 0;
1113     size_t i = 0;
1114 sysadm 1.69 int skip_current = 0;
1115 sysadm 1.54
1116 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)
1117 sysadm 1.55 {
1118     log_error("NULL pointer error\n");
1119     return -1;
1120     }
1121    
1122 sysadm 1.54 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 sysadm 1.56 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 sysadm 1.69 if (in_control || skip_current)
1139 sysadm 1.56 {
1140 sysadm 1.69 skip_current = 0;
1141    
1142 sysadm 1.56 if (out_bytes <= 0)
1143     {
1144 sysadm 1.60 log_error("No enough free space in p_conv, conv_len=%d, conv_size=%d\n", *p_conv_len, conv_size);
1145 sysadm 1.56 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 sysadm 1.69 (*p_conv_len)++;
1156 sysadm 1.56
1157     i++;
1158     if (i >= 2)
1159     {
1160     in_control = 0;
1161     }
1162     continue;
1163     }
1164    
1165 sysadm 1.54 ret = (int)iconv(cd, &in_buf, &in_bytes, &out_buf, &out_bytes);
1166     if (ret == -1)
1167     {
1168     if (errno == EINVAL) // Incomplete
1169     {
1170 sysadm 1.78 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 sysadm 1.56 if (p_buf != in_buf)
1173     {
1174 sysadm 1.69 *p_buf_len -= (int)(in_buf - p_buf);
1175 sysadm 1.56 *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 sysadm 1.54
1180     break;
1181     }
1182     else if (errno == E2BIG)
1183     {
1184 sysadm 1.78 log_error("iconv(inbytes=%zu, outbytes=%zu) error: E2BIG\n", in_bytes, out_bytes);
1185 sysadm 1.54 return -1;
1186     }
1187     else if (errno == EILSEQ)
1188     {
1189     if (in_bytes > out_bytes || out_bytes <= 0)
1190     {
1191 sysadm 1.78 log_error("iconv(inbytes=%zu, outbytes=%zu) error: EILSEQ\n", in_bytes, out_bytes);
1192 sysadm 1.54 return -2;
1193     }
1194    
1195 sysadm 1.59 // 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 sysadm 1.78 log_debug("Reset in_bytes from 0 to %zu\n", in_bytes);
1200 sysadm 1.59 }
1201    
1202 sysadm 1.78 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 sysadm 1.71 skip_current = 1;
1205 sysadm 1.69 }
1206     else // something strange
1207     {
1208 sysadm 1.78 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 sysadm 1.70 *p_buf_offset = (int)(in_buf - p_buf);
1211 sysadm 1.69 *p_conv_len = (int)(conv_size - out_bytes);
1212     skip_current = 1;
1213 sysadm 1.54 }
1214     }
1215     else
1216     {
1217 sysadm 1.71 *p_buf_offset = (int)(in_buf - p_buf);
1218 sysadm 1.54 *p_conv_len = (int)(conv_size - out_bytes);
1219     }
1220     }
1221    
1222 sysadm 1.69 if (*p_buf_offset >= *p_buf_len)
1223     {
1224     *p_buf_len = 0;
1225     *p_buf_offset = 0;
1226     }
1227    
1228 sysadm 1.54 return 0;
1229     }
1230 sysadm 1.55
1231     int io_conv_init(const char *charset)
1232     {
1233 sysadm 1.64 char tocode[CHARSET_MAX_LEN + 20];
1234 sysadm 1.58
1235 sysadm 1.55 if (charset == NULL)
1236     {
1237     log_error("NULL pointer error\n");
1238     return -1;
1239     }
1240    
1241     io_conv_cleanup();
1242    
1243 sysadm 1.58 strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);
1244     stdio_charset[sizeof(stdio_charset) - 1] = '\0';
1245 sysadm 1.55
1246 sysadm 1.64 snprintf(tocode, sizeof(tocode), "%s%s", BBS_default_charset,
1247     (strcasecmp(stdio_charset, BBS_default_charset) == 0 ? "" : "//IGNORE"));
1248 sysadm 1.60 stdin_cd = iconv_open(tocode, stdio_charset);
1249 sysadm 1.55 if (stdin_cd == (iconv_t)(-1))
1250     {
1251 sysadm 1.60 log_error("iconv_open(%s->%s) error: %d\n", stdio_charset, tocode, errno);
1252 sysadm 1.55 return -2;
1253     }
1254 sysadm 1.58
1255 sysadm 1.60 snprintf(tocode, sizeof(tocode), "%s%s", stdio_charset,
1256 sysadm 1.64 (strcasecmp(BBS_default_charset, stdio_charset) == 0 ? "" : "//TRANSLIT"));
1257     stdout_cd = iconv_open(tocode, BBS_default_charset);
1258 sysadm 1.55 if (stdout_cd == (iconv_t)(-1))
1259     {
1260 sysadm 1.64 log_error("iconv_open(%s->%s) error: %d\n", BBS_default_charset, tocode, errno);
1261 sysadm 1.55 iconv_close(stdin_cd);
1262 sysadm 1.72 stdin_cd = (iconv_t)(-1);
1263 sysadm 1.55 return -2;
1264     }
1265    
1266     return 0;
1267     }
1268    
1269     int io_conv_cleanup(void)
1270     {
1271 sysadm 1.72 if (stdin_cd != (iconv_t)(-1))
1272 sysadm 1.55 {
1273     iconv_close(stdin_cd);
1274 sysadm 1.72 stdin_cd = (iconv_t)(-1);
1275 sysadm 1.55 }
1276 sysadm 1.72 if (stdout_cd != (iconv_t)(-1))
1277 sysadm 1.55 {
1278     iconv_close(stdout_cd);
1279 sysadm 1.72 stdout_cd = (iconv_t)(-1);
1280 sysadm 1.55 }
1281    
1282     return 0;
1283     }

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