/[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.41 by sysadm, Mon Jun 9 15:39:05 2025 UTC Revision 1.67 by sysadm, Mon Nov 17 06:41:18 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>  #include <string.h>
21  #include <time.h>  #include <time.h>
 #include <fcntl.h>  
22  #include <unistd.h>  #include <unistd.h>
 #include <sys/select.h>  
23  #include <sys/ioctl.h>  #include <sys/ioctl.h>
24  #include <sys/epoll.h>  #include <sys/select.h>
25    #include <libssh/callbacks.h>
26  #include <libssh/libssh.h>  #include <libssh/libssh.h>
27  #include <libssh/server.h>  #include <libssh/server.h>
 #include <libssh/callbacks.h>  
28    
29    #ifdef HAVE_SYS_EPOLL_H
30    #include <sys/epoll.h>
31    #else
32    #include <poll.h>
33    #endif
34    
35    const char BBS_default_charset[CHARSET_MAX_LEN + 1] = "UTF-8";
36    char stdio_charset[CHARSET_MAX_LEN + 1] = "UTF-8";
37    
38    #ifdef HAVE_SYS_EPOLL_H
39    // epoll for STDIO
40    static int stdin_epollfd = -1;
41    static int stdout_epollfd = -1;
42    #endif
43    
44    static int stdin_flags = 0;
45    static int stdout_flags = 0;
46    
47    // static input / output buffer
48    static char stdin_buf[LINE_BUFFER_LEN];
49  static char stdout_buf[BUFSIZ];  static char stdout_buf[BUFSIZ];
50    static int stdin_buf_len = 0;
51  static int stdout_buf_len = 0;  static int stdout_buf_len = 0;
52    static int stdin_buf_offset = 0;
53  static int stdout_buf_offset = 0;  static int stdout_buf_offset = 0;
54    
55    static char stdin_conv[LINE_BUFFER_LEN * 2];
56    static char stdout_conv[BUFSIZ * 2];
57    static int stdin_conv_len = 0;
58    static int stdout_conv_len = 0;
59    static int stdin_conv_offset = 0;
60    static int stdout_conv_offset = 0;
61    
62    static iconv_t stdin_cd = NULL;
63    static iconv_t stdout_cd = NULL;
64    
65    int io_init(void)
66    {
67    #ifdef HAVE_SYS_EPOLL_H
68            struct epoll_event ev;
69    
70            if (stdin_epollfd == -1)
71            {
72                    stdin_epollfd = epoll_create1(0);
73                    if (stdin_epollfd == -1)
74                    {
75                            log_error("epoll_create1() error (%d)\n", errno);
76                            return -1;
77                    }
78    
79                    ev.events = EPOLLIN;
80                    ev.data.fd = STDIN_FILENO;
81                    if (epoll_ctl(stdin_epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
82                    {
83                            log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
84                            if (close(stdin_epollfd) < 0)
85                            {
86                                    log_error("close(stdin_epollfd) error (%d)\n");
87                            }
88                            stdin_epollfd = -1;
89                            return -1;
90                    }
91    
92                    stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
93                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
94            }
95    
96            if (stdout_epollfd == -1)
97            {
98                    stdout_epollfd = epoll_create1(0);
99                    if (stdout_epollfd == -1)
100                    {
101                            log_error("epoll_create1() error (%d)\n", errno);
102                            return -1;
103                    }
104    
105                    ev.events = EPOLLOUT;
106                    ev.data.fd = STDOUT_FILENO;
107                    if (epoll_ctl(stdout_epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
108                    {
109                            log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
110                            if (close(stdout_epollfd) < 0)
111                            {
112                                    log_error("close(stdout_epollfd) error (%d)\n");
113                            }
114                            stdout_epollfd = -1;
115                            return -1;
116                    }
117    
118                    stdout_flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
119                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags | O_NONBLOCK);
120            }
121    #else
122            if (stdin_flags == 0)
123            {
124                    stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
125                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
126            }
127    
128            if (stdout_flags == 0)
129            {
130                    stdout_flags = fcntl(STDOUT_FILENO, F_GETFL, 0);
131                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags | O_NONBLOCK);
132            }
133    #endif
134    
135            return 0;
136    }
137    
138    void io_cleanup(void)
139    {
140    #ifdef HAVE_SYS_EPOLL_H
141            if (stdin_epollfd != -1)
142            {
143                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags);
144                    stdin_flags = 0;
145    
146                    if (close(stdin_epollfd) < 0)
147                    {
148                            log_error("close(stdin_epollfd) error (%d)\n");
149                    }
150                    stdin_epollfd = -1;
151            }
152    
153            if (stdout_epollfd != -1)
154            {
155                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags);
156                    stdout_flags = 0;
157    
158                    if (close(stdout_epollfd) < 0)
159                    {
160                            log_error("close(stdout_epollfd) error (%d)\n");
161                    }
162                    stdout_epollfd = -1;
163            }
164    #else
165            if (stdin_flags != 0)
166            {
167                    fcntl(STDIN_FILENO, F_SETFL, stdin_flags);
168                    stdin_flags = 0;
169            }
170    
171            if (stdout_flags != 0)
172            {
173                    fcntl(STDOUT_FILENO, F_SETFL, stdout_flags);
174                    stdout_flags = 0;
175            }
176    #endif
177    }
178    
179  int prints(const char *format, ...)  int prints(const char *format, ...)
180  {  {
181          char buf[BUFSIZ];          char buf[BUFSIZ];
# Line 91  int outc(char c) Line 232  int outc(char c)
232          return ret;          return ret;
233  }  }
234    
235  int iflush()  int iflush(void)
236  {  {
237          int flags;  #ifdef HAVE_SYS_EPOLL_H
238          struct epoll_event ev, events[MAX_EVENTS];          struct epoll_event events[MAX_EVENTS];
239          int nfds, epollfd;  #else
240            struct pollfd pfds[1];
241    #endif
242    
243            int nfds;
244          int retry;          int retry;
245          int ret = 0;          int ret = 0;
246    
         epollfd = epoll_create1(0);  
         if (epollfd < 0)  
         {  
                 log_error("epoll_create1() error (%d)\n", errno);  
                 return -1;  
         }  
   
         ev.events = EPOLLOUT;  
         ev.data.fd = STDOUT_FILENO;  
         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)  
         {  
                 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);  
                 if (close(epollfd) < 0)  
                 {  
                         log_error("close(epoll) error (%d)\n");  
                 }  
                 return -1;  
         }  
   
         // Set STDOUT as non-blocking  
         flags = fcntl(STDOUT_FILENO, F_GETFL, 0);  
         fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);  
   
