/[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.26 by sysadm, Sun May 11 04:09:08 2025 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          Copyright            : (C) 2004-2025 by Leaflet   *   - basic terminal-based user input / output features
5          Email                : leaflet@leafok.com   *
6   ***************************************************************************/   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7     */
8  /***************************************************************************  
9   *                                                                         *  #ifdef HAVE_CONFIG_H
10   *   This program is free software; you can redistribute it and/or modify  *  #include "config.h"
11   *   it under the terms of the GNU General Public License as published by  *  #endif
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
12    
13    #include "common.h"
14  #include "io.h"  #include "io.h"
15  #include "log.h"  #include "log.h"
 #include "common.h"  
16  #include <errno.h>  #include <errno.h>
17  #include <stdio.h>  #include <fcntl.h>
18  #include <stdarg.h>  #include <stdarg.h>
19    #include <stdio.h>
20    #include <string.h>
21  #include <time.h>  #include <time.h>
 #include <fcntl.h>  
22  #include <unistd.h>  #include <unistd.h>
23  #include <sys/select.h>  #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  int outc(char c)  static iconv_t stdin_cd = NULL;
55    static iconv_t stdout_cd = NULL;
56    
57    int io_init(void)
58  {  {
59          int retval;          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          retval = fprintf(stdout, "%c", c);                  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          return retval;          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, ...)  int prints(const char *format, ...)
143  {  {
144            char buf[BUFSIZ];
145          va_list args;          va_list args;
146          int retval;          int ret;
147    
148          va_start(args, format);          va_start(args, format);
149          retval = vfprintf(stdout, format, args);          ret = vsnprintf(buf, sizeof(buf), format, args);
150          va_end(args);          va_end(args);
151    
152          return retval;          if (ret > 0)
153  }          {
154                    if (stdout_buf_len + ret > BUFSIZ)
155  int iflush()                  {
156  {                          iflush();
157          int retval;                  }
158    
159          retval = fflush(stdout);                  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 retval;          return ret;
173  }  }
174    
175  int igetch(int clear_buf)  int outc(char c)
176  {  {
         // static input buffer  
         static unsigned char buf[LINE_BUFFER_LEN];  
         static ssize_t len = 0;  
         static int pos = 0;  
   
         fd_set testfds;  
         struct timeval timeout;  
   
         unsigned char tmp[LINE_BUFFER_LEN];  
177          int ret;          int ret;
         int out = KEY_NULL;  
         int in_esc = 0;  
         int in_ascii = 0;  
         int in_control = 0;  
         int i = 0;  
         int flags;  
178    
179          if (clear_buf)          if (stdout_buf_len + 1 > BUFSIZ)
180          {          {
181                  pos = 0;                  iflush();
                 len = 0;  
   
                 return 0;  
182          }          }
183    
184          while (!SYS_server_exit && pos >= len)          if (stdout_buf_len + 1 <= BUFSIZ)
185          {          {
186                  FD_ZERO(&testfds);                  stdout_buf[stdout_buf_len] = c;
187                  FD_SET(STDIN_FILENO, &testfds);                  stdout_buf_len++;
188            }
189            else
190            {
191                    errno = EAGAIN;
192                    ret = -1;
193            }
194    
195                  timeout.tv_sec = 0;          return ret;
196                  timeout.tv_usec = 100 * 1000; // 0.1 second  }
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                  ret = select(STDIN_FILENO + 1, &testfds, NULL, NULL, &timeout);                  nfds = epoll_wait(stdout_epollfd, events, MAX_EVENTS, 100); // 0.1 second
212    
213                  if (ret < 0)                  if (nfds < 0)
214                  {                  {
215                          if (errno != EINTR)                          if (errno != EINTR)
216                          {                          {
217                                  log_error("Select error in igetch: !\n", errno);                                  log_error("epoll_wait() error (%d)\n", errno);
218                                  return KEY_NULL;                                  break;
219                          }                          }
220                          continue;                          continue;
221                  }                  }
222                  else if (ret == 0)                  else if (nfds == 0) // timeout
223                  {                  {
224                          return KEY_TIMEOUT;                          continue;
225                  }                  }
226    
227                  if (FD_ISSET(STDIN_FILENO, &testfds))                  for (int i = 0; i < nfds; i++)
228                  {                  {
229                          flags = fcntl(STDIN_FILENO, F_GETFL, 0);                          if (events[i].data.fd == STDOUT_FILENO)
                         fcntl(socket_server, F_SETFL, flags | O_NONBLOCK);  
   
                         len = read(STDIN_FILENO, buf, sizeof(buf));  
                         if (len < 0)  
230                          {                          {
231                                  if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)                                  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                                          log_error("Read socket error (%d)\n", errno);                                          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                          pos = 0;          return ret;
300    }
301    
302                          fcntl(STDIN_FILENO, F_SETFL, flags);  int igetch(int timeout)
303    {
304            static int stdin_read_wait = 0;
305    
306                          break;          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                    for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
324                    {
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                  // For debug                  if (stdin_buf_offset < stdin_buf_len)
437                  // for (j = 0; j < len; j++)                  {
438                  //   log_std ("<--[%u]\n", (buf[j] + 256) % 256);                          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 (pos < len)          while (stdin_conv_offset < stdin_conv_len)
456          {          {
457                  unsigned char c = buf[pos++];                  unsigned char c = (unsigned char)stdin_conv[stdin_conv_offset++];
458    
459                  if (c == '\0')                  // Convert \r\n to \r
460                    if (c == CR && stdin_conv_offset < stdin_conv_len && stdin_conv[stdin_conv_offset] == LF)
461                  {                  {
462                          return KEY_NULL;                          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)                  if (c == KEY_CONTROL)
# Line 164  int igetch(int clear_buf) Line 490  int igetch(int clear_buf)
490                          continue;                          continue;
491                  }                  }
492    
493                  if (c == ESC_KEY)                  if (c == KEY_ESC)
494                  {                  {
495                          if (in_esc == 0)                          if (in_esc == 0)
496                          {                          {
# Line 175  int igetch(int clear_buf) Line 501  int igetch(int clear_buf)
501                          }                          }
502                          else                          else
503                          {                          {
504                                  out = ESC_KEY;                                  out = KEY_CSI;
505                                  in_esc = 0;                                  in_esc = 0;
506                                  break;                                  break;
507                          }                          }
# Line 186  int igetch(int clear_buf) Line 512  int igetch(int clear_buf)
512                  if (in_ascii)                  if (in_ascii)
513                  {                  {
514                          tmp[i++] = c;                          tmp[i++] = c;
515                          if (c == 'm')                          if (i == 2 && (tmp[0] == 79 || tmp[0] == 91))
516                          {                          {
517                                  in_ascii = 0;                                  in_ascii = 0;
518                                  continue;                                  switch (tmp[1])
                         }  
                         if (i == 2 && c >= 'A' && c <= 'D')  
                         {  
                                 in_ascii = 0;  
                                 switch (c)  
519                                  {                                  {
520                                  case 'A':                                  case 65:
521                                          out = KEY_UP;                                          out = KEY_UP;
522                                          break;                                          break;
523                                  case 'B':                                  case 66:
524                                          out = KEY_DOWN;                                          out = KEY_DOWN;
525                                          break;                                          break;
526                                  case 'C':                                  case 67:
527                                          out = KEY_RIGHT;                                          out = KEY_RIGHT;
528                                          break;                                          break;
529                                  case 'D':                                  case 68:
530                                          out = KEY_LEFT;                                          out = KEY_LEFT;
531                                          break;                                          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                                  }                                  }
                                 break;  
631                          }                          }
632                          if (i == 3 && tmp[0] == 91 && tmp[2] == 126)                          if (i == 3 && tmp[0] == 91 && tmp[2] == 126)
633                          {                          {
# Line 219  int igetch(int clear_buf) Line 637  int igetch(int clear_buf)
637                                  case 49:                                  case 49:
638                                          out = KEY_HOME;                                          out = KEY_HOME;
639                                          break;                                          break;
640                                    case 50:
641                                            out = KEY_INS;
642                                            break;
643                                  case 51:                                  case 51:
644                                          out = KEY_DEL;                                          out = KEY_DEL;
645                                          break;                                          break;
# Line 231  int igetch(int clear_buf) Line 652  int igetch(int clear_buf)
652                                  case 54:                                  case 54:
653                                          out = KEY_PGDN;                                          out = KEY_PGDN;
654                                          break;                                          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                                  break;                          }
893    
894                            if (c == 'm')
895                            {
896                                    in_ascii = 0;
897                          }                          }
898                          continue;                          continue;
899                  }                  }
# Line 241  int igetch(int clear_buf) Line 902  int igetch(int clear_buf)
902                  break;                  break;
903          }          }
904    
905            // For ESC key
906            if (out == 0 && in_esc)
907            {
908                    out = KEY_ESC;
909            }
910    
911          // for debug          // for debug
912          // log_std ("-->[%u]\n", out);  #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;          return out;
920  }  }
921    
922  int igetch_t(long int sec)  int igetch_t(int sec)
923  {  {
924          int ch;          int ch;
925          time_t t_begin = time(0);          time_t t_begin = time(NULL);
926    
927          do          do
928          {          {
929                  ch = igetch(0);                  ch = igetch(100);
930          } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));          } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec));
931    
932          return ch;          return ch;
933  }  }
934    
935    void igetch_reset()
936    {
937            int ch;
938            do
939            {
940                    ch = igetch(100);
941            } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
942    }
943    
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    {
946            char *in_buf;
947            char *out_buf;
948            size_t in_bytes;
949            size_t out_bytes;
950            int ret;
951            int in_control = 0;
952            size_t i = 0;
953    
954            if (cd == NULL || p_buf == NULL || p_buf_len == NULL || p_buf_offset == NULL || p_conv == NULL || p_conv_len == NULL)
955            {
956                    log_error("NULL pointer error\n");
957                    return -1;
958            }
959    
960            in_buf = p_buf + *p_buf_offset;
961            in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
962            out_buf = p_conv + *p_conv_len;
963            out_bytes = conv_size - (size_t)(*p_conv_len);
964    
965            while (in_bytes > 0)
966            {
967                    if ((unsigned char)(*in_buf) == KEY_CONTROL)
968                    {
969                            if (in_control == 0)
970                            {
971                                    in_control = 1;
972                                    i = 0;
973                            }
974                    }
975    
976                    if (in_control)
977                    {
978                            if (out_bytes <= 0)
979                            {
980                                    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                            }
983    
984                            *out_buf = *in_buf;
985                            in_buf++;
986                            out_buf++;
987                            in_bytes--;
988                            out_bytes--;
989    
990                            (*p_buf_offset)++;
991                            *p_conv_len = (int)(conv_size - out_bytes);
992    
993                            i++;
994                            if (i >= 2)
995                            {
996                                    in_control = 0;
997                            }
998                            continue;
999                    }
1000    
1001                    ret = (int)iconv(cd, &in_buf, &in_bytes, &out_buf, &out_bytes);
1002                    if (ret == -1)
1003                    {
1004                            if (errno == EINVAL) // Incomplete
1005                            {
1006    #ifdef _DEBUG
1007                                    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                                    {
1011                                            *p_buf_len = (int)(p_buf + *p_buf_len - in_buf);
1012                                            *p_buf_offset = 0;
1013                                            *p_conv_len = (int)(conv_size - out_bytes);
1014                                            memmove(p_buf, in_buf, (size_t)(*p_buf_len));
1015                                    }
1016    
1017                                    break;
1018                            }
1019                            else if (errno == E2BIG)
1020                            {
1021                                    log_error("iconv(inbytes=%d, outbytes=%d) error: E2BIG\n", in_bytes, out_bytes);
1022                                    return -1;
1023                            }
1024                            else if (errno == EILSEQ)
1025                            {
1026                                    if (in_bytes > out_bytes || out_bytes <= 0)
1027                                    {
1028                                            log_error("iconv(inbytes=%d, outbytes=%d) error: EILSEQ and E2BIG\n", in_bytes, out_bytes);
1029                                            return -2;
1030                                    }
1031    
1032                                    // reset in_bytes when "//IGNORE" is applied
1033                                    if (in_bytes == 0)
1034                                    {
1035                                            in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
1036                                    }
1037    
1038                                    *out_buf = *in_buf;
1039                                    in_buf++;
1040                                    out_buf++;
1041                                    in_bytes--;
1042                                    out_bytes--;
1043    
1044                                    continue;
1045                            }
1046                    }
1047                    else
1048                    {
1049                            *p_buf_len = 0;
1050                            *p_buf_offset = 0;
1051                            *p_conv_len = (int)(conv_size - out_bytes);
1052    
1053                            break;
1054                    }
1055            }
1056    
1057            return 0;
1058    }
1059    
1060    int io_conv_init(const char *charset)
1061    {
1062            char tocode[CHARSET_MAX_LEN + 20];
1063    
1064            if (charset == NULL)
1065            {
1066                    log_error("NULL pointer error\n");
1067                    return -1;
1068            }
1069    
1070            io_conv_cleanup();
1071    
1072            strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);
1073            stdio_charset[sizeof(stdio_charset) - 1] = '\0';
1074    
1075            snprintf(tocode, sizeof(tocode), "%s%s", BBS_default_charset,
1076                             (strcasecmp(stdio_charset, BBS_default_charset) == 0 ? "" : "//IGNORE"));
1077            stdin_cd = iconv_open(tocode, stdio_charset);
1078            if (stdin_cd == (iconv_t)(-1))
1079            {
1080                    log_error("iconv_open(%s->%s) error: %d\n", stdio_charset, tocode, errno);
1081                    return -2;
1082            }
1083    
1084            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            if (stdout_cd == (iconv_t)(-1))
1088            {
1089                    log_error("iconv_open(%s->%s) error: %d\n", BBS_default_charset, tocode, errno);
1090                    iconv_close(stdin_cd);
1091                    return -2;
1092            }
1093    
1094            return 0;
1095    }
1096    
1097    int io_conv_cleanup(void)
1098    {
1099            if (stdin_cd != NULL)
1100            {
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