--- lbbs/src/bbs_main.c 2025/07/02 04:17:33 1.76 +++ lbbs/src/bbs_main.c 2025/12/18 10:43:48 1.121 @@ -1,23 +1,21 @@ -/*************************************************************************** - bbs_main.c - description - ------------------- - Copyright : (C) 2004-2025 by Leaflet - Email : leaflet@leafok.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bbs_main + * - entry and major procedures of user interactive access + * + * Copyright (C) 2004-2025 Leaflet + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "article_favor.h" #include "article_view_log.h" #include "bbs.h" #include "bbs_cmd.h" #include "bbs_main.h" +#include "bwf.h" #include "common.h" #include "database.h" #include "editor.h" @@ -27,8 +25,12 @@ #include "menu.h" #include "screen.h" #include "section_list.h" +#include "section_list_display.h" +#include "str_process.h" #include "trie_dict.h" +#include "user_list.h" #include "user_priv.h" +#include #include #include #include @@ -36,9 +38,18 @@ #include #include +static void child_proc_sig_usr1_handler(int i) +{ + // Restart log + if (log_restart() < 0) + { + log_error("Restart logging failed\n"); + } +} + int bbs_info() { - prints("欢迎光临 \033[1;33m%s \033[32m[%s] \033[37m( %s )\r\n", + prints("\r\n欢迎光临 \033[1;33m%s \033[32m[%s] \033[37m(%s)\033[m\r\n", BBS_name, BBS_server, APP_INFO); return iflush(); @@ -46,112 +57,34 @@ int bbs_info() int bbs_welcome(void) { - char sql[SQL_BUFFER_LEN]; - - u_int32_t u_online = 0; - u_int32_t u_anonymous = 0; - u_int32_t u_total = 0; - u_int32_t u_login_count = 0; - - MYSQL *db; - MYSQL_RES *rs; - MYSQL_ROW row; - - db = db_open(); - if (db == NULL) - { - return -1; - } - - snprintf(sql, sizeof(sql), - "SELECT COUNT(*) AS cc FROM " - "(SELECT DISTINCT SID FROM user_online " - "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND)) AS t1", - BBS_user_off_line); - if (mysql_query(db, sql) != 0) - { - log_error("Query user_online error: %s\n", mysql_error(db)); - mysql_close(db); - return -2; - } - if ((rs = mysql_store_result(db)) == NULL) - { - log_error("Get user_online data failed\n"); - mysql_close(db); - return -2; - } - if ((row = mysql_fetch_row(rs))) - { - u_online = (u_int32_t)atoi(row[0]); - } - mysql_free_result(rs); + int u_online = 0; + int u_anonymous = 0; + int u_total = 0; + int u_login_count = 0; - snprintf(sql, sizeof(sql), - "SELECT COUNT(*) AS cc FROM " - "(SELECT DISTINCT SID FROM user_online " - "WHERE UID = 0 AND last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND)) AS t1", - BBS_user_off_line); - if (mysql_query(db, sql) != 0) + if (get_user_online_list_count(&u_online, &u_anonymous) < 0) { - log_error("Query user_online error: %s\n", mysql_error(db)); - mysql_close(db); - return -2; + log_error("get_user_online_list_count() error\n"); + u_online = 0; } - if ((rs = mysql_store_result(db)) == NULL) + u_online += u_anonymous; + u_online++; // current user + if (BBS_priv.uid == 0) { - log_error("Get user_online data failed\n"); - mysql_close(db); - return -2; + u_anonymous++; } - if ((row = mysql_fetch_row(rs))) - { - u_anonymous = (u_int32_t)atoi(row[0]); - } - mysql_free_result(rs); - snprintf(sql, sizeof(sql), "SELECT COUNT(UID) AS cc FROM user_list WHERE enable"); - if (mysql_query(db, sql) != 0) - { - log_error("Query user_list error: %s\n", mysql_error(db)); - mysql_close(db); - return -2; - } - if ((rs = mysql_store_result(db)) == NULL) + if (get_user_list_count(&u_total) < 0) { - log_error("Get user_list data failed\n"); - mysql_close(db); - return -2; - } - if ((row = mysql_fetch_row(rs))) - { - u_total = (u_int32_t)atoi(row[0]); + log_error("get_user_list_count() error\n"); + u_total = 0; } - mysql_free_result(rs); - snprintf(sql, sizeof(sql), "SELECT ID FROM user_login_log ORDER BY ID LIMIT 1"); - if (mysql_query(db, sql) != 0) - { - log_error("Query user_login_log error: %s\n", mysql_error(db)); - mysql_close(db); - return -2; - } - if ((rs = mysql_store_result(db)) == NULL) - { - log_error("Get user_login_log data failed\n"); - mysql_close(db); - return -2; - } - if ((row = mysql_fetch_row(rs))) + if (get_user_login_count(&u_login_count) < 0) { - u_login_count = (u_int32_t)atoi(row[0]); + log_error("get_user_login_count() error\n"); + u_login_count = 0; } - mysql_free_result(rs); - - mysql_close(db); - - // Count current user before login - u_online++; - u_anonymous++; // Display logo display_file(DATA_WELCOME, 2); @@ -161,9 +94,9 @@ int bbs_welcome(void) "\033[32m目前上站人数 [\033[36m%d/%d\033[32m] " "匿名游客[\033[36m%d\033[32m] " "注册用户数[\033[36m%d/%d\033[32m]\r\n" - "从 [\033[36m%s\033[32m] 起,累计访问人次:[\033[36m%d\033[32m]\033[m\r\n", + "从 [\033[36m%s\033[32m] 起,累计访问人次: [\033[36m%d\033[32m]\033[m\r\n", BBS_name, u_online, BBS_max_client, u_anonymous, u_total, - BBS_max_user, BBS_start_dt, u_login_count); + BBS_max_user_count, BBS_start_dt, u_login_count); iflush(); @@ -180,7 +113,7 @@ int bbs_logout(void) return -1; } - if (user_online_del(db) < 0) + if (user_online_exp(db) < 0) { return -2; } @@ -189,7 +122,28 @@ int bbs_logout(void) display_file(DATA_GOODBYE, 1); - log_common("User logout\n"); + log_common("User [%s] (uid=%d) logout, idle for %ld seconds since last input\n", + BBS_username, BBS_priv.uid, time(NULL) - BBS_last_access_tm); + + return 0; +} + +int bbs_session_cleanup(void) +{ + MYSQL *db; + + db = db_open(); + if (db == NULL) + { + return -1; + } + + if (user_online_del(db) < 0) + { + return -2; + } + + mysql_close(db); return 0; } @@ -197,6 +151,7 @@ int bbs_logout(void) int bbs_center() { int ch; + int loop; time_t t_last_action; BBS_last_access_tm = t_last_action = time(NULL); @@ -209,10 +164,16 @@ int bbs_center() display_menu(&bbs_menu); iflush(); - while (!SYS_server_exit) + for (loop = 1; !SYS_server_exit && loop;) { ch = igetch(100); + if (ch != KEY_NULL && ch != KEY_TIMEOUT) + { + BBS_last_access_tm = time(NULL); + log_debug("Debug: BBS_last_access_tm is updated\n"); + } + if (bbs_menu.choose_step == 0 && time(NULL) - t_last_action >= 10) { t_last_action = time(NULL); @@ -231,21 +192,25 @@ int bbs_center() switch (ch) { case KEY_NULL: // broken pipe - return 0; + log_debug("KEY_NULL\n"); + loop = 0; + break; case KEY_TIMEOUT: - if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME) + if (time(NULL) - BBS_last_access_tm >= BBS_max_user_idle_time) { - return 0; + log_debug("User input timeout\n"); + loop = 0; + break; } continue; case CR: - igetch_reset(); default: switch (menu_control(&bbs_menu, ch)) { case EXITBBS: case EXITMENU: - return 0; + loop = 0; + break; case REDRAW: t_last_action = time(NULL); clearscr(); @@ -261,8 +226,67 @@ int bbs_center() } iflush(); } + } + + return 0; +} + +int bbs_charset_select() +{ + char msg[LINE_BUFFER_LEN]; + int ch; + + snprintf(msg, sizeof(msg), + "\rChoose character set in 5 seconds, (U)UTF-8, (G)GBK [U]: "); + + while (!SYS_server_exit) + { + ch = press_any_key_ex(msg, 5); + switch (toupper(ch)) + { + case KEY_NULL: + return -1; + case KEY_TIMEOUT: + case CR: + case 'U': + break; + case 'G': + if (io_conv_init("GBK") < 0) + { + log_error("io_conv_init(%s) error\n", "GBK"); + return -1; + } + break; + default: + continue; + } - BBS_last_access_tm = time(NULL); + break; + } + + snprintf(msg, sizeof(msg), + "\r请在5秒内选择宽字符显示规则, (V)变宽, (F)定宽? [V]: "); + + while (!SYS_server_exit) + { + ch = press_any_key_ex(msg, 5); + switch (toupper(ch)) + { + case KEY_NULL: + return -1; + case KEY_TIMEOUT: + case CR: + case 'V': + UTF8_fixed_width = 0; + break; + case 'F': + UTF8_fixed_width = 1; + break; + default: + continue; + } + + break; } return 0; @@ -271,6 +295,7 @@ int bbs_center() int bbs_main() { struct sigaction act = {0}; + char msg[LINE_BUFFER_LEN]; // Set signal handler act.sa_handler = SIG_IGN; @@ -285,6 +310,12 @@ int bbs_main() log_error("set signal action of SIGCHLD error: %d\n", errno); goto cleanup; } + act.sa_handler = child_proc_sig_usr1_handler; + if (sigaction(SIGUSR1, &act, NULL) == -1) + { + log_error("set signal action of SIGUSR1 error: %d\n", errno); + goto cleanup; + } // Set data pools in shared memory readonly if (set_trie_dict_shm_readonly() < 0) @@ -295,10 +326,16 @@ int bbs_main() { goto cleanup; } +#ifdef HAVE_SYSTEM_V if (set_section_list_shm_readonly() < 0) { goto cleanup; } + if (set_user_list_pool_shm_readonly() < 0) + { + goto cleanup; + } +#endif // Load menu in shared memory if (set_menu_shm_readonly(&bbs_menu) < 0) @@ -306,8 +343,21 @@ int bbs_main() goto cleanup; } + // Set default charset + if (io_conv_init(BBS_default_charset) < 0) + { + log_error("io_conv_init(%s) error\n", BBS_default_charset); + goto cleanup; + } + set_input_echo(0); + // Set user charset + if (bbs_charset_select() < 0) + { + goto cleanup; + } + // System info if (bbs_info() < 0) { @@ -323,14 +373,29 @@ int bbs_main() // User login if (SSH_v2) { - prints("\033[1m%s 欢迎使用ssh方式访问 \033[1;33m按任意键继续...\033[m", BBS_username); - iflush(); - igetch_t(MAX_DELAY_TIME); + snprintf(msg, sizeof(msg), "\033[1m%s 欢迎使用ssh方式访问 \033[1;33m按任意键继续...\033[m", BBS_username); + press_any_key_ex(msg, 60); } else if (bbs_login() < 0) { goto cleanup; } + log_common("User [%s] (uid=%d) login from %s:%d\n", + BBS_username, BBS_priv.uid, hostaddr_client, port_client); + + // Check EULA update status + if (BBS_update_eula) + { + user_update_agreement(); + goto cleanup; + } + + // Load section aid locations + if (section_aid_locations_load(BBS_priv.uid) < 0) + { + log_error("article_view_log_load() error\n"); + goto cleanup; + } // Load article view log if (article_view_log_load(BBS_priv.uid, &BBS_article_view_log, 0) < 0) @@ -339,6 +404,13 @@ int bbs_main() goto cleanup; } + // Load article favorite + if (article_favor_load(BBS_priv.uid, &BBS_article_favor, 0) < 0) + { + log_error("article_favor_load() error\n"); + goto cleanup; + } + // Init editor memory pool if (editor_memory_pool_init() < 0) { @@ -357,26 +429,52 @@ int bbs_main() // Logout bbs_logout(); + // Save section aid locations + if (section_aid_locations_save(BBS_priv.uid) < 0) + { + log_error("article_view_log_save() error\n"); + } + // Save incremental article view log if (article_view_log_save_inc(&BBS_article_view_log) < 0) { log_error("article_view_log_save_inc() error\n"); } + // Save incremental article favorite + if (article_favor_save_inc(&BBS_article_favor) < 0) + { + log_error("article_favor_save_inc() error\n"); + } + cleanup: + // Cleanup session + bbs_session_cleanup(); + + // Cleanup iconv + io_conv_cleanup(); + // Cleanup editor memory pool editor_memory_pool_cleanup(); // Unload article view log article_view_log_unload(&BBS_article_view_log); + // Unload article favor + article_favor_unload(&BBS_article_favor); + // Detach menu in shared memory detach_menu_shm(&bbs_menu); + detach_menu_shm(&top10_menu); // Detach data pools shm + detach_user_list_pool_shm(); detach_section_list_shm(); detach_article_block_shm(); detach_trie_dict_shm(); + // Cleanup BWF + bwf_cleanup(); + return 0; }