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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.80 - (hide annotations)
Fri Dec 19 06:16:27 2025 UTC (2 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.79: +50 -50 lines
Content type: text/x-csrc
Append \n to the end of logging message by log_...()
Remove ending \n from each logging message

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

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