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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.64 - (hide annotations)
Wed Nov 5 02:48:48 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.63: +8 -7 lines
Content type: text/x-csrc
Use enum / const int instead of macro define constant integers
Use const char * instead of macro define for constant strings

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

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