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

Contents of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.137 - (show annotations)
Fri Dec 19 06:16:27 2025 UTC (2 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.136: +17 -17 lines
Content type: text/x-csrc
Append \n to the end of logging message by log_...()
Remove ending \n from each logging message

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * screen
4 * - advanced telnet-based user interactive input / output features
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "bbs.h"
14 #include "common.h"
15 #include "editor.h"
16 #include "file_loader.h"
17 #include "io.h"
18 #include "log.h"
19 #include "login.h"
20 #include "screen.h"
21 #include "str_process.h"
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <wchar.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32
33 const char CTRL_SEQ_CLR_LINE[] = "\033[K";
34
35 static const int ACTIVE_BOARD_HEIGHT = 8;
36
37 static const int STR_TOP_LEFT_MAX_LEN = 80;
38 static const int STR_TOP_MIDDLE_MAX_LEN = 40;
39 static const int STR_TOP_RIGHT_MAX_LEN = 80;
40
41 static size_t get_time_str(char *s, size_t len)
42 {
43 time_t curtime;
44 struct tm local_tm;
45
46 time(&curtime);
47 localtime_r(&curtime, &local_tm);
48 size_t j = strftime(s, len, "%m/%d %H:%M %Z", &local_tm);
49
50 return j;
51 }
52
53 void moveto(int row, int col)
54 {
55 if (row >= 0)
56 {
57 prints("\033[%d;%dH", row, col);
58 }
59 else
60 {
61 prints("\r");
62 }
63 }
64
65 void clrtoeol()
66 {
67 prints(CTRL_SEQ_CLR_LINE);
68 }
69
70 void clrline(int line_begin, int line_end)
71 {
72 int i;
73
74 for (i = line_begin; i <= line_end; i++)
75 {
76 moveto(i, 0);
77 prints(CTRL_SEQ_CLR_LINE);
78 }
79 }
80
81 void clrtobot(int line_begin)
82 {
83 moveto(line_begin, 0);
84 prints("\033[J");
85 moveto(line_begin, 0);
86 }
87
88 void clearscr()
89 {
90 prints("\033[2J");
91 moveto(1, 1);
92 }
93
94 inline int press_any_key()
95 {
96 return press_any_key_ex(" \033[1;33m按任意键继续...\033[m", 60);
97 }
98
99 int press_any_key_ex(const char *msg, int sec)
100 {
101 int ch = 0;
102 int duration = 0;
103 time_t t_begin = time(NULL);
104
105 moveto(SCREEN_ROWS, 0);
106 clrtoeol();
107
108 prints(msg);
109 iflush();
110
111 igetch_reset();
112
113 do
114 {
115 ch = igetch_t(sec - duration);
116 duration = (int)(time(NULL) - t_begin);
117 } while (!SYS_server_exit && ch == 0 && duration < 60);
118
119 return ch;
120 }
121
122 void set_input_echo(int echo)
123 {
124 if (echo)
125 {
126 outc('\x83'); // ASCII code 131
127 }
128 else
129 {
130 // outc ('\x85'); // ASCII code 133
131 prints("\xff\xfb\x01\xff\xfb\x03");
132 }
133 iflush();
134 }
135
136 static int _str_input(char *buffer, int buf_size, int max_display_len, enum io_echo_t echo_mode)
137 {
138 int ch;
139 int offset = 0;
140 int eol;
141 int display_len;
142 char input_str[5];
143 int str_len = 0;
144 wchar_t wcs[2];
145 char c;
146
147 buffer[buf_size - 1] = '\0';
148 offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
149
150 igetch_reset();
151
152 while (!SYS_server_exit)
153 {
154 ch = igetch_t(MIN(BBS_max_user_idle_time, 60));
155
156 if (ch == CR)
157 {
158 break;
159 }
160 else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
161 {
162 return -1;
163 }
164 else if (ch == LF || ch == '\0')
165 {
166 continue;
167 }
168 else if (ch == BACKSPACE)
169 {
170 if (offset > 0)
171 {
172 offset--;
173 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
174 {
175 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
176 {
177 offset--;
178 }
179 display_len--;
180 prints("\033[D \033[D");
181 }
182 buffer[offset] = '\0';
183 display_len--;
184 prints("\033[D \033[D");
185 iflush();
186 }
187 continue;
188 }
189 else if (ch > 255 || iscntrl(ch))
190 {
191 continue;
192 }
193 else if ((ch & 0xff80) == 0x80) // head of multi-byte character
194 {
195 str_len = 0;
196 c = (char)(ch & 0xf0);
197 while (c & 0x80)
198 {
199 input_str[str_len] = (char)(ch - 256);
200 str_len++;
201 c = (c & 0x7f) << 1;
202
203 if ((c & 0x80) == 0) // Input completed
204 {
205 break;
206 }
207
208 // Expect additional bytes of input
209 ch = igetch(100); // 0.1 second
210 if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
211 {
212 log_debug("Ignore %d bytes of incomplete UTF8 character", str_len);
213 str_len = 0;
214 break;
215 }
216 }
217 input_str[str_len] = '\0';
218
219 if (str_len == 0) // Incomplete input
220 {
221 continue;
222 }
223
224 if (mbstowcs(wcs, input_str, 1) == (size_t)-1)
225 {
226 log_error("mbstowcs() error");
227 }
228 if (offset + str_len > buf_size - 1 || display_len + (UTF8_fixed_width ? 2 : wcwidth(wcs[0])) > max_display_len) // No enough space for Chinese character
229 {
230 outc('\a');
231 iflush();
232 continue;
233 }
234
235 memcpy(buffer + offset, input_str, (size_t)str_len);
236 offset += str_len;
237 buffer[offset] = '\0';
238 display_len += 2;
239
240 switch (echo_mode)
241 {
242 case DOECHO:
243 prints(input_str);
244 break;
245 case NOECHO:
246 prints("**");
247 break;
248 }
249 }
250 else if (ch >= 32 && ch < 127) // Printable character
251 {
252 if (offset + 1 > buf_size - 1 || display_len + 1 > max_display_len)
253 {
254 outc('\a');
255 iflush();
256 continue;
257 }
258
259 buffer[offset++] = (char)ch;
260 buffer[offset] = '\0';
261 display_len++;
262
263 switch (echo_mode)
264 {
265 case DOECHO:
266 outc((char)ch);
267 break;
268 case NOECHO:
269 outc('*');
270 break;
271 }
272 }
273 else // Invalid character
274 {
275 continue;
276 }
277
278 iflush();
279 }
280
281 return offset;
282 }
283
284 int str_input(char *buffer, int buf_size, enum io_echo_t echo_mode)
285 {
286 int len;
287
288 buffer[0] = '\0';
289
290 len = _str_input(buffer, buf_size, buf_size, echo_mode);
291
292 prints("\r\n");
293 iflush();
294
295 return len;
296 }
297
298 int get_data(int row, int col, char *prompt, char *buffer, int buf_size, int max_display_len)
299 {
300 int len = 0;
301 int col_cur = 0;
302 int ch;
303 int offset = 0;
304 int eol;
305 int display_len;
306 char input_str[5];
307 int str_len = 0;
308 wchar_t wcs[2];
309 int wc_len;
310 char c;
311
312 buffer[buf_size - 1] = '\0';
313 offset = split_line(buffer, max_display_len, &eol, &display_len, 0);
314 buffer[offset] = '\0';
315 len = offset;
316 col_cur = col + str_length(prompt, 1) + display_len;
317
318 moveto(row, col);
319 prints("%s", prompt);
320 prints("%s", buffer);
321 prints("%*s", max_display_len - display_len, "");
322 moveto(row, col_cur);
323 iflush();
324
325 igetch_reset();
326
327 while (!SYS_server_exit)
328 {
329 ch = igetch_t(MIN(BBS_max_user_idle_time, 60));
330
331 if (ch == CR)
332 {
333 break;
334 }
335 else if (ch == KEY_TIMEOUT || ch == KEY_NULL) // timeout or broken pipe
336 {
337 return -1;
338 }
339 else if (ch == LF || ch == '\0')
340 {
341 continue;
342 }
343 else if (ch == BACKSPACE)
344 {
345 if (offset > 0)
346 {
347 str_len = 1;
348 offset--;
349 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
350 {
351 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
352 {
353 str_len++;
354 offset--;
355 }
356
357 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
358 {
359 log_error("mbstowcs() error");
360 }
361 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
362
363 if (wc_len == 2)
364 {
365 display_len--;
366 col_cur--;
367 }
368 }
369
370 memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
371 len -= str_len;
372 buffer[len] = '\0';
373 display_len--;
374 col_cur--;
375
376 moveto(row, col_cur);
377 prints("%s", buffer + offset);
378 prints("%*s", max_display_len - display_len, "");
379 moveto(row, col_cur);
380 iflush();
381 }
382 continue;
383 }
384 else if (ch == KEY_DEL)
385 {
386 if (offset < len)
387 {
388 if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
389 {
390 str_len = 0;
391 c = (char)(buffer[offset] & 0xf0);
392 while (c & 0x80)
393 {
394 str_len++;
395 c = (c & 0x7f) << 1;
396 }
397 display_len--;
398 }
399 else
400 {
401 str_len = 1;
402 }
403
404 memmove(buffer + offset, buffer + offset + str_len, (size_t)(len - offset - str_len));
405 len -= str_len;
406 buffer[len] = '\0';
407 display_len--;
408
409 moveto(row, col_cur);
410 prints("%s", buffer + offset);
411 prints("%*s", max_display_len - display_len, "");
412 moveto(row, col_cur);
413 iflush();
414 }
415 continue;
416 }
417 else if (ch == KEY_LEFT)
418 {
419 if (offset > 0)
420 {
421 str_len = 1;
422 offset--;
423 if (buffer[offset] < 0 || buffer[offset] > 127) // UTF8
424 {
425 while (offset > 0 && (buffer[offset] & 0xc0) != 0xc0)
426 {
427 str_len++;
428 offset--;
429 }
430
431 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
432 {
433 log_error("mbstowcs() error");
434 }
435 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
436
437 if (wc_len == 2)
438 {
439 col_cur--;
440 }
441 }
442 col_cur--;
443
444 moveto(row, col_cur);
445 iflush();
446 }
447 continue;
448 }
449 else if (ch == KEY_RIGHT)
450 {
451 if (offset < len)
452 {
453 str_len = 0;
454 if ((buffer[offset] & 0x80) == 0x80) // head of multi-byte character
455 {
456 c = (char)(buffer[offset] & 0xf0);
457 while (c & 0x80)
458 {
459 str_len++;
460 c = (c & 0x7f) << 1;
461 }
462
463 if (mbstowcs(wcs, buffer + offset, 1) == (size_t)-1)
464 {
465 log_error("mbstowcs() error");
466 }
467 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
468
469 if (wc_len == 2)
470 {
471 col_cur++;
472 }
473 }
474 else
475 {
476 str_len = 1;
477 }
478
479 col_cur++;
480 offset += str_len;
481
482 moveto(row, col_cur);
483 iflush();
484 }
485 continue;
486 }
487 else if (ch == KEY_HOME || ch == KEY_UP)
488 {
489 if (offset > 0)
490 {
491 offset = 0;
492 col_cur = col + str_length(prompt, 1);
493
494 moveto(row, col_cur);
495 iflush();
496 }
497 continue;
498 }
499 else if (ch == KEY_END || ch == KEY_DOWN)
500 {
501 if (offset < len)
502 {
503 offset = len;
504 col_cur = col + str_length(prompt, 1) + display_len;
505
506 moveto(row, col_cur);
507 iflush();
508 }
509 continue;
510 }
511 else if (ch > 255 || iscntrl(ch))
512 {
513 continue;
514 }
515 else if ((ch & 0xff80) == 0x80) // head of multi-byte character
516 {
517 str_len = 0;
518 c = (char)(ch & 0xf0);
519 while (c & 0x80)
520 {
521 input_str[str_len] = (char)(ch - 256);
522 str_len++;
523 c = (c & 0x7f) << 1;
524
525 if ((c & 0x80) == 0) // Input completed
526 {
527 break;
528 }
529
530 // Expect additional bytes of input
531 ch = igetch(100); // 0.1 second
532 if (ch == KEY_NULL || ch == KEY_TIMEOUT) // Ignore received bytes if no futher input
533 {
534 log_debug("Ignore %d bytes of incomplete UTF8 character", str_len);
535 str_len = 0;
536 break;
537 }
538 }
539 input_str[str_len] = '\0';
540
541 if (str_len == 0) // Incomplete input
542 {
543 continue;
544 }
545
546 if (mbstowcs(wcs, input_str, 1) == (size_t)-1)
547 {
548 log_error("mbstowcs() error");
549 }
550 wc_len = (UTF8_fixed_width ? 2 : wcwidth(wcs[0]));
551
552 if (len + str_len > buf_size - 1 ||
553 display_len + wc_len > max_display_len) // No enough space for Chinese character
554 {
555 outc('\a');
556 iflush();
557 continue;
558 }
559
560 memmove(buffer + offset + str_len, buffer + offset, (size_t)(len - offset));
561 memcpy(buffer + offset, input_str, (size_t)str_len);
562 len += str_len;
563 buffer[len] = '\0';
564 display_len += wc_len;
565
566 moveto(row, col_cur);
567 prints("%s", buffer + offset);
568 prints("%*s", max_display_len - display_len, "");
569
570 col_cur += wc_len;
571
572 moveto(row, col_cur);
573 iflush();
574
575 offset += str_len;
576 }
577 else if (ch >= 32 && ch < 127) // Printable character
578 {
579 if (len + 1 > buf_size - 1 || display_len + 1 > max_display_len)
580 {
581 outc('\a');
582 iflush();
583 continue;
584 }
585
586 memmove(buffer + offset + 1, buffer + offset, (size_t)(len - offset));
587 buffer[offset] = (char)ch;
588 len++;
589 buffer[len] = '\0';
590 display_len++;
591
592 moveto(row, col_cur);
593 prints("%s", buffer + offset);
594 prints("%*s", max_display_len - display_len, "");
595
596 col_cur++;
597
598 moveto(row, col_cur);
599 iflush();
600
601 offset++;
602 }
603 else // Invalid character
604 {
605 continue;
606 }
607 }
608
609 return len;
610 }
611
612 int display_data(const void *p_data, long display_line_total, const long *p_line_offsets, int eof_exit,
613 display_data_key_handler key_handler, const char *help_filename)
614 {
615 static int show_help = 1;
616 char buffer[LINE_BUFFER_LEN];
617 DISPLAY_CTX ctx;
618 int ch = 0;
619 int input_ok;
620 const int screen_begin_row = 1;
621 const int screen_row_total = SCREEN_ROWS - screen_begin_row;
622 int output_current_row = screen_begin_row;
623 int output_end_row = SCREEN_ROWS - 1;
624 long int line_current = 0;
625 long int len;
626 long int percentile;
627 int loop;
628 int eol, display_len;
629
630 clrline(output_current_row, SCREEN_ROWS);
631
632 // update msg_ext with extended key handler
633 if (key_handler(&ch, &ctx) != 0)
634 {
635 return ch;
636 }
637
638 loop = 1;
639 while (!SYS_server_exit && loop)
640 {
641 if (eof_exit > 0 && line_current >= display_line_total)
642 {
643 if (eof_exit == 1)
644 {
645 ch = press_any_key();
646 }
647 else // if (eof_exit == 2)
648 {
649 iflush();
650 }
651
652 loop = 0;
653 break;
654 }
655
656 if (line_current >= display_line_total || output_current_row > output_end_row)
657 {
658 ctx.reach_begin = (line_current < output_current_row ? 1 : 0);
659
660 if (line_current - (output_current_row - screen_begin_row) + screen_row_total < display_line_total)
661 {
662 percentile = (line_current - (output_current_row - screen_begin_row) + screen_row_total) * 100 / display_line_total;
663 ctx.reach_end = 0;
664 }
665 else
666 {
667 percentile = 100;
668 ctx.reach_end = 1;
669 }
670
671 ctx.line_top = line_current - (output_current_row - screen_begin_row) + 1;
672 ctx.line_bottom = MIN(line_current - (output_current_row - screen_begin_row) + screen_row_total, display_line_total);
673
674 snprintf(buffer, sizeof(buffer),
675 "\033[1;44;33m第\033[32m%ld\033[33m-\033[32m%ld\033[33m行 (\033[32m%ld%%\033[33m) %s",
676 ctx.line_top,
677 ctx.line_bottom,
678 percentile,
679 ctx.msg);
680
681 len = split_line(buffer, SCREEN_COLS, &eol, &display_len, 1);
682 for (; display_len < SCREEN_COLS; display_len++)
683 {
684 buffer[len++] = ' ';
685 }
686 buffer[len] = '\0';
687 strncat(buffer, "\033[m", sizeof(buffer) - 1 - strnlen(buffer, sizeof(buffer)));
688
689 moveto(SCREEN_ROWS, 0);
690 prints("%s", buffer);
691 iflush();
692
693 input_ok = 0;
694 while (!SYS_server_exit && !input_ok)
695 {
696 ch = igetch_t(BBS_max_user_idle_time);
697 input_ok = 1;
698
699 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
700 {
701 BBS_last_access_tm = time(NULL);
702
703 // Refresh current action
704 if (user_online_update(NULL) < 0)
705 {
706 log_error("user_online_update(NULL) error");
707 }
708 }
709
710 // extended key handler
711 if (key_handler(&ch, &ctx) != 0)
712 {
713 goto cleanup;
714 }
715
716 switch (ch)
717 {
718 case KEY_NULL:
719 log_debug("KEY_NULL");
720 goto cleanup;
721 case KEY_TIMEOUT:
722 log_debug("User input timeout");
723 goto cleanup;
724 case KEY_HOME:
725 if (line_current - output_current_row < 0) // Reach begin
726 {
727 break;
728 }
729 line_current = 0;
730 output_current_row = screen_begin_row;
731 output_end_row = SCREEN_ROWS - 1;
732 clrline(output_current_row, SCREEN_ROWS);
733 break;
734 case KEY_END:
735 if (display_line_total < screen_row_total)
736 {
737 break;
738 }
739 line_current = display_line_total - screen_row_total;
740 output_current_row = screen_begin_row;
741 output_end_row = SCREEN_ROWS - 1;
742 clrline(output_current_row, SCREEN_ROWS);
743 break;
744 case KEY_UP:
745 if (line_current - output_current_row < 0) // Reach begin
746 {
747 break;
748 }
749 line_current -= output_current_row;
750 output_current_row = screen_begin_row;
751 // screen_end_line = screen_begin_line;
752 // prints("\033[T"); // Scroll down 1 line
753 output_end_row = SCREEN_ROWS - 1; // Legacy Fterm only works with this line
754 break;
755 case CR:
756 case KEY_DOWN:
757 if (line_current + (screen_row_total - (output_current_row - screen_begin_row)) >= display_line_total) // Reach end
758 {
759 break;
760 }
761 line_current += (screen_row_total - (output_current_row - screen_begin_row));
762 output_current_row = screen_row_total;
763 output_end_row = SCREEN_ROWS - 1;
764 moveto(SCREEN_ROWS, 0);
765 clrtoeol();
766 // prints("\033[S"); // Scroll up 1 line
767 prints("\n"); // Legacy Cterm only works with this line
768 break;
769 case KEY_PGUP:
770 if (line_current - output_current_row < 0) // Reach begin
771 {
772 break;
773 }
774 line_current -= ((screen_row_total - 1) + (output_current_row - screen_begin_row));
775 if (line_current < 0)
776 {
777 line_current = 0;
778 }
779 output_current_row = screen_begin_row;
780 output_end_row = SCREEN_ROWS - 1;
781 clrline(output_current_row, SCREEN_ROWS);
782 break;
783 case KEY_SPACE:
784 case KEY_PGDN:
785 if (line_current + screen_row_total - (output_current_row - screen_begin_row) >= display_line_total) // Reach end
786 {
787 break;
788 }
789 line_current += (screen_row_total - 1) - (output_current_row - screen_begin_row);
790 if (line_current + screen_row_total > display_line_total) // No enough lines to display
791 {
792 line_current = display_line_total - screen_row_total;
793 }
794 output_current_row = screen_begin_row;
795 output_end_row = SCREEN_ROWS - 1;
796 clrline(output_current_row, SCREEN_ROWS);
797 break;
798 case KEY_ESC:
799 case KEY_LEFT:
800 loop = 0;
801 break;
802 case 'h':
803 if (!show_help) // Not reentrant
804 {
805 break;
806 }
807 // Display help information
808 show_help = 0;
809 display_file(help_filename, 1);
810 show_help = 1;
811 case KEY_F5:
812 // Refresh after display help information
813 line_current -= (output_current_row - screen_begin_row);
814 output_current_row = screen_begin_row;
815 output_end_row = SCREEN_ROWS - 1;
816 clrline(output_current_row, SCREEN_ROWS);
817 break;
818 case 0: // Refresh bottom line
819 break;
820 default:
821 input_ok = 0;
822 break;
823 }
824 }
825
826 continue;
827 }
828
829 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
830 if (len >= sizeof(buffer))
831 {
832 log_error("Buffer overflow: len=%ld(%ld - %ld) line=%ld ",
833 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
834 len = sizeof(buffer) - 1;
835 }
836 else if (len < 0)
837 {
838 log_error("Incorrect line offsets: len=%ld(%ld - %ld) line=%ld ",
839 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
840 len = 0;
841 }
842
843 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
844 buffer[len] = '\0';
845
846 moveto(output_current_row, 0);
847 clrtoeol();
848 prints("%s", buffer);
849 line_current++;
850 output_current_row++;
851 }
852
853 cleanup:
854 return ch;
855 }
856
857 int display_file_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
858 {
859 switch (*p_key)
860 {
861 case 0: // Set msg
862 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
863 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] | "
864 "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] | "
865 "帮助[\033[32mh\033[33m] |");
866 break;
867 }
868
869 return 0;
870 }
871
872 int display_file(const char *filename, int eof_exit)
873 {
874 int ret;
875 void *p_shm;
876 size_t data_len;
877 long line_total;
878 const void *p_data;
879 const long *p_line_offsets;
880
881 if ((p_shm = get_file_shm_readonly(filename, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
882 {
883 log_error("get_file_shm(%s) error", filename);
884 return KEY_NULL;
885 }
886
887 if (user_online_update("VIEW_FILE") < 0)
888 {
889 log_error("user_online_update(VIEW_FILE) error");
890 }
891
892 ret = display_data(p_data, line_total, p_line_offsets, eof_exit, display_file_key_handler, DATA_READ_HELP);
893
894 if (detach_file_shm(p_shm) < 0)
895 {
896 log_error("detach_file_shm(%s) error", filename);
897 }
898
899 return ret;
900 }
901
902 int show_top(const char *str_left, const char *str_middle, const char *str_right)
903 {
904 char str_left_f[STR_TOP_LEFT_MAX_LEN + 1];
905 char str_middle_f[STR_TOP_MIDDLE_MAX_LEN + 1];
906 char str_right_f[STR_TOP_RIGHT_MAX_LEN + 1];
907 int str_left_len;
908 int str_middle_len;
909 int str_right_len;
910 int eol;
911 int len;
912
913 strncpy(str_left_f, str_left, sizeof(str_left_f) - 1);
914 str_left_f[sizeof(str_left_f) - 1] = '\0';
915 len = split_line(str_left_f, STR_TOP_LEFT_MAX_LEN / 2, &eol, &str_left_len, 1);
916 str_left_f[len] = '\0';
917
918 strncpy(str_middle_f, str_middle, sizeof(str_middle_f) - 1);
919 str_middle_f[sizeof(str_middle_f) - 1] = '\0';
920 len = split_line(str_middle, STR_TOP_MIDDLE_MAX_LEN / 2, &eol, &str_middle_len, 1);
921 str_middle_f[len] = '\0';
922
923 strncpy(str_right_f, str_right, sizeof(str_right_f) - 1);
924 str_right_f[sizeof(str_right_f) - 1] = '\0';
925 len = split_line(str_right, STR_TOP_RIGHT_MAX_LEN / 2, &eol, &str_right_len, 1);
926 str_right_f[len] = '\0';
927
928 moveto(1, 0);
929 clrtoeol();
930 prints("\033[1;44;33m%s\033[37m%*s%s\033[33m%*s%s\033[m",
931 str_left_f, 44 - str_left_len - str_middle_len, "",
932 str_middle_f, 36 - str_right_len, "", str_right_f);
933
934 return 0;
935 }
936
937 int show_bottom(const char *msg)
938 {
939 char str_time[LINE_BUFFER_LEN];
940 int len_str_time;
941 time_t time_online;
942 struct tm *tm_online;
943 char msg_f[LINE_BUFFER_LEN];
944 int eol;
945 int len_msg;
946 int len;
947 int len_username;
948 char str_tm_online[LINE_BUFFER_LEN];
949 int len_str_tm_online;
950
951 len_str_time = (int)get_time_str(str_time, sizeof(str_time));
952
953 msg_f[0] = '\0';
954 len_msg = 0;
955 if (msg != NULL)
956 {
957 strncpy(msg_f, msg, sizeof(msg_f) - 1);
958 msg_f[sizeof(msg_f) - 1] = '\0';
959 len = split_line(msg_f, 23, &eol, &len_msg, 1);
960 msg_f[len] = '\0';
961 }
962
963 len_username = (int)strnlen(BBS_username, sizeof(BBS_username));
964
965 time_online = time(NULL) - BBS_login_tm;
966 tm_online = gmtime(&time_online);
967 if (tm_online->tm_mday > 1)
968 {
969 snprintf(str_tm_online, sizeof(str_tm_online),
970 "\033[36m%d\033[33md \033[36m%d\033[33m:\033[36m%.2d",
971 tm_online->tm_mday - 1, tm_online->tm_hour, tm_online->tm_min);
972 }
973 else
974 {
975 snprintf(str_tm_online, sizeof(str_tm_online),
976 "\033[36m%d\033[33m:\033[36m%.2d",
977 tm_online->tm_hour, tm_online->tm_min);
978 }
979 len_str_tm_online = str_length(str_tm_online, 1);
980
981 moveto(SCREEN_ROWS, 0);
982 clrtoeol();
983 prints("\033[1;44;33m时间[\033[36m%s\033[33m]%s%*s \033[33m用户[\033[36m%s\033[33m][%s\033[33m]\033[m",
984 str_time, msg_f, 65 - len_str_time - len_msg - len_username - len_str_tm_online,
985 "", BBS_username, str_tm_online);
986
987 return 0;
988 }
989
990 int show_active_board()
991 {
992 static int line_current = 0;
993 static const void *p_shm = NULL;
994 static size_t data_len;
995 static long line_total;
996 static const void *p_data;
997 static const long *p_line_offsets;
998
999 static time_t t_last_show = 0;
1000 static int line_last = 0;
1001
1002 char buffer[LINE_BUFFER_LEN];
1003 long int len;
1004
1005 if (p_shm == NULL)
1006 {
1007 if ((p_shm = get_file_shm_readonly(DATA_ACTIVE_BOARD, &data_len, &line_total, &p_data, &p_line_offsets)) == NULL)
1008 {
1009 log_error("get_file_shm(%s) error", DATA_ACTIVE_BOARD);
1010 return KEY_NULL;
1011 }
1012 }
1013
1014 if (time(NULL) - t_last_show >= 10)
1015 {
1016 line_last = line_current;
1017 t_last_show = time(NULL);
1018 }
1019 else
1020 {
1021 line_current = line_last;
1022 }
1023
1024 clrline(2, 2 + ACTIVE_BOARD_HEIGHT);
1025
1026 for (int i = 0; i < ACTIVE_BOARD_HEIGHT; i++)
1027 {
1028 len = p_line_offsets[line_current + 1] - p_line_offsets[line_current];
1029 if (len >= LINE_BUFFER_LEN)
1030 {
1031 log_error("buffer overflow: len=%ld(%ld - %ld) line=%ld ",
1032 len, p_line_offsets[line_current + 1], p_line_offsets[line_current], line_current);
1033 len = LINE_BUFFER_LEN - 1;
1034 }
1035
1036 memcpy(buffer, (const char *)p_data + p_line_offsets[line_current], (size_t)len);
1037 buffer[len] = '\0';
1038
1039 moveto(3 + i, 0);
1040 prints("%s", buffer);
1041
1042 line_current++;
1043 if (line_current >= line_total)
1044 {
1045 line_current = 0;
1046 break;
1047 }
1048 }
1049
1050 return 0;
1051 }

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