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


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

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