summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pttbbs/common/sys/string.c18
-rw-r--r--pttbbs/include/cmsys.h8
-rw-r--r--pttbbs/include/common.h6
-rw-r--r--pttbbs/include/proto.h3
-rw-r--r--pttbbs/mbbsd/bbs.c125
-rw-r--r--pttbbs/mbbsd/mail.c34
-rw-r--r--pttbbs/mbbsd/stuff.c42
-rw-r--r--pttbbs/mbbsd/var.c5
8 files changed, 166 insertions, 75 deletions
diff --git a/pttbbs/common/sys/string.c b/pttbbs/common/sys/string.c
index 1d0aa3a9..80dda509 100644
--- a/pttbbs/common/sys/string.c
+++ b/pttbbs/common/sys/string.c
@@ -26,6 +26,24 @@ str_lower(char *t, const char *s)
} while (ch);
}
+int
+str_starts_with(const char *str, const char *prefix) {
+ while (*prefix) {
+ if (*prefix++ != *str++)
+ return 0;
+ }
+ return 1;
+}
+
+int
+str_case_starts_with(const char *str, const char *prefix) {
+ while (*prefix) {
+ if (tolower(*prefix++) != tolower(*str++))
+ return 0;
+ }
+ return 1;
+}
+
/**
* 移除字串 buf 後端多餘的空白。
* @param buf
diff --git a/pttbbs/include/cmsys.h b/pttbbs/include/cmsys.h
index 81783c62..17f9fbe6 100644
--- a/pttbbs/include/cmsys.h
+++ b/pttbbs/include/cmsys.h
@@ -97,6 +97,8 @@ extern unsigned int *uintbsearch(const unsigned int key, const unsigned int *bas
/* string.h */
extern void str_lower(char *t, const char *s);
+extern int str_starts_with(const char *str, const char *prefix);
+extern int str_case_starts_with(const char *str, const char *prefix);
extern void trim(char *buf);
extern void chomp(char *src);
extern int strlen_noansi(const char *s);
@@ -300,9 +302,9 @@ extern int ucs2utf(uint16_t ucs2, uint8_t *utf8);
extern int utf2ucs(uint8_t *utf8, uint16_t *pucs);
/* big5.c */
-extern const uint16_t const b2u_table[];
-extern const uint16_t const u2b_table[];
-extern const uint8_t const b2u_ambiguous_width[];
+extern const uint16_t b2u_table[];
+extern const uint16_t u2b_table[];
+extern const uint8_t b2u_ambiguous_width[];
#endif
#endif
diff --git a/pttbbs/include/common.h b/pttbbs/include/common.h
index fa614eba..0861235b 100644
--- a/pttbbs/include/common.h
+++ b/pttbbs/include/common.h
@@ -192,6 +192,12 @@
#define WB_OFO_MSG_BOTTOM 22
#define WB_OFO_MSG_LEFT 4
+/* ----------------------------------------------------- */
+/* 標題類形 */
+/* ----------------------------------------------------- */
+#define SUBJECT_NORMAL 0
+#define SUBJECT_REPLY 1
+#define SUBJECT_FORWARD 2
/* ----------------------------------------------------- */
/* 群組名單模式 Ptt */
diff --git a/pttbbs/include/proto.h b/pttbbs/include/proto.h
index 716fac1e..ee79ffd3 100644
--- a/pttbbs/include/proto.h
+++ b/pttbbs/include/proto.h
@@ -613,7 +613,8 @@ int show_80x24_screen(const char *filename);
void show_help(const char * const helptext[]);
void show_helpfile(const char * helpfile);
int search_num(int ch, int max);
-char*subject(char *title);
+const char* subject(const char *title);
+const char* subject_ex(const char *title, int *ptype);
int str_checksum(const char *str);
int userid_is_BM(const char *userid, const char *list);
int is_uBM(const char *list, const char *id);
diff --git a/pttbbs/mbbsd/bbs.c b/pttbbs/mbbsd/bbs.c
index fde50827..5e1b0b66 100644
--- a/pttbbs/mbbsd/bbs.c
+++ b/pttbbs/mbbsd/bbs.c
@@ -575,11 +575,12 @@ tn_safe_strip(char *title)
static void
readdoent(int num, fileheader_t * ent)
{
- int type = ' ';
- char *mark, *title,
- color, special = 0, isonline = 0, recom[8];
+ int type = ' ', title_type = SUBJECT_NORMAL;
+ const char *title;
+ char *mark, color, special = 0, isonline = 0, recom[8];
char *typeattr = "";
char isunread = 0, oisunread = 0;
+ int w = 0;
#ifdef SAFE_ARTICLE_DELETE
// TODO maybe we should also check .filename because admin can't change that
@@ -658,7 +659,7 @@ readdoent(int num, fileheader_t * ent)
type = '+';
}
- title = ent->filename[0]!='L' ? subject(ent->title) : "<本文鎖定>";
+ title = ent->filename[0]!='L' ? subject_ex(ent->title, &title_type) : "<本文鎖定>";
#ifdef SAFE_ARTICLE_DELETE
if (iscorpse)
color = '0', mark = "□";
@@ -667,29 +668,17 @@ readdoent(int num, fileheader_t * ent)
#endif
if (ent->filemode & FILE_VOTE)
color = '2', mark = "ˇ";
- else if (title == ent->title)
- color = '1', mark = "□";
- else if (ent->title[0] == str_forward[0])
- color = '6', mark = "轉";
- else // if (ent->title[0] == str_reply[0])
- color = '3', mark = "R:";
-
- /* 把過長的 title 砍掉。 前面約有 33 個字元。 */
- {
- int l = t_columns - 34; /* 33+1, for trailing one more space */
- unsigned char *p = (unsigned char*)title;
-
- /* strlen 順便做 safe print checking */
- while (*p && l > 0)
- {
- /* 本來應該做 DBCS checking, 懶得寫了 */
- if(*p < ' ')
- *p = ' ';
- p++, l--;
- }
-
- if (*p && l <= 0)
- strcpy((char*)p-3, " …");
+ else switch(title_type) {
+ case SUBJECT_REPLY:
+ color = '3', mark = "R:";
+ break;
+ case SUBJECT_FORWARD:
+ color = '6', mark = "轉";
+ break;
+ case SUBJECT_NORMAL:
+ default:
+ color = '1', mark = "□";
+ break;
}
// TN_ANNOUNCE: [公告]
@@ -745,13 +734,42 @@ readdoent(int num, fileheader_t * ent)
if(isonline) outs(ANSI_COLOR(1));
prints("%-13.12s", ent->owner);
if(isonline) outs(ANSI_RESET);
-
- if (strncmp(currtitle, title, TTLEN))
- prints("%s " ANSI_COLOR(1) "%.*s" ANSI_RESET "%s\n",
- mark, special ? 6 : 0, title, special ? title + 6 : title);
- else
- prints(ANSI_COLOR(1;3%c) "%s %s" ANSI_RESET "\n",
- color, mark, title);
+
+ // TODO calculate correct width. 前面約有 33 個字元。 */
+ w = t_columns - 34; /* 33+1, for trailing one more space */
+
+ // print subject prefix
+ ent->title[sizeof(ent->title)-1] = 0;
+ if (strcmp(currtitle, title) == 0) {
+ prints(ANSI_COLOR(1;3%c), color);
+ outs(mark);
+ outc(' ');
+ } else {
+ outs(mark);
+ outc(' ');
+ if (special) {
+ int len_announce = strlen(TN_ANNOUNCE);
+ outs(ANSI_COLOR(1));
+ outs(TN_ANNOUNCE);
+ outs(ANSI_RESET);
+ title += len_announce;
+ w -= len_announce;
+ }
+ }
+
+ // strip unsafe characters
+ strip_nonebig5((char*)title, INT_MAX);
+
+ // print subject, bounded by w.
+ if (strlen(title) > w) {
+ if (DBCS_Status(title, w-2) == DBCS_TRAILING)
+ w--;
+ outns(title, w-2);
+ outs("…");
+ } else {
+ outs(title);
+ }
+ outc('\n');
}
int
@@ -1014,12 +1032,12 @@ do_reply_title(int row, const char *title, char result[STRLEN])
char genbuf[200];
char genbuf2[4];
- snprintf(result, STRLEN, "%s%s", str_reply, subject(title));
+ snprintf(result, STRLEN, "%s %s", str_reply, subject(title));
result[TTLEN - 1] = '\0';
- snprintf(genbuf, sizeof(genbuf), "採用原標題《%.60s》嗎?[Y] ", result);
- getdata(row, 0, genbuf, genbuf2, 4, LCECHO);
+ mvouts(row++, 0, "原標題: "); outs(result);
+ getdata(row, 0, "採用原標題[Y/n]? ", genbuf2, 3, LCECHO);
if (genbuf2[0] == 'n')
- getdata(++row, 0, "標題:", result, TTLEN, DOECHO);
+ getdata(row, 0, "新標題:", result, TTLEN, DOECHO);
}
void
@@ -1051,7 +1069,7 @@ log_crosspost_in_allpost(const char *brd, const fileheader_t *postfile) {
strcat(genbuf, "…");
}
snprintf(fh.title, sizeof(fh.title),
- "%s%-*.*s.%s板", str_forward, len, len, genbuf, brd);
+ "%s %-*.*s.%s板", str_forward, len, len, genbuf, brd);
setbdir(genbuf, BN_ALLPOST);
if (append_record(genbuf, &fh, sizeof(fileheader_t)) != -1) {
@@ -1069,13 +1087,20 @@ do_crosspost(const char *brd, fileheader_t *postfile, const char *fpath,
int len = 42-strlen(currboard);
fileheader_t fh;
int bid = getbnum(brd);
+ char *title, *prefix = "";
+ int title_type = SUBJECT_NORMAL;
if(bid <= 0 || bid > MAX_BOARD) return;
-
- if(!strncasecmp(postfile->title, str_reply, 3))
- len=len+4;
- else if(!strncasecmp(postfile->title, str_forward, 3))
- len=len+4;
+ title = subject_ex(postfile->title, &title_type);
+ switch (title_type) {
+ case SUBJECT_REPLY:
+ prefix = str_reply;
+ break;
+ case SUBJECT_FORWARD:
+ // is this a real case?
+ prefix = str_forward;
+ break;
+ }
memcpy(&fh, postfile, sizeof(fileheader_t));
if(isstamp) {
@@ -1088,7 +1113,9 @@ do_crosspost(const char *brd, fileheader_t *postfile, const char *fpath,
if(!strcasecmp(brd, BN_UNANONYMOUS))
strcpy(fh.owner, cuser.userid);
- sprintf(fh.title,"%-*.*s.%s板", len, len, postfile->title, currboard);
+ // TODO improve this in future (see log_crosspost_in_allpost)
+ snprintf(fh.title, sizeof(fh.title), "%s%s%-*.*s.%s板",
+ prefix, *prefix ? " " : "", len, len, title, currboard);
unlink(genbuf);
Copy((char *)fpath, genbuf);
fh.filemode = FILE_LOCAL;
@@ -1999,13 +2026,13 @@ cross_post(int ent, fileheader_t * fhdr, const char *direct)
if (ans[0] != 'n')
author = '1';
};
- snprintf(xtitle, sizeof(xtitle), "%s%.66s",
+ snprintf(xtitle, sizeof(xtitle), "%s %.66s",
str_forward, subject(fhdr->title));
- snprintf(genbuf, sizeof(genbuf), "採用原標題《%.60s》嗎?[Y] ", xtitle);
- getdata(2, 0, genbuf, genbuf2, 4, LCECHO);
+ mvouts(2, 0, "原標題: "); outs(xtitle);
+ getdata(3, 0, "採用原標題[Y/n]? ", genbuf2, 3, LCECHO);
if (genbuf2[0] == 'n') {
- if (getdata_str(2, 0, "標題:", genbuf, TTLEN, DOECHO, xtitle))
+ if (getdata_str(3, 0, "新標題:", genbuf, TTLEN, DOECHO, xtitle))
strlcpy(xtitle, genbuf, sizeof(xtitle));
}
// FIXME 這裡可能會有人偷偷生出保留標題(如[公告])
diff --git a/pttbbs/mbbsd/mail.c b/pttbbs/mbbsd/mail.c
index 78dbb833..475c9060 100644
--- a/pttbbs/mbbsd/mail.c
+++ b/pttbbs/mbbsd/mail.c
@@ -1123,6 +1123,7 @@ maildoent(int num, fileheader_t * ent)
char *title, *mark, *color = NULL, type = ' ';
char datepart[6];
char isonline = 0;
+ int title_type = SUBJECT_NORMAL;
if (ent->filemode & FILE_MARKED)
{
@@ -1143,13 +1144,21 @@ maildoent(int num, fileheader_t * ent)
if (FindTaggedItem(ent))
type = 'D';
- title = subject(mark = ent->title);
- if (title == mark) {
- color = ANSI_COLOR(1;31);
- mark = "◇";
- } else {
- color = ANSI_COLOR(1;33);
- mark = "R:";
+ title = subject_ex(ent->title, &title_type);
+ switch (title_type) {
+ case SUBJECT_REPLY:
+ mark = "轉";
+ color = ANSI_COLOR(1;36);
+ break;
+ case SUBJECT_FORWARD:
+ mark = "R:";
+ color = ANSI_COLOR(1;33);
+ break;
+ default:
+ case SUBJECT_NORMAL:
+ mark = "◇";
+ color = ANSI_COLOR(1;31);
+ break;
}
strlcpy(datepart, ent->date, sizeof(datepart));
@@ -1578,14 +1587,15 @@ mail_cross_post(int unused_arg, fileheader_t * fhdr, const char *direct)
if (ans[0] != 'n')
author = '1';
}
- snprintf(xtitle, sizeof(xtitle), "%s%.66s",
+ snprintf(xtitle, sizeof(xtitle), "%s %.66s",
str_forward, fhdr->title);
- snprintf(genbuf, sizeof(genbuf), "採用原標題《%.60s》嗎?[Y] ", xtitle);
- getdata(2, 0, genbuf, genbuf2, sizeof(genbuf2), LCECHO);
- if (*genbuf2 == 'n')
- if (getdata(2, 0, "標題:", genbuf, TTLEN, DOECHO))
+ mvouts(2, 0, "原標題: "); outs(xtitle);
+ getdata(3, 0, "採用原標題[Y/n]? ", genbuf2, 3, LCECHO);
+ if (genbuf2[0] == 'n') {
+ if (getdata(3, 0, "新標題:", genbuf, TTLEN, DOECHO))
strlcpy(xtitle, genbuf, sizeof(xtitle));
+ }
getdata(2, 0, "(S)存檔 (L)站內 (Q)取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] == 'l' || genbuf[0] == 's') {
diff --git a/pttbbs/mbbsd/stuff.c b/pttbbs/mbbsd/stuff.c
index 09eb8fee..4e1740b2 100644
--- a/pttbbs/mbbsd/stuff.c
+++ b/pttbbs/mbbsd/stuff.c
@@ -26,22 +26,48 @@ setbdir(char *buf, const char *boardname)
(currmode & MODE_DIGEST ? fn_mandex : str_dotdir));
}
+static int *
+_set_ptype(int *ptype, int type) {
+ if (ptype) {
+ *ptype = type;
+ }
+ return NULL;
+}
+
/**
* 給定文章標題 title,傳回指到主題的部分的指標。
* @param title
*/
-char *
-subject(char *title)
+const char*
+subject_ex(const char *title, int *ptype)
{
- if (strncasecmp(title, str_reply, 3) == 0 ||
- strncasecmp(title, str_forward, 3) == 0) {
- title += 3;
- if (*title == ' ')
- title++;
- }
+ do {
+ if (str_starts_with(title, str_reply)) {
+ title += strlen(str_reply);
+ ptype = _set_ptype(ptype, SUBJECT_REPLY);
+ }
+ else if (str_starts_with(title, str_forward)) {
+ title += strlen(str_forward);
+ ptype = _set_ptype(ptype, SUBJECT_FORWARD);
+ }
+ else if (str_starts_with(title, str_legacy_forward)) {
+ title += strlen(str_legacy_forward);
+ ptype = _set_ptype(ptype, SUBJECT_FORWARD);
+ } else {
+ ptype = _set_ptype(ptype, SUBJECT_NORMAL);
+ break;
+ }
+ while (*title == ' ')
+ title ++;
+ } while (1);
return title;
}
+const char *
+subject(const char *title) {
+ return subject_ex(title, NULL);
+}
+
int
is_uBM(const char *list, const char *id)
{
diff --git a/pttbbs/mbbsd/var.c b/pttbbs/mbbsd/var.c
index 3da09dbe..d5f24d4f 100644
--- a/pttbbs/mbbsd/var.c
+++ b/pttbbs/mbbsd/var.c
@@ -177,8 +177,9 @@ char * const err_uid = ERR_UID;
char * const err_filename = ERR_FILENAME;
char * const str_mail_address = "." BBSUSER "@" MYHOSTNAME;
-char * const str_reply = "Re: ";
-char * const str_forward = "Fw: ";
+char * const str_reply = "Re:";
+char * const str_forward = "Fw:";
+char * const str_legacy_forward = "[轉錄]";
char * const str_space = " \t\n\r";
char * const str_sysop = "SYSOP";
char * const str_author1 = STR_AUTHOR1;