--- lbbs/src/article_post.c 2025/06/15 04:46:19 1.17 +++ lbbs/src/article_post.c 2025/09/30 03:02:06 1.25 @@ -14,24 +14,22 @@ * * ***************************************************************************/ -#define _POSIX_C_SOURCE 200809L - -#include "article_post.h" #include "article_cache.h" -#include "editor.h" -#include "screen.h" +#include "article_post.h" #include "bbs.h" -#include "log.h" +#include "database.h" +#include "editor.h" #include "io.h" +#include "log.h" #include "lml.h" -#include "database.h" +#include "screen.h" #include "user_priv.h" #include #include #include #include -#define TITLE_INPUT_MAX_LEN 74 +#define TITLE_INPUT_MAX_LEN 72 #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB #define ARTICLE_QUOTE_MAX_LINES 20 #define ARTICLE_QUOTE_LINE_MAX_LEN 76 @@ -46,11 +44,12 @@ int article_post(const SECTION_LIST *p_s char sql[SQL_BUFFER_LEN]; char *sql_content = NULL; EDITOR_DATA *p_editor_data = NULL; - char title_input[TITLE_INPUT_MAX_LEN + 1]; + char title_input[BBS_article_title_max_len + 1]; char title_f[BBS_article_title_max_len * 2 + 1]; char *content = NULL; char *content_f = NULL; long len_content; + int content_display_length; char nickname_f[BBS_nickname_max_len * 2 + 1]; int sign_id = 0; long len; @@ -67,7 +66,7 @@ int article_post(const SECTION_LIST *p_s { clearscr(); moveto(1, 1); - prints("您没有权限在本版块发表文章\n"); + prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n"); press_any_key(); return 0; @@ -90,18 +89,18 @@ int article_post(const SECTION_LIST *p_s { clearscr(); moveto(21, 1); - prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创")); + prints("鍙戣〃鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝绫诲瀷: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "杞浇" : "鍘熷垱")); moveto(22, 1); - prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title)); + prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title)); moveto(23, 1); - prints("使用第 %d 个签名", sign_id); + prints("浣跨敤绗 %d 涓鍚", sign_id); if (toupper(ch) != 'T') { - prints(" 按0~3选签名档(0表示不使用)"); + prints(" 鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)"); moveto(24, 1); - prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: "); + prints("T鏀规爣棰, C鍙栨秷, Z璁句负杞浇, Y璁句负鍘熷垱, Enter缁х画: "); iflush(); ch = 0; } @@ -110,13 +109,16 @@ int article_post(const SECTION_LIST *p_s { switch (toupper(ch)) { + case KEY_NULL: + case KEY_TIMEOUT: + goto cleanup; case CR: igetch_reset(); break; case 'T': moveto(24, 1); clrtoeol(); - len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1); + len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN, DOECHO); for (p = title_input; *p == ' '; p++) ; for (q = title_input + len; q > p && *(q - 1) == ' '; q--) @@ -133,7 +135,7 @@ int article_post(const SECTION_LIST *p_s case 'C': clearscr(); moveto(1, 1); - prints("取消..."); + prints("鍙栨秷..."); press_any_key(); goto cleanup; case 'Y': @@ -166,13 +168,16 @@ int article_post(const SECTION_LIST *p_s clearscr(); moveto(1, 1); - prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: "); + prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: "); iflush(); for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME)) { switch (toupper(ch)) { + case KEY_NULL: + case KEY_TIMEOUT: + goto cleanup; case CR: igetch_reset(); case 'S': @@ -180,7 +185,7 @@ int article_post(const SECTION_LIST *p_s case 'C': clearscr(); moveto(1, 1); - prints("取消..."); + prints("鍙栨秷..."); press_any_key(); goto cleanup; case 'T': @@ -201,6 +206,11 @@ int article_post(const SECTION_LIST *p_s } } + if (SYS_server_exit) // Do not save data on shutdown + { + goto cleanup; + } + content = malloc(ARTICLE_CONTENT_MAX_LEN); if (content == NULL) { @@ -254,6 +264,9 @@ int article_post(const SECTION_LIST *p_s rs = NULL; } + // Calculate display length of content + content_display_length = str_length(content, 1); + // Begin transaction if (mysql_query(db, "SET autocommit=0") != 0) { @@ -317,9 +330,9 @@ int article_post(const SECTION_LIST *p_s snprintf(sql, sizeof(sql), "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, " "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) " - "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %ld)", + "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %d)", p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f, - p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, len_content); + p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, content_display_length); if (mysql_query(db, sql) != 0) { @@ -383,7 +396,7 @@ int article_post(const SECTION_LIST *p_s clearscr(); moveto(1, 1); - prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval); + prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval); press_any_key(); ret = 1; // Success @@ -410,6 +423,7 @@ int article_modify(const SECTION_LIST *p char *content = NULL; char *content_f = NULL; long len_content; + int content_display_length; int ch; long ret = 0; time_t now; @@ -427,7 +441,7 @@ int article_modify(const SECTION_LIST *p { clearscr(); moveto(1, 1); - prints("该文章无法被编辑,请联系版主。"); + prints("璇ユ枃绔犳棤娉曡缂栬緫锛岃鑱旂郴鐗堜富銆"); press_any_key(); return 0; @@ -474,7 +488,7 @@ int article_modify(const SECTION_LIST *p content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0'; // Remove control sequence - len_content = ctrl_seq_filter(content); + len_content = str_filter(content, 0); p_editor_data = editor_data_load(content); if (p_editor_data == NULL) @@ -499,13 +513,16 @@ int article_modify(const SECTION_LIST *p clearscr(); moveto(1, 1); - prints("(S)保存, (C)取消 or (E)再编辑? [S]: "); + prints("(S)淇濆瓨, (C)鍙栨秷 or (E)鍐嶇紪杈? [S]: "); iflush(); for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME)) { switch (toupper(ch)) { + case KEY_NULL: + case KEY_TIMEOUT: + goto cleanup; case CR: igetch_reset(); case 'S': @@ -513,7 +530,7 @@ int article_modify(const SECTION_LIST *p case 'C': clearscr(); moveto(1, 1); - prints("取消..."); + prints("鍙栨秷..."); press_any_key(); goto cleanup; case 'E': @@ -526,6 +543,11 @@ int article_modify(const SECTION_LIST *p } } + if (SYS_server_exit) // Do not save data on shutdown + { + goto cleanup; + } + // Allocate buffers in big size content = malloc(ARTICLE_CONTENT_MAX_LEN); if (content == NULL) @@ -548,9 +570,12 @@ int article_modify(const SECTION_LIST *p strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt); len_content += snprintf(content + len_content, LINE_BUFFER_LEN, - "\n--\n※ 作者已于 %s 修改本文※\n", + "\n--\n鈥 浣滆呭凡浜 %s 淇敼鏈枃鈥籠n", str_modify_dt); + // Calculate display length of content + content_display_length = str_length(content, 1); + db = db_open(); if (db == NULL) { @@ -618,8 +643,8 @@ int article_modify(const SECTION_LIST *p // Update article snprintf(sql, sizeof(sql), - "UPDATE bbs SET CID = %d, length = %ld, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition - p_article_new->cid, len_content, p_article->aid); + "UPDATE bbs SET CID = %d, length = %d, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition + p_article_new->cid, content_display_length, p_article->aid); if (mysql_query(db, sql) != 0) { @@ -661,7 +686,7 @@ int article_modify(const SECTION_LIST *p clearscr(); moveto(1, 1); - prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval); + prints("淇敼瀹屾垚锛屾柊鍐呭閫氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval); press_any_key(); ret = 1; // Success @@ -693,6 +718,7 @@ int article_reply(const SECTION_LIST *p_ char *content = NULL; char *content_f = NULL; long len_content; + int content_display_length; char nickname_f[BBS_nickname_max_len * 2 + 1]; int sign_id = 0; long len; @@ -714,7 +740,7 @@ int article_reply(const SECTION_LIST *p_ { clearscr(); moveto(1, 1); - prints("您没有权限在本版块发表文章\n"); + prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n"); press_any_key(); return 0; @@ -722,7 +748,7 @@ int article_reply(const SECTION_LIST *p_ p_article_new->title[0] = '\0'; snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title); - len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len); + len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len, 0); title_input[len] = '\0'; db = db_open(); @@ -764,10 +790,10 @@ int article_reply(const SECTION_LIST *p_ { mysql_close(db); db = NULL; - + clearscr(); moveto(1, 1); - prints("该主题谢绝回复"); + prints("璇ヤ富棰樿阿缁濆洖澶"); press_any_key(); goto cleanup; @@ -811,23 +837,28 @@ int article_reply(const SECTION_LIST *p_ } // Apply LML render to content body - len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN); + len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN, 0); content_f[len] = '\0'; // Remove control sequence - len = ctrl_seq_filter(content_f); + len = str_filter(content_f, 0); len = snprintf(content, ARTICLE_CONTENT_MAX_LEN, - "\n\n【 在 %s (%s) 的大作中提到: 】\n", + "\n\n銆 鍦 %s (%s) 鐨勫ぇ浣滀腑鎻愬埌: 銆慭n", p_article->username, p_article->nickname); - quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1); + quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1, 0, NULL); for (i = 0; i < quote_content_lines; i++) { memcpy(content + len, ": ", 2); // quote line prefix len += 2; memcpy(content + len, content_f + line_offsets[i], (size_t)(line_offsets[i + 1] - line_offsets[i])); len += (line_offsets[i + 1] - line_offsets[i]); + if (content[len - 1] != '\n') // Appennd \n if not exist + { + content[len] = '\n'; + len++; + } } if (content[len - 1] != '\n') // Appennd \n if not exist { @@ -861,18 +892,18 @@ int article_reply(const SECTION_LIST *p_ { clearscr(); moveto(21, 1); - prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname); + prints("鍥炲鏂囩珷浜 %s[%s] 璁ㄨ鍖", p_section->stitle, p_section->sname); moveto(22, 1); - prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title)); + prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title)); moveto(23, 1); - prints("使用第 %d 个签名", sign_id); + prints("浣跨敤绗 %d 涓鍚", sign_id); if (toupper(ch) != 'T') { - prints(" 按0~3选签名档(0表示不使用)"); + prints(" 鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)"); moveto(24, 1); - prints("T改标题, C取消, Enter继续: "); + prints("T鏀规爣棰, C鍙栨秷, Enter缁х画: "); iflush(); ch = 0; } @@ -881,13 +912,16 @@ int article_reply(const SECTION_LIST *p_ { switch (toupper(ch)) { + case KEY_NULL: + case KEY_TIMEOUT: + goto cleanup; case CR: igetch_reset(); break; case 'T': moveto(24, 1); clrtoeol(); - len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1); + len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN, DOECHO); for (p = title_input; *p == ' '; p++) ; for (q = title_input + len; q > p && *(q - 1) == ' '; q--) @@ -904,7 +938,7 @@ int article_reply(const SECTION_LIST *p_ case 'C': clearscr(); moveto(1, 1); - prints("取消..."); + prints("鍙栨秷..."); press_any_key(); goto cleanup; case '0': @@ -931,13 +965,16 @@ int article_reply(const SECTION_LIST *p_ clearscr(); moveto(1, 1); - prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: "); + prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: "); iflush(); for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME)) { switch (toupper(ch)) { + case KEY_NULL: + case KEY_TIMEOUT: + goto cleanup; case CR: igetch_reset(); case 'S': @@ -945,7 +982,7 @@ int article_reply(const SECTION_LIST *p_ case 'C': clearscr(); moveto(1, 1); - prints("取消..."); + prints("鍙栨秷..."); press_any_key(); goto cleanup; case 'T': @@ -966,6 +1003,11 @@ int article_reply(const SECTION_LIST *p_ } } + if (SYS_server_exit) // Do not save data on shutdown + { + goto cleanup; + } + content = malloc(ARTICLE_CONTENT_MAX_LEN); if (content == NULL) { @@ -1019,6 +1061,9 @@ int article_reply(const SECTION_LIST *p_ rs = NULL; } + // Calculate display length of content + content_display_length = str_length(content, 1); + // Begin transaction if (mysql_query(db, "SET autocommit=0") != 0) { @@ -1082,10 +1127,10 @@ int article_reply(const SECTION_LIST *p_ snprintf(sql, sizeof(sql), "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, " "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) " - "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %ld)", + "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %d)", p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid), BBS_priv.uid, BBS_username, nickname_f, title_f, - p_article_new->cid, hostaddr_client, BBS_user_exp, len_content); + p_article_new->cid, hostaddr_client, BBS_user_exp, content_display_length); if (mysql_query(db, sql) != 0) { @@ -1164,7 +1209,7 @@ int article_reply(const SECTION_LIST *p_ clearscr(); moveto(1, 1); - prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval); + prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval); press_any_key(); ret = 1; // Success