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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.74 - (hide annotations)
Thu Dec 18 02:17:39 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.73: +37 -7 lines
Content type: text/x-csrc
Add handling of error events (EPOLLRDHUP | EPOLLHUP | EPOLLERR)

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

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