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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.67 - (hide annotations)
Mon Nov 17 06:41:18 2025 UTC (3 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.66: +87 -8 lines
Content type: text/x-csrc
Add --with-epoll to configure to switch between epoll and poll

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

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