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

Diff of /lbbs/src/io.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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