diff options
-rw-r--r-- | pttbbs/include/proto.h | 16 | ||||
-rw-r--r-- | pttbbs/mbbsd/announce.c | 112 | ||||
-rw-r--r-- | pttbbs/mbbsd/bbs.c | 2 | ||||
-rw-r--r-- | pttbbs/mbbsd/mail.c | 2 | ||||
-rw-r--r-- | pttbbs/mbbsd/read.c | 263 | ||||
-rw-r--r-- | pttbbs/mbbsd/record.c | 12 |
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), ¶m); - 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; } |