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

Contents of /lbbs/src/bbs_net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.66 - (show annotations)
Sat Oct 18 01:50:48 2025 UTC (4 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.65: +4 -70 lines
Content type: text/x-csrc
Move io_buf_conv() to io.c(.h)

1 /***************************************************************************
2 bbs_net.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "bbs.h"
18 #include "common.h"
19 #include "io.h"
20 #include "log.h"
21 #include "login.h"
22 #include "menu.h"
23 #include "screen.h"
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <netdb.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <arpa/inet.h>
34 #include <libssh/libssh.h>
35 #include <libssh/server.h>
36 #include <libssh/callbacks.h>
37 #include <netinet/in.h>
38 #include <netinet/ip.h>
39 #include <sys/select.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/epoll.h>
43
44 #define MENU_CONF_DELIM " \t\r\n"
45
46 #define MAX_PROCESS_BAR_LEN 30
47 #define MAXSTATION 26 * 2
48 #define STATION_PER_LINE 4
49
50 #define BBS_NET_DEFAULT_CHARSET "UTF-8"
51
52 struct _bbsnet_conf
53 {
54 char host1[20];
55 char host2[40];
56 char ip[40];
57 in_port_t port;
58 char charset[20];
59 } bbsnet_conf[MAXSTATION];
60
61 MENU_SET bbsnet_menu;
62
63 int load_bbsnet_conf(const char *file_config)
64 {
65 FILE *fp;
66 MENU *p_menu;
67 MENU_ITEM *p_menu_item;
68 MENU_ITEM_ID menu_item_id;
69 char t[256], *t1, *t2, *t3, *t4, *t5, *saveptr;
70
71 fp = fopen(file_config, "r");
72 if (fp == NULL)
73 {
74 return -1;
75 }
76
77 bbsnet_menu.p_menu_pool = calloc(1, sizeof(MENU));
78 if (bbsnet_menu.p_menu_pool == NULL)
79 {
80 log_error("calloc(p_menu_pool) error\n");
81 return -3;
82 }
83 bbsnet_menu.menu_count = 1;
84
85 bbsnet_menu.p_menu_item_pool = calloc(MAXSTATION, sizeof(MENU_ITEM));
86 if (bbsnet_menu.p_menu_item_pool == NULL)
87 {
88 log_error("calloc(p_menu_item_pool) error\n");
89 return -3;
90 }
91 bbsnet_menu.menu_item_count = MAXSTATION;
92
93 p_menu = (MENU *)get_menu_by_id(&bbsnet_menu, 0);
94
95 strncpy(p_menu->name, "BBSNET", sizeof(p_menu->name) - 1);
96 p_menu->name[sizeof(p_menu->name) - 1] = '\0';
97 p_menu->title.show = 0;
98 p_menu->screen_show = 0;
99
100 menu_item_id = 0;
101 while (fgets(t, 255, fp) && menu_item_id < MAXSTATION)
102 {
103 t1 = strtok_r(t, MENU_CONF_DELIM, &saveptr);
104 t2 = strtok_r(NULL, MENU_CONF_DELIM, &saveptr);
105 t3 = strtok_r(NULL, MENU_CONF_DELIM, &saveptr);
106 t4 = strtok_r(NULL, MENU_CONF_DELIM, &saveptr);
107 t5 = strtok_r(NULL, MENU_CONF_DELIM, &saveptr);
108
109 if (t1 == NULL || t2 == NULL || t3 == NULL || t4 == NULL || t5 == NULL || t[0] == '#' || t[0] == '*')
110 {
111 continue;
112 }
113
114 strncpy(bbsnet_conf[menu_item_id].host1, t2, sizeof(bbsnet_conf[menu_item_id].host1) - 1);
115 bbsnet_conf[menu_item_id].host1[sizeof(bbsnet_conf[menu_item_id].host1) - 1] = '\0';
116 strncpy(bbsnet_conf[menu_item_id].host2, t1, sizeof(bbsnet_conf[menu_item_id].host2) - 1);
117 bbsnet_conf[menu_item_id].host2[sizeof(bbsnet_conf[menu_item_id].host2) - 1] = '\0';
118 strncpy(bbsnet_conf[menu_item_id].ip, t3, sizeof(bbsnet_conf[menu_item_id].ip) - 1);
119 bbsnet_conf[menu_item_id].ip[sizeof(bbsnet_conf[menu_item_id].ip) - 1] = '\0';
120 bbsnet_conf[menu_item_id].port = (in_port_t)(t4 ? atoi(t4) : 23);
121 strncpy(bbsnet_conf[menu_item_id].charset, t5, sizeof(bbsnet_conf[menu_item_id].charset) - 1);
122 bbsnet_conf[menu_item_id].charset[sizeof(bbsnet_conf[menu_item_id].charset) - 1] = '\0';
123
124 p_menu_item = get_menu_item_by_id(&bbsnet_menu, menu_item_id);
125 if (p_menu_item == NULL)
126 {
127 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
128 return -1;
129 }
130
131 p_menu_item->row = (int16_t)(2 + menu_item_id / STATION_PER_LINE);
132 p_menu_item->col = (int16_t)(5 + menu_item_id % STATION_PER_LINE * 20);
133 snprintf(p_menu_item->action, sizeof(p_menu_item->action), "%d", (int16_t)menu_item_id);
134 p_menu_item->submenu = 0;
135 p_menu_item->priv = 0;
136 p_menu_item->level = 0;
137 p_menu_item->name[0] =
138 (char)(menu_item_id < MAXSTATION / 2 ? 'A' + menu_item_id : 'a' + menu_item_id);
139 p_menu_item->name[1] = '\0';
140 snprintf(p_menu_item->text, sizeof(p_menu_item->text), "%c. %s",
141 p_menu_item->name[0], bbsnet_conf[menu_item_id].host1);
142
143 p_menu->items[p_menu->item_count] = menu_item_id;
144 p_menu->item_count++;
145 menu_item_id++;
146 }
147
148 bbsnet_menu.menu_item_count = (int16_t)menu_item_id;
149 bbsnet_menu.menu_id_path[0] = 0;
150 bbsnet_menu.menu_item_pos[0] = 0;
151 bbsnet_menu.choose_step = 0;
152
153 fclose(fp);
154
155 return 0;
156 }
157
158 void unload_bbsnet_conf(void)
159 {
160 bbsnet_menu.menu_count = 0;
161 bbsnet_menu.menu_item_count = 0;
162
163 free(bbsnet_menu.p_menu_pool);
164 bbsnet_menu.p_menu_pool = NULL;
165 free(bbsnet_menu.p_menu_item_pool);
166 bbsnet_menu.p_menu_item_pool = NULL;
167 }
168
169 void process_bar(int n, int len)
170 {
171 char buf[LINE_BUFFER_LEN];
172 char buf2[LINE_BUFFER_LEN];
173
174 if (len > LINE_BUFFER_LEN)
175 {
176 len = LINE_BUFFER_LEN - 1;
177 }
178 if (n < 0)
179 {
180 n = 0;
181 }
182 else if (n > len)
183 {
184 n = len;
185 }
186
187 moveto(4, 0);
188 prints(" ------------------------------ \r\n");
189 snprintf(buf, sizeof(buf), " %3d%% ", n * 100 / len);
190 strncpy(buf2, buf, (size_t)n);
191 buf2[n] = '\0';
192 prints("|\033[46m%s\033[44m%s\033[m|\r\n", buf2, buf + n);
193 prints(" ------------------------------ \r\n");
194 iflush();
195 }
196
197 int bbsnet_connect(int n)
198 {
199 int sock, ret, loop, error;
200 int sock_connected = 0;
201 int flags_sock;
202 int flags_stdin;
203 int flags_stdout;
204 int len;
205 struct sockaddr_in sin;
206 char input_buf[LINE_BUFFER_LEN];
207 char output_buf[LINE_BUFFER_LEN];
208 int input_buf_len = 0;
209 int output_buf_len = 0;
210 int input_buf_offset = 0;
211 int output_buf_offset = 0;
212 iconv_t input_cd = NULL;
213 char input_conv[LINE_BUFFER_LEN * 2];
214 char output_conv[LINE_BUFFER_LEN * 2];
215 int input_conv_len = 0;
216 int output_conv_len = 0;
217 int input_conv_offset = 0;
218 int output_conv_offset = 0;
219 iconv_t output_cd = NULL;
220 struct epoll_event ev, events[MAX_EVENTS];
221 int nfds, epollfd;
222 int stdin_read_wait = 0;
223 int stdout_write_wait = 0;
224 int sock_read_wait = 0;
225 int sock_write_wait = 0;
226 struct hostent *p_host = NULL;
227 int tos;
228 char remote_addr[IP_ADDR_LEN];
229 int remote_port;
230 char local_addr[IP_ADDR_LEN];
231 int local_port;
232 socklen_t sock_len;
233 time_t t_used = time(NULL);
234 struct tm *tm_used;
235 int ch;
236
237 if (user_online_update("BBS_NET") < 0)
238 {
239 log_error("user_online_update(BBS_NET) error\n");
240 }
241
242 clearscr();
243
244 moveto(0, 0);
245 prints("\033[1;32m正在测试往 %s (%s) 的连接,请稍候... \033[m\r\n",
246 bbsnet_conf[n].host1, bbsnet_conf[n].ip);
247 iflush();
248
249 p_host = gethostbyname(bbsnet_conf[n].ip);
250
251 if (p_host == NULL)
252 {
253 prints("\033[1;31m查找主机名失败!\033[m\r\n");
254 press_any_key();
255 return -1;
256 }
257
258 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
259
260 if (sock < 0)
261 {
262 prints("\033[1;31m无法创建socket!\033[m\r\n");
263 press_any_key();
264 return -1;
265 }
266
267 sin.sin_family = AF_INET;
268 sin.sin_addr.s_addr = (BBS_address[0] != '\0' ? inet_addr(BBS_address) : INADDR_ANY);
269 sin.sin_port = 0;
270
271 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
272 {
273 log_error("Bind address %s:%u failed (%d)\n",
274 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), errno);
275 return -2;
276 }
277
278 memset(&sin, 0, sizeof(sin));
279 sin.sin_family = AF_INET;
280 sin.sin_addr = *(struct in_addr *)p_host->h_addr_list[0];
281 sin.sin_port = htons(bbsnet_conf[n].port);
282
283 strncpy(remote_addr, inet_ntoa(sin.sin_addr), sizeof(remote_addr) - 1);
284 remote_addr[sizeof(remote_addr) - 1] = '\0';
285 remote_port = ntohs(sin.sin_port);
286
287 prints("\033[1;32m穿梭进度条提示您当前已使用的时间,按\033[1;33mCtrl+C\033[1;32m中断。\033[m\r\n");
288 process_bar(0, MAX_PROCESS_BAR_LEN);
289
290 // Set socket as non-blocking
291 flags_sock = fcntl(sock, F_GETFL, 0);
292 fcntl(sock, F_SETFL, flags_sock | O_NONBLOCK);
293
294 // Set STDIN/STDOUT as non-blocking
295 flags_stdin = fcntl(STDIN_FILENO, F_GETFL, 0);
296 flags_stdout = fcntl(STDOUT_FILENO, F_GETFL, 0);
297 fcntl(STDIN_FILENO, F_SETFL, flags_stdin | O_NONBLOCK);
298 fcntl(STDOUT_FILENO, F_SETFL, flags_stdout | O_NONBLOCK);
299
300 epollfd = epoll_create1(0);
301 if (epollfd < 0)
302 {
303 log_error("epoll_create1() error (%d)\n", errno);
304 return -1;
305 }
306
307 ev.events = EPOLLOUT | EPOLLET;
308 ev.data.fd = sock;
309 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ev) == -1)
310 {
311 log_error("epoll_ctl(socket) error (%d)\n", errno);
312 goto cleanup;
313 }
314
315 ev.events = EPOLLIN | EPOLLET;
316 ev.data.fd = STDIN_FILENO;
317 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1)
318 {
319 log_error("epoll_ctl(STDIN_FILENO) error (%d)\n", errno);
320 goto cleanup;
321 }
322
323 while (!SYS_server_exit)
324 {
325 if ((ret = connect(sock, (struct sockaddr *)&sin, sizeof(sin))) < 0)
326 {
327 if (errno == EAGAIN || errno == EALREADY || errno == EINPROGRESS)
328 {
329 // Use select / epoll to check writability of the socket,
330 // then use getsockopt to check the status of the socket.
331 // See man connect(2)
332 break;
333 }
334 else if (errno == EINTR)
335 {
336 continue;
337 }
338 else
339 {
340 log_error("connect(socket) error (%d)\n", errno);
341
342 prints("\033[1;31m连接失败!\033[m\r\n");
343 press_any_key();
344
345 goto cleanup;
346 }
347 }
348 }
349
350 for (int j = 0; j < MAX_PROCESS_BAR_LEN && !sock_connected && !SYS_server_exit; j++)
351 {
352 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 500); // 0.5 second
353
354 if (nfds < 0)
355 {
356 if (errno != EINTR)
357 {
358 log_error("epoll_wait() error (%d)\n", errno);
359 break;
360 }
361 }
362 else if (nfds == 0) // timeout
363 {
364 process_bar(j + 1, MAX_PROCESS_BAR_LEN);
365 }
366 else // ret > 0
367 {
368 for (int i = 0; i < nfds; i++)
369 {
370 if (events[i].data.fd == sock)
371 {
372 len = sizeof(error);
373 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) < 0)
374 {
375 log_error("getsockopt() error (%d) !\n", error);
376 goto cleanup;
377 }
378 if (error == 0)
379 {
380 sock_connected = 1;
381 }
382 }
383 else if (events[i].data.fd == STDIN_FILENO)
384 {
385 ch = igetch(0);
386 if (ch == Ctrl('C') || ch == KEY_ESC)
387 {
388 goto cleanup;
389 }
390 }
391 }
392 }
393 }
394 if (SYS_server_exit)
395 {
396 goto cleanup;
397 }
398 if (!sock_connected)
399 {
400 prints("\033[1;31m连接失败!\033[m\r\n");
401 press_any_key();
402
403 goto cleanup;
404 }
405
406 tos = IPTOS_LOWDELAY;
407 if (setsockopt(sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
408 {
409 log_error("setsockopt IP_TOS=%d error (%d)\n", tos, errno);
410 }
411
412 sock_len = sizeof(sin);
413 if (getsockname(sock, (struct sockaddr *)&sin, &sock_len) < 0)
414 {
415 log_error("getsockname() error: %d", errno);
416 goto cleanup;
417 }
418
419 strncpy(local_addr, inet_ntoa(sin.sin_addr), sizeof(local_addr) - 1);
420 local_addr[sizeof(local_addr) - 1] = '\0';
421 local_port = ntohs(sin.sin_port);
422
423 prints("\033[1;31m连接成功!\033[m\r\n");
424 iflush();
425 log_common("BBSNET connect to %s:%d from %s:%d by [%s]\n",
426 remote_addr, remote_port, local_addr, local_port, BBS_username);
427
428 input_cd = iconv_open(bbsnet_conf[n].charset, BBS_NET_DEFAULT_CHARSET);
429 if (input_cd == (iconv_t)(-1))
430 {
431 log_error("iconv_open(%s->%s) error: %d\n", BBS_NET_DEFAULT_CHARSET, bbsnet_conf[n].charset, errno);
432 goto cleanup;
433 }
434 output_cd = iconv_open(BBS_NET_DEFAULT_CHARSET, bbsnet_conf[n].charset);
435 if (input_cd == (iconv_t)(-1))
436 {
437 log_error("iconv_open(%s->%s) error: %d\n", bbsnet_conf[n].charset, BBS_NET_DEFAULT_CHARSET, errno);
438 iconv_close(input_cd);
439 goto cleanup;
440 }
441
442 ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
443 ev.data.fd = sock;
444 if (epoll_ctl(epollfd, EPOLL_CTL_MOD, sock, &ev) == -1)
445 {
446 log_error("epoll_ctl(socket) error (%d)\n", errno);
447 goto cleanup;
448 }
449
450 ev.events = EPOLLOUT | EPOLLET;
451 ev.data.fd = STDOUT_FILENO;
452 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev) == -1)
453 {
454 log_error("epoll_ctl(STDOUT_FILENO) error (%d)\n", errno);
455 goto cleanup;
456 }
457
458 BBS_last_access_tm = t_used = time(NULL);
459 loop = 1;
460
461 while (loop && !SYS_server_exit)
462 {
463 if (SSH_v2 && ssh_channel_is_closed(SSH_channel))
464 {
465 log_error("SSH channel is closed\n");
466 loop = 0;
467 break;
468 }
469
470 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); // 0.1 second
471
472 if (nfds < 0)
473 {
474 if (errno != EINTR)
475 {
476 log_error("epoll_wait() error (%d)\n", errno);
477 break;
478 }
479 continue;
480 }
481 else if (nfds == 0) // timeout
482 {
483 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
484 {
485 break;
486 }
487 }
488
489 for (int i = 0; i < nfds; i++)
490 {
491 if (events[i].data.fd == STDIN_FILENO)
492 {
493 stdin_read_wait = 1;
494 }
495
496 if (events[i].data.fd == sock)
497 {
498 if (events[i].events & EPOLLIN)
499 {
500 sock_read_wait = 1;
501 }
502 if (events[i].events & EPOLLOUT)
503 {
504 sock_write_wait = 1;
505 }
506 }
507
508 if (events[i].data.fd == STDOUT_FILENO)
509 {
510 stdout_write_wait = 1;
511 }
512 }
513
514 if (stdin_read_wait)
515 {
516 while (input_buf_len < sizeof(input_buf) && !SYS_server_exit)
517 {
518 if (SSH_v2)
519 {
520 ret = ssh_channel_read_nonblocking(SSH_channel, input_buf + input_buf_len, sizeof(input_buf) - (uint32_t)input_buf_len, 0);
521 if (ret == SSH_ERROR)
522 {
523 log_error("ssh_channel_read_nonblocking() error: %s\n", ssh_get_error(SSH_session));
524 loop = 0;
525 break;
526 }
527 else if (ret == SSH_EOF)
528 {
529 stdin_read_wait = 0;
530 loop = 0;
531 break;
532 }
533 else if (ret == 0)
534 {
535 stdin_read_wait = 0;
536 break; // Check whether channel is still open
537 }
538 }
539 else
540 {
541 ret = (int)read(STDIN_FILENO, input_buf + input_buf_len, sizeof(input_buf) - (size_t)input_buf_len);
542 }
543 if (ret < 0)
544 {
545 if (errno == EAGAIN || errno == EWOULDBLOCK)
546 {
547 stdin_read_wait = 0;
548 break;
549 }
550 else if (errno == EINTR)
551 {
552 continue;
553 }
554 else
555 {
556 log_error("read(STDIN) error (%d)\n", errno);
557 loop = 0;
558 break;
559 }
560 }
561 else if (ret == 0) // broken pipe
562 {
563 #ifdef _DEBUG
564 log_error("read(STDIN) EOF\n");
565 #endif
566 stdin_read_wait = 0;
567 loop = 0;
568 break;
569 }
570 else
571 {
572 input_buf_len += ret;
573 BBS_last_access_tm = time(NULL);
574
575 // Refresh current action while user input
576 if (user_online_update("BBS_NET") < 0)
577 {
578 log_error("user_online_update(BBS_NET) error\n");
579 }
580
581 continue;
582 }
583 }
584 }
585
586 if (sock_write_wait)
587 {
588 if (input_buf_offset < input_buf_len)
589 {
590 ret = io_buf_conv(input_cd, input_buf, &input_buf_len, &input_buf_offset, input_conv, sizeof(input_conv), &input_conv_len);
591 if (ret < 0)
592 {
593 log_error("io_buf_conv(input, %d, %d, %d) error\n", input_buf_len, input_buf_offset, input_conv_len);
594 }
595 }
596
597 while (input_conv_offset < input_conv_len && !SYS_server_exit)
598 {
599 ret = (int)write(sock, input_conv + input_conv_offset, (size_t)(input_conv_len - input_conv_offset));
600 if (ret < 0)
601 {
602 if (errno == EAGAIN || errno == EWOULDBLOCK)
603 {
604 sock_write_wait = 0;
605 break;
606 }
607 else if (errno == EINTR)
608 {
609 continue;
610 }
611 else
612 {
613 log_error("write(socket) error (%d)\n", errno);
614 loop = 0;
615 break;
616 }
617 }
618 else if (ret == 0) // broken pipe
619 {
620 #ifdef _DEBUG
621 log_error("write(socket) EOF\n");
622 #endif
623 sock_write_wait = 0;
624 loop = 0;
625 break;
626 }
627 else
628 {
629 input_conv_offset += ret;
630 if (input_conv_offset >= input_conv_len) // Output buffer complete
631 {
632 input_conv_offset = 0;
633 input_conv_len = 0;
634 break;
635 }
636 continue;
637 }
638 }
639 }
640
641 if (sock_read_wait)
642 {
643 while (output_buf_len < sizeof(output_buf) && !SYS_server_exit)
644 {
645 ret = (int)read(sock, output_buf + output_buf_len, sizeof(output_buf) - (size_t)output_buf_len);
646 if (ret < 0)
647 {
648 if (errno == EAGAIN || errno == EWOULDBLOCK)
649 {
650 sock_read_wait = 0;
651 break;
652 }
653 else if (errno == EINTR)
654 {
655 continue;
656 }
657 else
658 {
659 log_error("read(socket) error (%d)\n", errno);
660 loop = 0;
661 break;
662 }
663 }
664 else if (ret == 0) // broken pipe
665 {
666 #ifdef _DEBUG
667 log_error("read(socket) EOF\n");
668 #endif
669 sock_read_wait = 0;
670 loop = 0;
671 break;
672 }
673 else
674 {
675 output_buf_len += ret;
676 continue;
677 }
678 }
679 }
680
681 if (stdout_write_wait)
682 {
683 if (output_buf_offset < output_buf_len)
684 {
685 ret = io_buf_conv(output_cd, output_buf, &output_buf_len, &output_buf_offset, output_conv, sizeof(output_conv), &output_conv_len);
686 if (ret < 0)
687 {
688 log_error("io_buf_conv(output, %d, %d, %d) error\n", output_buf_len, output_buf_offset, output_conv_len);
689 }
690 }
691
692 while (output_conv_offset < output_conv_len && !SYS_server_exit)
693 {
694 if (SSH_v2)
695 {
696 ret = ssh_channel_write(SSH_channel, output_conv + output_conv_offset, (uint32_t)(output_conv_len - output_conv_offset));
697 if (ret == SSH_ERROR)
698 {
699 log_error("ssh_channel_write() error: %s\n", ssh_get_error(SSH_session));
700 loop = 0;
701 break;
702 }
703 }
704 else
705 {
706 ret = (int)write(STDOUT_FILENO, output_conv + output_conv_offset, (size_t)(output_conv_len - output_conv_offset));
707 }
708 if (ret < 0)
709 {
710 if (errno == EAGAIN || errno == EWOULDBLOCK)
711 {
712 stdout_write_wait = 0;
713 break;
714 }
715 else if (errno == EINTR)
716 {
717 continue;
718 }
719 else
720 {
721 log_error("write(STDOUT) error (%d)\n", errno);
722 loop = 0;
723 break;
724 }
725 }
726 else if (ret == 0) // broken pipe
727 {
728 #ifdef _DEBUG
729 log_error("write(STDOUT) EOF\n");
730 #endif
731 stdout_write_wait = 0;
732 loop = 0;
733 break;
734 }
735 else
736 {
737 output_conv_offset += ret;
738 if (output_conv_offset >= output_conv_len) // Output buffer complete
739 {
740 output_conv_offset = 0;
741 output_conv_len = 0;
742 break;
743 }
744 continue;
745 }
746 }
747 }
748 }
749
750 iconv_close(input_cd);
751 iconv_close(output_cd);
752
753 cleanup:
754 if (close(epollfd) < 0)
755 {
756 log_error("close(epoll) error (%d)\n");
757 }
758
759 // Restore STDIN/STDOUT flags
760 fcntl(STDIN_FILENO, F_SETFL, flags_stdin);
761 fcntl(STDOUT_FILENO, F_SETFL, flags_stdout);
762
763 // Restore socket flags
764 fcntl(sock, F_SETFL, flags_sock);
765
766 if (close(sock) == -1)
767 {
768 log_error("Close socket failed\n");
769 }
770
771 t_used = time(NULL) - t_used;
772 tm_used = gmtime(&t_used);
773
774 log_common("BBSNET disconnect, %d days %d hours %d minutes %d seconds used\n",
775 tm_used->tm_mday - 1, tm_used->tm_hour, tm_used->tm_min,
776 tm_used->tm_sec);
777
778 return 0;
779 }
780
781 static int
782 bbsnet_refresh()
783 {
784 clearscr();
785 moveto(1, 0);
786 prints(" ----------------------------------------------------------------------------- ");
787 for (int i = 2; i < 19; i++)
788 {
789 moveto(i, 0);
790 prints("|");
791 moveto(i, 79);
792 prints("|");
793 }
794 moveto(19, 0);
795 prints("|-----------------------------------------------------------------------------|");
796 moveto(22, 0);
797 prints(" ----------------------------------------------------------------------------- ");
798 moveto(23, 0);
799 prints(" [\x1b[1;32mCtrl+C\x1b[m]退出");
800
801 iflush();
802
803 return 0;
804 }
805
806 int bbsnet_selchange()
807 {
808 int i = bbsnet_menu.menu_item_pos[0];
809
810 moveto(20, 0);
811 clrtoeol();
812 prints("|\x1b[1m单位:\x1b[1;33m%-18s\x1b[m 站名:\x1b[1;33m%s\x1b[m",
813 bbsnet_conf[i].host2, bbsnet_conf[i].host1);
814 moveto(20, 79);
815 prints("|");
816 moveto(21, 0);
817 clrtoeol();
818 prints("|\x1b[1m连往:\x1b[1;33m%-20s", bbsnet_conf[i].ip);
819 if (bbsnet_conf[i].port != 23)
820 {
821 prints(" %d", bbsnet_conf[i].port);
822 }
823 prints("\x1b[m");
824 moveto(21, 79);
825 prints("|");
826 iflush();
827
828 return 0;
829 }
830
831 int bbs_net()
832 {
833 int ch, i;
834
835 load_bbsnet_conf(CONF_BBSNET);
836
837 clearscr();
838 bbsnet_refresh();
839 display_menu(&bbsnet_menu);
840 bbsnet_selchange();
841
842 while (!SYS_server_exit)
843 {
844 ch = igetch(100);
845
846 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
847 {
848 BBS_last_access_tm = time(NULL);
849 }
850
851 switch (ch)
852 {
853 case KEY_NULL: // broken pipe
854 log_error("KEY_NULL\n");
855 goto cleanup;
856 case KEY_TIMEOUT:
857 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
858 {
859 log_error("User input timeout\n");
860 goto cleanup;
861 }
862 continue;
863 case KEY_ESC:
864 case Ctrl('C'): // user cancel
865 goto cleanup;
866 case CR:
867 bbsnet_connect(bbsnet_menu.menu_item_pos[0]);
868 bbsnet_refresh();
869 display_menu(&bbsnet_menu);
870 bbsnet_selchange();
871 break;
872 case KEY_UP:
873 for (i = 0; i < STATION_PER_LINE; i++)
874 {
875 menu_control(&bbsnet_menu, KEY_UP);
876 }
877 bbsnet_selchange();
878 break;
879 case KEY_DOWN:
880 for (i = 0; i < STATION_PER_LINE; i++)
881 {
882 menu_control(&bbsnet_menu, KEY_DOWN);
883 }
884 bbsnet_selchange();
885 break;
886 case KEY_LEFT:
887 menu_control(&bbsnet_menu, KEY_UP);
888 bbsnet_selchange();
889 break;
890 case KEY_RIGHT:
891 menu_control(&bbsnet_menu, KEY_DOWN);
892 bbsnet_selchange();
893 break;
894 case KEY_HOME:
895 case KEY_PGUP:
896 menu_control(&bbsnet_menu, KEY_PGUP);
897 bbsnet_selchange();
898 break;
899 case KEY_END:
900 case KEY_PGDN:
901 menu_control(&bbsnet_menu, KEY_PGDN);
902 bbsnet_selchange();
903 break;
904 default:
905 menu_control(&bbsnet_menu, ch);
906 bbsnet_selchange();
907 break;
908 }
909 }
910
911 cleanup:
912 unload_bbsnet_conf();
913
914 return 0;
915 }

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