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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.75 - (hide annotations)
Thu Dec 18 02:56:00 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.74: +16 -38 lines
Content type: text/x-csrc
Refine with log_debug()

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

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