summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pttbbs/include/proto.h16
-rw-r--r--pttbbs/mbbsd/announce.c112
-rw-r--r--pttbbs/mbbsd/bbs.c2
-rw-r--r--pttbbs/mbbsd/mail.c2
-rw-r--r--pttbbs/mbbsd/read.c263
-rw-r--r--pttbbs/mbbsd/record.c12
6 files changed, 191 insertions, 216 deletions
diff --git a/pttbbs/include/proto.h b/pttbbs/include/proto.h
index a4ea2aa5..2d7ef749 100644
--- a/pttbbs/include/proto.h
+++ b/pttbbs/include/proto.h
@@ -465,9 +465,19 @@ int main_railway(void);
void i_read(int cmdmode, const char *direct, void (*dotitle)(), void (*doentry)(), const onekey_t *rcmdlist, int bidcache);
void fixkeep(const char *s, int first);
keeploc_t *getkeep(const char *s, int def_topline, int def_cursline);
-int Tagger(time4_t chrono, int recno, int mode);
-void EnumTagFhdr(fileheader_t *fhdr, char *direct, int locus);
-void UnTagger (int locus);
+
+typedef struct
+{
+ // TODO use aid_t
+ char filename[FNLEN];
+} TagItem;
+
+TagItem *FindTaggedItem(const fileheader_t *fh);
+TagItem *RemoveTagItem(const fileheader_t *fh);
+TagItem *AddTagItem(const fileheader_t *fh);
+TagItem *ToggleTagItem(const fileheader_t *fh);
+int IsEmptyTagList();
+
/* record */
int stampfile_u(char *fpath, fileheader_t *fh);
int stampadir(char *fpath, fileheader_t * fh, int large_set);
diff --git a/pttbbs/mbbsd/announce.c b/pttbbs/mbbsd/announce.c
index b2534206..664c48cb 100644
--- a/pttbbs/mbbsd/announce.c
+++ b/pttbbs/mbbsd/announce.c
@@ -640,14 +640,67 @@ a_appenditem(const menu_t * pm, int isask)
}
}
+typedef struct _iter_paste_tag_param {
+ menu_t *pm;
+ boardheader_t *bh;
+ int mode;
+ int copied;
+ int item;
+} _iter_paste_tag_param;
+
+static int
+_iter_paste_tag(void *item, void *optarg) {
+ char buf[PATHLEN];
+ char title[TTLEN + 1] = "◇ ";
+ fileheader_t *fhdr = (fileheader_t*) item;
+ _iter_paste_tag_param *param = (_iter_paste_tag_param*) optarg;
+
+ param->item ++;
+ // XXX many process crashed here as fhdr.filename[0] == 0
+ // let's workaround it? or trace?
+ if (!fhdr->filename[0])
+ {
+ grayout(0, b_lines-2, GRAYOUT_DARK);
+ move(b_lines-1, 0); clrtobot();
+ prints("處理 #%d 項發生錯誤。 請把你剛剛進行的完整步驟貼到 "
+ BN_BUGREPORT " 板。\n", param->item);
+ vmsg("忽略錯誤並繼續進行。");
+ return 0;
+ }
+
+ if (!FindTaggedItem(fhdr))
+ return 0;
+
+ if (TagBoard == 0)
+ sethomefile(buf, cuser.userid, fhdr->filename);
+ else {
+ setbfile(buf, param->bh->brdname, fhdr->filename);
+ }
+
+ if (!dashf(buf))
+ return 0;
+
+ strlcpy(title + 3, fhdr->title, sizeof(title) - 3);
+ a_copyitem(buf, title, 0, 0);
+ if (param->mode) {
+ param->mode--;
+ a_pasteitem(param->pm, 0);
+ } else
+ a_appenditem(param->pm, 0);
+
+ param->copied++;
+ RemoveTagItem(fhdr);
+ return IsEmptyTagList();
+}
+
static int
a_pastetagpost(menu_t * pm, int mode)
{
- fileheader_t fhdr;
boardheader_t *bh = NULL;
- int ans = 0, ent = 0, tagnum;
- char title[TTLEN + 1] = "◇ ";
- char dirname[PATHLEN], buf[PATHLEN];
+ char dirname[PATHLEN];
+ _iter_paste_tag_param param = {0};
+ param.pm = pm;
+ param.mode = mode;
if (TagBoard == 0){
sethomedir(dirname, cuser.userid);
@@ -655,62 +708,27 @@ a_pastetagpost(menu_t * pm, int mode)
else{
bh = getbcache(TagBoard);
setbdir(dirname, bh->brdname);
+ param.bh = bh;
}
- tagnum = TagNum;
// prevent if anything wrong
- if (tagnum > MAXTAGS || tagnum < 0)
+ if (TagNum > MAXTAGS || TagNum < 0)
{
vmsg("內部錯誤。請把你剛剛進行的完整步驟貼到 "
BN_BUGREPORT " 板。");
- return ans;
+ return 0;
}
- if (tagnum < 1)
- return ans;
+ if (IsEmptyTagList())
+ return 0;
/* since we use different tag features,
* copyqueue is not required/used. */
copyqueue_reset();
+ apply_record(dirname, _iter_paste_tag, sizeof(fileheader_t), &param);
- while (tagnum-- > 0) {
- memset(&fhdr, 0, sizeof(fhdr));
- EnumTagFhdr(&fhdr, dirname, ent++);
-
- // XXX many process crashed here as fhdr.filename[0] == 0
- // let's workaround it? or trace?
- // if (!fhdr->filename[0])
- // continue;
-
- if (!fhdr.filename[0])
- {
- grayout(0, b_lines-2, GRAYOUT_DARK);
- move(b_lines-1, 0); clrtobot();
- prints("第 %d 項處理發生錯誤。 請把你剛剛進行的完整步驟貼到 "
- BN_BUGREPORT " 板。\n", ent);
- vmsg("忽略錯誤並繼續進行。");
- continue;
- }
-
- if (TagBoard == 0)
- sethomefile(buf, cuser.userid, fhdr.filename);
- else
- setbfile(buf, bh->brdname, fhdr.filename);
-
- if (dashf(buf)) {
- strlcpy(title + 3, fhdr.title, sizeof(title) - 3);
- a_copyitem(buf, title, 0, 0);
- if (mode) {
- mode--;
- a_pasteitem(pm, 0);
- } else
- a_appenditem(pm, 0);
- ++ans;
- UnTagger(tagnum);
- }
- }
-
- return ans;
+ TagNum = 0;
+ return param.copied;
}
static void
diff --git a/pttbbs/mbbsd/bbs.c b/pttbbs/mbbsd/bbs.c
index b764ff94..34afb54c 100644
--- a/pttbbs/mbbsd/bbs.c
+++ b/pttbbs/mbbsd/bbs.c
@@ -631,7 +631,7 @@ readdoent(int num, fileheader_t * ent)
// tag should override everything
if ((currmode & MODE_BOARD) || HasBasicUserPerm(PERM_LOGINOK))
{
- if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN))
+ if (FindTaggedItem(ent))
type = 'D';
}
diff --git a/pttbbs/mbbsd/mail.c b/pttbbs/mbbsd/mail.c
index 7287e5c9..8c1c2199 100644
--- a/pttbbs/mbbsd/mail.c
+++ b/pttbbs/mbbsd/mail.c
@@ -1140,7 +1140,7 @@ maildoent(int num, fileheader_t * ent)
' ' : '+';
}
- if (TagNum && !Tagger(atoi(ent->filename + 2), 0, TAG_NIN))
+ if (FindTaggedItem(ent))
type = 'D';
title = subject(mark = ent->title);
diff --git a/pttbbs/mbbsd/read.c b/pttbbs/mbbsd/read.c
index 1b0f89a3..9b3b81e9 100644
--- a/pttbbs/mbbsd/read.c
+++ b/pttbbs/mbbsd/read.c
@@ -10,190 +10,145 @@ static int last_line; // PTT: last_line 游標可指的最後一個
/* ----------------------------------------------------- */
/* Tag List 標籤 */
/* ----------------------------------------------------- */
-typedef struct
-{
- time4_t chrono;
- int recno;
-} TagItem;
-
static TagItem *TagList = NULL; /* ascending list */
-/**
- * @param locus
- * @return void
- */
-void
-UnTagger(int locus)
-{
- if (locus > TagNum || TagNum <= 0)
- return;
-
- TagNum--;
+int compare_tagitem(const void *pa, const void *pb) {
+ TagItem *taga = (TagItem*) pa,
+ *tagb = (TagItem*) pb;
+ return strcmp(taga->filename, tagb->filename);
+}
- if (TagNum > locus)
- memmove(&TagList[locus], &TagList[locus + 1],
- (TagNum - locus) * sizeof(TagItem));
+int IsEmptyTagList() {
+ return !TagList || TagNum <= 0;
}
-int
-Tagger(time4_t chrono, int recno, int mode)
-{
- int head, tail, posi = 0, comp;
+TagItem *FindTaggedItem(const fileheader_t *fh) {
+ if (IsEmptyTagList())
+ return NULL;
- if(TagList == NULL) {
- TagList = malloc(sizeof(TagItem)*(MAXTAGS+1));
- }
+ return (TagItem*)bsearch(
+ fh->filename, TagList, TagNum, sizeof(TagItem), compare_tagitem);
+}
- for (head = 0, tail = TagNum - 1, comp = 1; head <= tail;) {
- posi = (head + tail) >> 1;
- if (!(comp = TagList[posi].chrono - chrono)) {
- if (!recno)
- break;
- else if (!(comp = TagList[posi].recno - recno))
- break;
- }
- if (comp < 0) {
- head = posi + 1;
- } else {
- tail = posi - 1;
- }
- }
+TagItem *RemoveTagItem(const fileheader_t *fh) {
+ TagItem *tag = IsEmptyTagList() ? NULL : FindTaggedItem(fh);
+ if (!tag)
+ return tag;
- if (mode == TAG_NIN) {
- if (!comp && recno) /* 絕對嚴謹:連 recno 一起比對 */
- comp = recno - TagList[posi].recno;
- return comp;
+ TagNum--;
+ memmove(tag, tag + 1, (TagNum - (tag - TagList)) * sizeof(TagItem));
+ return tag;
+}
- }
- if (!comp) {
- if (mode != TAG_TOGGLE || TagNum <= 0)
- return NA;
-
- TagNum--;
- memmove(&TagList[posi], &TagList[posi + 1],
- (TagNum - posi) * sizeof(TagItem));
- } else if (TagNum < MAXTAGS) {
- TagItem *tagp;
-
- memmove(&TagList[head+1], &TagList[head], sizeof(TagItem)*(TagNum-head));
- tagp = &TagList[head];
- tagp->chrono = chrono;
- tagp->recno = recno;
- TagNum++;
+TagItem *AddTagItem(const fileheader_t *fh) {
+ if (TagNum == MAXTAGS)
+ return NULL;
+ if(TagList == NULL) {
+ const size_t sz = sizeof(TagItem) * (MAXTAGS + 1);
+ TagList = (TagItem*) malloc(sz);
+ memset(TagList, 0, sz);
} else {
- bell();
- return 0; /* full */
+ memset(TagList+TagNum, 0, sizeof(TagItem));
}
- return YEA;
-}
-
-void
-EnumTagFhdr(fileheader_t * fhdr, char *direct, int locus)
-{
- get_record(direct, fhdr, sizeof(fileheader_t), TagList[locus].recno);
+ // assert(!FindTaggedItem(fh));
+ strlcpy(TagList[TagNum++].filename, fh->filename, sizeof(fh->filename));
+ qsort(TagList, TagNum, sizeof(TagItem), compare_tagitem);
+ return FindTaggedItem(fh);
}
-/* -1 : 取消 */
-/* 0 : single article */
-/* ow: whole tag list */
-
-int
-AskTag(const char *msg)
-{
- int num;
-
- num = TagNum;
- switch (vansf("◆ %s A)文章 T)標記 Q)uit?", msg)) {
- case 'q':
- num = -1;
- break;
- case 'a':
- num = 0;
- }
- return num;
+TagItem *ToggleTagItem(const fileheader_t *fh) {
+ TagItem *tag = RemoveTagItem(fh);
+ if (tag)
+ return tag;
+ return AddTagItem(fh);
}
-
-#include <sys/mman.h>
-
-static char *
-f_map(const char *fpath, int *fsize)
-{
- int fd, size;
- struct stat st;
- char *map;
-
- if ((fd = open(fpath, O_RDONLY)) < 0)
- return (char *)-1;
-
- if (fstat(fd, &st) || !S_ISREG(st.st_mode) || (size = st.st_size) <= 0) {
- close(fd);
- return (char *)-1;
- }
- map = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- close(fd);
- *fsize = size;
- return map;
+static int
+_iter_tag_match_title(void *ptr, void *opt) {
+ fileheader_t *fh = (fileheader_t*) ptr;
+ char *pattern = (char*) opt;
+ char *title = subject(fh->title);
+
+ if (strncmp(pattern, title, TTLEN) != 0)
+ return 0;
+ if (FindTaggedItem(fh))
+ return 0;
+ if (!AddTagItem(fh))
+ return -1;
+ return 0;
}
-
static int
TagThread(const char *direct)
{
- int fsize, count;
- char *title, *fimage;
- fileheader_t *head, *tail;
-
- fimage = f_map(direct, &fsize);
- if (fimage == (char *)-1)
- return DONOTHING;
-
- head = (fileheader_t *) fimage;
- tail = (fileheader_t *) (fimage + fsize);
- count = 0;
- do {
- count++;
- title = subject(head->title);
- if (!strncmp(currtitle, title, TTLEN)) {
- if (!Tagger(atoi(head->filename + 2), count, TAG_INSERT))
- break;
- }
- } while (++head < tail);
-
- munmap(fimage, fsize);
+ apply_record(direct, _iter_tag_match_title, sizeof(fileheader_t), currtitle);
return FULLUPDATE;
}
+static int
+_iter_delete_tagged(void *ptr, void *opt) {
+ fileheader_t *fh = (fileheader_t*) ptr;
+ const char *direct = (const char*)opt;
+
+ if ((fh->filemode & FILE_MARKED) ||
+ (fh->filemode & FILE_DIGEST))
+ return 0;
+ if (!FindTaggedItem(fh))
+ return 0;
+ // only called by home or board, no need for man.
+ // so backup_direct can be same as direct.
+ delete_file_content(direct, fh, direct, NULL, 0);
+ return IsEmptyTagList();
+}
+
int
TagPruner(int bid)
{
boardheader_t *bp=NULL;
+ char direct[PATHLEN];
+
assert(bid >= 0); /* bid == 0 means in mailbox */
- if (bid){
+ if (bid && currstat != RMAIL){
bp = getbcache(bid);
if (is_readonly_board(bp->brdname))
return DONOTHING;
+ setbdir(direct, bp->brdname);
+ } else if(currstat == RMAIL) {
+ sethomedir(direct, cuser.userid);
+ } else {
+ vmsg("抱歉,程式異常 - 請至 " BN_BUGREPORT " 報告您剛的詳細步驟。");
+ return FULLUPDATE;
}
- if (TagNum && ((currstat != READING) || (currmode & MODE_BOARD))) {
- if (vans("刪除所有標記[N]?") != 'y')
- return READ_REDRAW;
+
+ if (IsEmptyTagList() || (currstat == READING && !(currmode & MODE_BOARD)))
+ return DONOTHING;
+ if (vans("刪除所有標記[N]?") != 'y')
+ return READ_REDRAW;
+
+ // ready to start.
+ outmsg("處理中,請稍後...");
+ refresh();
+
+ // first, delete and backup all files
+ apply_record(direct, _iter_delete_tagged, sizeof(fileheader_t), direct);
+
+ // now, delete the header
#ifdef SAFE_ARTICLE_DELETE
- if(bp && !(currmode & MODE_DIGEST) &&
- bp->nuser >= SAFE_ARTICLE_DELETE_NUSER)
- safe_delete_range(currdirect, 0, 0);
- else
+ if(bp && !(currmode & MODE_DIGEST) &&
+ bp->nuser >= SAFE_ARTICLE_DELETE_NUSER)
+ safe_delete_range(currdirect, 0, 0);
+ else
#endif
- delete_range(currdirect, 0, 0);
- TagNum = 0;
- if (bid)
- setbtotal(bid);
- else if(currstat == RMAIL)
- setupmailusage();
-
- return NEWDIRECT;
- }
- return DONOTHING;
+ delete_range(currdirect, 0, 0);
+
+ TagNum = 0;
+ if (bid)
+ setbtotal(bid);
+ else if(currstat == RMAIL)
+ setupmailusage();
+
+ return NEWDIRECT;
}
@@ -1011,17 +966,9 @@ i_read_key(const onekey_t * rcmdlist, keeploc_t * locmem,
TagNum = 0;
}
/* rocker.011112: 解決再select mode標記文章的問題 */
- if (Tagger(atoi(headers[locmem->crs_ln - locmem->top_ln].filename + 2),
- (currmode & MODE_SELECT) ?
- (headers[locmem->crs_ln - locmem->top_ln].multi.refer.ref) :
- locmem->crs_ln, TAG_TOGGLE))
+ if (ToggleTagItem(&headers[locmem->crs_ln - locmem->top_ln]))
{
-// (*doentry) (locmem->crs_ln, &headers[locmem->crs_ln-locmem->top_ln]);
locmem->crs_ln ++;
- // new_ln = locmem->crs_ln + 1;
- // new_top = 1;
- // mode = FULLUPDATE;
- // mode = PART_REDRAW;
mode = PARTUPDATE;
}
break;
diff --git a/pttbbs/mbbsd/record.c b/pttbbs/mbbsd/record.c
index 007f9a93..b3b9ccbb 100644
--- a/pttbbs/mbbsd/record.c
+++ b/pttbbs/mbbsd/record.c
@@ -167,7 +167,7 @@ void safe_delete_range(const char *fpath, int id1, int id2)
if (!((fhdr.filemode & FILE_MARKED) || /* 標記 */
(fhdr.filemode & FILE_DIGEST) || /* 文摘 */
(id1 && (i < id1 || i > id2)) || /* range */
- (!id1 && Tagger(atoi(t + 2), i, TAG_NIN)))) /* TagList */
+ (!id1 && !FindTaggedItem(&fhdr)))) /* TagList */
safe_article_delete(i, &fhdr, fpath, NULL);
}
close(fd);
@@ -218,7 +218,7 @@ delete_range(const char *fpath, int id1, int id2)
((fhdr.filemode & FILE_DIGEST) && (currstat != RMAIL) )||
/* 文摘 , FILE_DIGEST is used as REPLIED in mail menu.*/
(id1 && (count < id1 || count > id2)) || /* range */
- (!id1 && Tagger(atoi(t + 2), count, TAG_NIN))) { /* TagList */
+ (!id1 && !FindTaggedItem(&fhdr))) { /* TagList */
if ((safewrite(fdw, &fhdr, sizeof(fileheader_t)) == -1)) {
close(fdr);
close(fdw);
@@ -226,11 +226,11 @@ delete_range(const char *fpath, int id1, int id2)
flock(fd, LOCK_UN);
close(fd);
return -1;
- }
+ }
} else {
- //if (dashd(fullpath))
- unlink(fullpath);
- dcount++;
+ unlink(fullpath);
+ dcount++;
+ RemoveTagItem(&fhdr);
}
++count;
}