247          // Retry wait / flush for at most 3 times          // Retry wait / flush for at most 3 times
248          retry = 3;          retry = 3;
249          while (retry > 0 && !SYS_server_exit)          while (retry > 0 && !SYS_server_exit)
250          {          {
251                  retry--;                  retry--;
252    
253                  nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second  #ifdef HAVE_SYS_EPOLL_H
254                    nfds = epoll_wait(stdout_epollfd, events, MAX_EVENTS, 100); // 0.1 second
255                    ret = nfds;
256    #else
257                    pfds[0].fd = STDOUT_FILENO;
258                    pfds[0].events = POLLOUT;
259                    nfds = 1;
260                    ret = poll(pfds, (nfds_t)nfds, 100); // 0.1 second
261    #endif
262    
263                  if (nfds < 0)                  if (ret < 0)
264                  {                  {
265                          if (errno != EINTR)                          if (errno != EINTR)
266                          {                          {
267    #ifdef HAVE_SYS_EPOLL_H
268                                  log_error("epoll_wait() error (%d)\n", errno);                                  log_error("epoll_wait() error (%d)\n", errno);
269    #else
270                                    log_error("poll() error (%d)\n", errno);
271    #endif
272                                  break;                                  break;
273                          }                          }
274                          continue;                          continue;
275                  }                  }
276                  else if (nfds == 0) // timeout                  else if (ret == 0) // timeout
277                  {                  {
278                          continue;                          continue;
279                  }                  }
280    
281                  for (int i = 0; i < nfds; i++)                  for (int i = 0; i < nfds; i++)
282                  {                  {
283    #ifdef HAVE_SYS_EPOLL_H
284                          if (events[i].data.fd == STDOUT_FILENO)                          if (events[i].data.fd == STDOUT_FILENO)
285    #else
286                            if (pfds[i].fd == STDOUT_FILENO && (pfds[i].revents & POLLOUT))
287    #endif
288                          {                          {
289                                  while (stdout_buf_offset < stdout_buf_len && !SYS_server_exit) // write until complete or error                                  if (stdout_buf_offset < stdout_buf_len)
290                                    {
291                                            ret = io_buf_conv(stdout_cd, stdout_buf, &stdout_buf_len, &stdout_buf_offset, stdout_conv, sizeof(stdout_conv), &stdout_conv_len);
292                                            if (ret < 0)
293                                            {
294                                                    log_error("io_buf_conv(stdout, %d, %d, %d) error\n", stdout_buf_len, stdout_buf_offset, stdout_conv_len);
295                                                    stdout_buf_len = stdout_buf_offset; // Discard invalid sequence
296                                            }
297                                    }
298    
299                                    while (stdout_conv_offset < stdout_conv_len && !SYS_server_exit) // write until complete or error
300                                  {                                  {
301                                          if (SSH_v2)                                          if (SSH_v2)
302                                          {                                          {
303                                                  ret = ssh_channel_write(SSH_channel, stdout_buf + stdout_buf_offset, (uint32_t)(stdout_buf_len - stdout_buf_offset));                                                  ret = ssh_channel_write(SSH_channel, stdout_conv + stdout_conv_offset, (uint32_t)(stdout_conv_len - stdout_conv_offset));
304                                                  if (ret == SSH_ERROR)                                                  if (ret == SSH_ERROR)
305                                                  {                                                  {
306                                                          log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));                                                          log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));
# Line 162  int iflush() Line 310  int iflush()
310                                          }                                          }
311                                          else                                          else
312                                          {                                          {
313                                                  ret = (int)write(STDOUT_FILENO, stdout_buf + stdout_buf_offset, (size_t)(stdout_buf_len - stdout_buf_offset));                                                  ret = (int)write(STDOUT_FILENO, stdout_conv + stdout_conv_offset, (size_t)(stdout_conv_len - stdout_conv_offset));
314                                          }                                          }
315                                          if (ret < 0)                                          if (ret < 0)
316                                          {                                          {
# Line 176  int iflush() Line 324  int iflush()
324                                                  }                                                  }
325                                                  else                                                  else
326                                                  {                                                  {
327    #ifdef _DEBUG
328                                                          log_error("write(STDOUT) error (%d)\n", errno);                                                          log_error("write(STDOUT) error (%d)\n", errno);
329    #endif
330                                                          retry = 0;                                                          retry = 0;
331                                                          break;                                                          break;
332                                                  }                                                  }
# Line 188  int iflush() Line 338  int iflush()
338                                          }                                          }
339                                          else                                          else
340                                          {                                          {
341                                                  stdout_buf_offset += ret;                                                  stdout_conv_offset += ret;
342                                                  if (stdout_buf_offset >= stdout_buf_len) // flush buffer completely                                                  if (stdout_conv_offset >= stdout_conv_len) // flush buffer completely
343                                                  {                                                  {
344                                                          ret = 0;                                                          ret = 0;
345                                                          stdout_buf_offset = 0;                                                          stdout_conv_offset = 0;
346                                                          stdout_buf_len = 0;                                                          stdout_conv_len = 0;
347                                                          retry = 0;                                                          retry = 0;
348                                                          break;                                                          break;
349                                                  }                                                  }
# Line 204  int iflush() Line 354  int iflush()
354                  }                  }
355          }          }
356    
         // Restore STDOUT flags  
         fcntl(STDOUT_FILENO, F_SETFL, flags);  
   
         if (close(epollfd) < 0)  
         {  
                 log_error("close(epoll) error (%d)\n");  
         }  
   
357          return ret;          return ret;
358  }  }
359    
360  int igetch(int timeout)  int igetch(int timeout)
361  {  {
362          // static input buffer          static int stdin_read_wait = 0;
         static unsigned char buf[LINE_BUFFER_LEN];  
         static int len = 0;  
         static int pos = 0;  
363    
364          struct epoll_event ev, events[MAX_EVENTS];  #ifdef HAVE_SYS_EPOLL_H
365          int nfds, epollfd;          struct epoll_event events[MAX_EVENTS];
366    #else
367            struct pollfd pfds[1];
368    #endif
369    
370            int nfds;
371          int ret;          int ret;
372          int loop;          int loop;
373    
# Line 233  int igetch(int timeout) Line 377  int igetch(int timeout)
377          int in_ascii = 0;          int in_ascii = 0;
378          int in_control = 0;          int in_control = 0;
379          int i = 0;          int i = 0;
         int flags;  
   
         epollfd = epoll_create1(0);  
         if (epollfd < 0)  
         {  
                 log_error("epoll_create1() error (%d)\n", errno);  
                 return -1;  
         }  
380    
381          ev.events = EPOLLIN;          if (stdin_conv_offset >= stdin_conv_len)
         ev.data.fd = STDIN_FILENO;  
         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)  
382          {          {
383                  log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);                  stdin_conv_len = 0;
384                    stdin_conv_offset = 0;
385    
386                  if (close(epollfd) < 0)                  for (loop = 1; loop && stdin_buf_len < sizeof(stdin_buf) && stdin_conv_offset >= stdin_conv_len && !SYS_server_exit;)
387                  {                  {
388                          log_error("close(epoll) error (%d)\n");                          if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
389                  }                          {
390                  return -1;                                  log_error("SSH channel is closed\n");
391          }                                  loop = 0;
392                                    break;
393          flags = fcntl(STDIN_FILENO, F_GETFL, 0);                          }
         fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);  
   
         loop = 1;  
   
         while (loop && pos >= len && !SYS_server_exit)  
         {  
                 len = 0;  
                 pos = 0;  
394    
395                  if (SSH_v2 && ssh_channel_is_closed(SSH_channel))                          if (!stdin_read_wait)
396                  {                          {
397                          log_error("SSH channel is closed\n");  #ifdef HAVE_SYS_EPOLL_H
398                          loop = 0;                                  nfds = epoll_wait(stdin_epollfd, events, MAX_EVENTS, timeout);
399                          break;                                  ret = nfds;
400                  }  #else
401                                    pfds[0].fd = STDIN_FILENO;
402                                    pfds[0].events = POLLIN;
403                                    nfds = 1;
404                                    ret = poll(pfds, (nfds_t)nfds, timeout);
405    #endif
406    
407                  nfds = epoll_wait(epollfd, events, MAX_EVENTS, timeout);                                  if (ret < 0)
408                                    {
409                                            if (errno != EINTR)
410                                            {
411    #ifdef HAVE_SYS_EPOLL_H
412                                                    log_error("epoll_wait() error (%d)\n", errno);
413    #else
414                                                    log_error("poll() error (%d)\n", errno);
415    #endif
416                                                    break;
417                                            }
418                                            continue;
419                                    }
420                                    else if (ret == 0) // timeout
421                                    {
422                                            out = KEY_TIMEOUT;
423                                            break;
424                                    }
425    
426                  if (nfds < 0)                                  for (int i = 0; i < nfds; i++)
427                  {                                  {
428                          if (errno != EINTR)  #ifdef HAVE_SYS_EPOLL_H
429                          {                                          if (events[i].data.fd == STDIN_FILENO)
430                                  log_error("epoll_wait() error (%d)\n", errno);  #else
431                                  break;                                          if (pfds[i].fd == STDIN_FILENO && (pfds[i].revents & POLLIN))
432    #endif
433                                            {
434                                                    stdin_read_wait = 1;
435                                            }
436                                    }
437                          }                          }
                         continue;  
                 }  
                 else if (nfds == 0) // timeout  
                 {  
                         out = KEY_TIMEOUT;  
                         break;  
                 }  
438    
439                  for (int i = 0; i < nfds; i++)                          if (stdin_read_wait)
                 {  
                         if (events[i].data.fd == STDIN_FILENO)  
440                          {                          {
441                                  while (len < sizeof(buf) && !SYS_server_exit) // read until complete or error                                  while (stdin_buf_len < sizeof(stdin_buf) && !SYS_server_exit) // read until complete or error
442                                  {                                  {
443                                          if (SSH_v2)                                          if (SSH_v2)
444                                          {                                          {
445                                                  ret = ssh_channel_read_nonblocking(SSH_channel, buf + len, sizeof(buf) - (uint32_t)len, 0);                                                  ret = ssh_channel_read_nonblocking(SSH_channel, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (uint32_t)stdin_buf_len, 0);
446                                                  if (ret == SSH_ERROR)                                                  if (ret == SSH_ERROR)
447                                                  {                                                  {
448                                                          log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));                                                          log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));
# Line 306  int igetch(int timeout) Line 451  int igetch(int timeout)
451                                                  }                                                  }
452                                                  else if (ret == SSH_EOF)                                                  else if (ret == SSH_EOF)
453                                                  {                                                  {
454                                                            stdin_read_wait = 0;
455                                                          loop = 0;                                                          loop = 0;
456                                                          break;                                                          break;
457                                                  }                                                  }
458                                                  else if (ret == 0)                                                  else if (ret == 0)
459                                                  {                                                  {
460                                                          out = 0;                                                          out = 0;
461                                                          break; // Check whether channel is still open                                                          stdin_read_wait = 0;
462                                                            loop = 0;
463                                                            break;
464                                                  }                                                  }
465                                          }                                          }
466                                          else                                          else
467                                          {                                          {
468                                                  ret = (int)read(STDIN_FILENO, buf + len, sizeof(buf) - (size_t)len);                                                  ret = (int)read(STDIN_FILENO, stdin_buf + stdin_buf_len, sizeof(stdin_buf) - (size_t)stdin_buf_len);
469                                          }                                          }
470                                          if (ret < 0)                                          if (ret < 0)
471                                          {                                          {
472                                                  if (errno == EAGAIN || errno == EWOULDBLOCK)                                                  if (errno == EAGAIN || errno == EWOULDBLOCK)
473                                                  {                                                  {
474                                                          out = 0;                                                          out = 0;
475                                                            stdin_read_wait = 0;
476                                                          loop = 0;                                                          loop = 0;
477                                                          break;                                                          break;
478                                                  }                                                  }
# Line 333  int igetch(int timeout) Line 482  int igetch(int timeout)
482                                                  }                                                  }
483                                                  else                                                  else
484                                                  {                                                  {
485    #ifdef _DEBUG
486                                                          log_error("read(STDIN) error (%d)\n", errno);                                                          log_error("read(STDIN) error (%d)\n", errno);
487    #endif
488                                                          loop = 0;                                                          loop = 0;
489                                                          break;                                                          break;
490                                                  }                                                  }
491                                          }                                          }
492                                          else if (ret == 0) // broken pipe                                          else if (ret == 0) // broken pipe
493                                          {                                          {
494                                                    stdin_read_wait = 0;
495                                                  loop = 0;                                                  loop = 0;
496                                                  break;                                                  break;
497                                          }                                          }
498                                          else                                          else
499                                          {                                          {
500                                                  len += ret;                                                  stdin_buf_len += ret;
501                                                  continue;                                                  continue;
502                                          }                                          }
503                                  }                                  }
504                          }                          }
505    
506                            // For debug
507    #ifdef _DEBUG
508                            for (int j = stdin_buf_offset; j < stdin_buf_len; j++)
509                            {
510                                    log_error("Debug input: <--[%u]\n", (stdin_buf[j] + 256) % 256);
511                            }
512    #endif
513                  }                  }
514    
515                  // For debug                  if (stdin_buf_offset < stdin_buf_len)
516                  // for (int j = pos; j < len; j++)                  {
517                  // {                          ret = io_buf_conv(stdin_cd, stdin_buf, &stdin_buf_len, &stdin_buf_offset, stdin_conv, sizeof(stdin_conv), &stdin_conv_len);
518                  //      log_common("Debug: <--[%u]\n", (buf[j] + 256) % 256);                          if (ret < 0)
519                  // }                          {
520          }                                  log_error("io_buf_conv(stdin, %d, %d, %d) error\n", stdin_buf_len, stdin_buf_offset, stdin_conv_len);
521                                    stdin_buf_len = stdin_buf_offset; // Discard invalid sequence
522                            }
523    
524          fcntl(STDIN_FILENO, F_SETFL, flags);                          // For debug
525    #ifdef _DEBUG
526                            for (int j = stdin_conv_offset; j < stdin_conv_len; j++)
527                            {
528                                    log_error("Debug input_conv: <--[%u]\n", (stdin_conv[j] + 256) % 256);
529                            }
530    #endif
531                    }
532            }
533    
534          while (pos < len)          while (stdin_conv_offset < stdin_conv_len)
535          {          {
536                  unsigned char c = buf[pos++];                  unsigned char c = (unsigned char)stdin_conv[stdin_conv_offset++];
537    
538                    // Convert \r\n to \r
539                    if (c == CR && stdin_conv_offset < stdin_conv_len && stdin_conv[stdin_conv_offset] == LF)
540                    {
541                            stdin_conv_offset++;
542                    }
543    
544                    // Convert single \n to \r
545                    if (c == LF)
546                    {
547                            c = CR;
548                    }
549    
550                  if (c == KEY_CONTROL)                  if (c == KEY_CONTROL)
551                  {                  {
# Line 534  int igetch(int timeout) Line 716  int igetch(int timeout)
716                                  case 49:                                  case 49:
717                                          out = KEY_HOME;                                          out = KEY_HOME;
718                                          break;                                          break;
719                                    case 50:
720                                            out = KEY_INS;
721                                            break;
722                                  case 51:                                  case 51:
723                                          out = KEY_DEL;                                          out = KEY_DEL;
724                                          break;                                          break;
# Line 796  int igetch(int timeout) Line 981  int igetch(int timeout)
981                  break;                  break;
982          }          }
983    
         if (close(epollfd) < 0)  
         {  
                 log_error("close(epoll) error (%d)\n");  
         }  
   
984          // For ESC key          // For ESC key
985          if (out == 0 && in_esc)          if (out == 0 && in_esc)
986          {          {
# Line 808  int igetch(int timeout) Line 988  int igetch(int timeout)
988          }          }
989    
990          // for debug          // for debug
991          // if (out != KEY_TIMEOUT && out != KEY_NULL)  #ifdef _DEBUG
992          // {          if (out != KEY_TIMEOUT && out != KEY_NULL)
993          //      log_common("Debug: -->[0x %x]\n", out);          {
994          // }                  log_error("Debug: -->[0x %x]\n", out);
995            }
996    #endif
997    
998          return out;          return out;
999  }  }
# Line 819  int igetch(int timeout) Line 1001  int igetch(int timeout)
1001  int igetch_t(int sec)  int igetch_t(int sec)
1002  {  {
1003          int ch;          int ch;
1004          time_t t_begin = time(0);          time_t t_begin = time(NULL);
1005    
1006          do          do
1007          {          {
1008                  ch = igetch(100);                  ch = igetch(100);
1009          } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(0) - t_begin < sec));          } while (!SYS_server_exit && ch == KEY_TIMEOUT && (time(NULL) - t_begin < sec));
1010    
1011          return ch;          return ch;
1012  }  }
# Line 834  void igetch_reset() Line 1016  void igetch_reset()
1016          int ch;          int ch;
1017          do          do
1018          {          {
1019                  ch = igetch(0);                  ch = igetch(100);
1020          } while (ch != KEY_NULL && ch != KEY_TIMEOUT);          } while (ch != KEY_NULL && ch != KEY_TIMEOUT);
1021  }  }
1022    
1023    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)
1024    {
1025            char *in_buf;
1026            char *out_buf;
1027            size_t in_bytes;
1028            size_t out_bytes;
1029            int ret;
1030            int in_control = 0;
1031            size_t i = 0;
1032    
1033            if (cd == NULL || p_buf == NULL || p_buf_len == NULL || p_buf_offset == NULL || p_conv == NULL || p_conv_len == NULL)
1034            {
1035                    log_error("NULL pointer error\n");
1036                    return -1;
1037            }
1038    
1039            in_buf = p_buf + *p_buf_offset;
1040            in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
1041            out_buf = p_conv + *p_conv_len;
1042            out_bytes = conv_size - (size_t)(*p_conv_len);
1043    
1044            while (in_bytes > 0)
1045            {
1046                    if ((unsigned char)(*in_buf) == KEY_CONTROL)
1047                    {
1048                            if (in_control == 0)
1049                            {
1050                                    in_control = 1;
1051                                    i = 0;
1052                            }
1053                    }
1054    
1055                    if (in_control)
1056                    {
1057                            if (out_bytes <= 0)
1058                            {
1059                                    log_error("No enough free space in p_conv, conv_len=%d, conv_size=%d\n", *p_conv_len, conv_size);
1060                                    return -2;
1061                            }
1062    
1063                            *out_buf = *in_buf;
1064                            in_buf++;
1065                            out_buf++;
1066                            in_bytes--;
1067                            out_bytes--;
1068    
1069                            (*p_buf_offset)++;
1070                            *p_conv_len = (int)(conv_size - out_bytes);
1071    
1072                            i++;
1073                            if (i >= 2)
1074                            {
1075                                    in_control = 0;
1076                            }
1077                            continue;
1078                    }
1079    
1080                    ret = (int)iconv(cd, &in_buf, &in_bytes, &out_buf, &out_bytes);
1081                    if (ret == -1)
1082                    {
1083                            if (errno == EINVAL) // Incomplete
1084                            {
1085    #ifdef _DEBUG
1086                                    log_error("iconv(inbytes=%d, outbytes=%d) error: EINVAL, in_buf[0]=%d\n", in_bytes, out_bytes, in_buf[0]);
1087    #endif
1088                                    if (p_buf != in_buf)
1089                                    {
1090                                            *p_buf_len = (int)(p_buf + *p_buf_len - in_buf);
1091                                            *p_buf_offset = 0;
1092                                            *p_conv_len = (int)(conv_size - out_bytes);
1093                                            memmove(p_buf, in_buf, (size_t)(*p_buf_len));
1094                                    }
1095    
1096                                    break;
1097                            }
1098                            else if (errno == E2BIG)
1099                            {
1100                                    log_error("iconv(inbytes=%d, outbytes=%d) error: E2BIG\n", in_bytes, out_bytes);
1101                                    return -1;
1102                            }
1103                            else if (errno == EILSEQ)
1104                            {
1105                                    if (in_bytes > out_bytes || out_bytes <= 0)
1106                                    {
1107                                            log_error("iconv(inbytes=%d, outbytes=%d) error: EILSEQ and E2BIG\n", in_bytes, out_bytes);
1108                                            return -2;
1109                                    }
1110    
1111                                    // reset in_bytes when "//IGNORE" is applied
1112                                    if (in_bytes == 0)
1113                                    {
1114                                            in_bytes = (size_t)(*p_buf_len - *p_buf_offset);
1115                                    }
1116    
1117                                    *out_buf = *in_buf;
1118                                    in_buf++;
1119                                    out_buf++;
1120                                    in_bytes--;
1121                                    out_bytes--;
1122    
1123                                    continue;
1124                            }
1125                    }
1126                    else
1127                    {
1128                            *p_buf_len = 0;
1129                            *p_buf_offset = 0;
1130                            *p_conv_len = (int)(conv_size - out_bytes);
1131    
1132                            break;
1133                    }
1134            }
1135    
1136            return 0;
1137    }
1138    
1139    int io_conv_init(const char *charset)
1140    {
1141            char tocode[CHARSET_MAX_LEN + 20];
1142    
1143            if (charset == NULL)
1144            {
1145                    log_error("NULL pointer error\n");
1146                    return -1;
1147            }
1148    
1149            io_conv_cleanup();
1150    
1151            strncpy(stdio_charset, charset, sizeof(stdio_charset) - 1);
1152            stdio_charset[sizeof(stdio_charset) - 1] = '\0';
1153    
1154            snprintf(tocode, sizeof(tocode), "%s%s", BBS_default_charset,
1155                             (strcasecmp(stdio_charset, BBS_default_charset) == 0 ? "" : "//IGNORE"));
1156            stdin_cd = iconv_open(tocode, stdio_charset);
1157            if (stdin_cd == (iconv_t)(-1))
1158            {
1159                    log_error("iconv_open(%s->%s) error: %d\n", stdio_charset, tocode, errno);
1160                    return -2;
1161            }
1162    
1163            snprintf(tocode, sizeof(tocode), "%s%s", stdio_charset,
1164                             (strcasecmp(BBS_default_charset, stdio_charset) == 0 ? "" : "//TRANSLIT"));
1165            stdout_cd = iconv_open(tocode, BBS_default_charset);
1166            if (stdout_cd == (iconv_t)(-1))
1167            {
1168                    log_error("iconv_open(%s->%s) error: %d\n", BBS_default_charset, tocode, errno);
1169                    iconv_close(stdin_cd);
1170                    return -2;
1171            }
1172    
1173            return 0;
1174    }
1175    
1176    int io_conv_cleanup(void)
1177    {
1178            if (stdin_cd != NULL)
1179            {
1180                    iconv_close(stdin_cd);
1181                    stdin_cd = NULL;
1182            }
1183            if (stdout_cd != NULL)
1184            {
1185                    iconv_close(stdout_cd);
1186                    stdout_cd = NULL;
1187            }
1188    
1189            return 0;
1190    }


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

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