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

Annotation of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.60 - (hide annotations)
Mon Oct 20 01:55:50 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.59: +9 -4 lines
Content type: text/x-csrc
Do not apply //IGNORE or //TRANSLIT if tocode and fromcode is the same

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

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