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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.73 - (hide annotations)
Wed Dec 17 03:56:39 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.72: +6 -0 lines
Content type: text/x-csrc
Refine debug log

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

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