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

Contents of /lbbs/src/screen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.132 - (show annotations)
Sat Nov 29 01:56:08 2025 UTC (3 months, 2 weeks ago) by sysadm
Branch: MAIN
Changes since 1.131: +6 -0 lines
Content type: text/x-csrc
Refresh user online status on user input

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

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