diff options
Diffstat (limited to 'mbbsd/announce.c')
-rw-r--r-- | mbbsd/announce.c | 1558 |
1 files changed, 0 insertions, 1558 deletions
diff --git a/mbbsd/announce.c b/mbbsd/announce.c deleted file mode 100644 index fb7db427..00000000 --- a/mbbsd/announce.c +++ /dev/null @@ -1,1558 +0,0 @@ -/* $Id$ */ -#include "bbs.h" - -// XXX piaip 2007/12/29 -// 最近發現很多 code 都死在 announce -// 因為進來要看 lastlevel 而非 currbid -// user 可能一進 BBS 直殺郵件->mail_cite->進精華區 -// 於是就爆炸 -// 同理 currboard 也不該用 -// 請改用 me.bid (注意 me.bid 可能為 0, 表示進來的非看板。) -// -// XXX 9999 麻煩想個方式改掉 - -// for max file size limitation here, see edit.c -#define MAX_FILE_SIZE (32768*1024) - -/* copy temp queue operation -------------------------------------- */ - -/* TODO - * change this to char* instead of char[] - */ -typedef struct { - char copyfile[PATHLEN]; - char copytitle[TTLEN + 1]; - char copyowner[IDLEN + 2]; -} CopyQueue ; - -#define COPYQUEUE_COMMON_SIZE (10) - -static CopyQueue *copyqueue; -static int allocated_copyqueue = 0, used_copyqueue = 0, head_copyqueue = 0; - -int copyqueue_testin(CopyQueue *pcq) -{ - int i = 0; - for (i = head_copyqueue; i < used_copyqueue; i++) - if (strcmp(pcq->copyfile, copyqueue[i].copyfile) == 0) - return 1; - return 0; -} - -int copyqueue_locate(CopyQueue *pcq) -{ - int i = 0; - for (i = head_copyqueue; i < used_copyqueue; i++) - if (strcmp(pcq->copyfile, copyqueue[i].copyfile) == 0) - return i; - return -1; -} - -int copyqueue_fileinqueue(const char *fn) -{ - int i = 0; - for (i = head_copyqueue; i < used_copyqueue; i++) - if (strcmp(fn, copyqueue[i].copyfile) == 0) - return 1; - return 0; -} - -void copyqueue_reset() -{ - allocated_copyqueue = 0; - used_copyqueue = 0; - head_copyqueue = 0; -} - -int copyqueue_append(CopyQueue *pcq) -{ - if(copyqueue_testin(pcq)) - return 0; - if(head_copyqueue == used_copyqueue) - { - // empty queue, happy happy reset - if(allocated_copyqueue > COPYQUEUE_COMMON_SIZE) - { - // let's reduce it - allocated_copyqueue = COPYQUEUE_COMMON_SIZE; - copyqueue = (CopyQueue*)realloc( copyqueue, - allocated_copyqueue * sizeof(CopyQueue)); - } - head_copyqueue = used_copyqueue = 0; - } - used_copyqueue ++; - - if(used_copyqueue > allocated_copyqueue) - { - allocated_copyqueue = - used_copyqueue + COPYQUEUE_COMMON_SIZE; // half page - copyqueue = (CopyQueue*) realloc (copyqueue, - sizeof(CopyQueue) * allocated_copyqueue); - if(!copyqueue) - { - vmsg("記憶體不足,拷貝失敗"); - // try to reset - copyqueue_reset(); - if(copyqueue) free(copyqueue); - copyqueue = NULL; - return 0; - } - } - memcpy(&(copyqueue[used_copyqueue-1]), pcq, sizeof(CopyQueue)); - return 1; -} - -int copyqueue_toggle(CopyQueue *pcq) -{ - int i = copyqueue_locate(pcq); - if(i >= 0) - { -#if 0 - if (getans("已標記過此檔,要取消標記嗎 [y/N]: ") != 'y') - return 1; -#endif - /* remove it */ - used_copyqueue --; - if(head_copyqueue > used_copyqueue) - head_copyqueue =used_copyqueue; - if (i < used_copyqueue) - { - memcpy(copyqueue + i, copyqueue+i+1, - sizeof(CopyQueue) * (used_copyqueue - i)); - } - return 0; - } else { - copyqueue_append(pcq); - } - return 1; -} - -CopyQueue *copyqueue_gethead() -{ - if( used_copyqueue <= 0 || - head_copyqueue >= used_copyqueue) - return NULL; - return &(copyqueue[head_copyqueue++]); -} - -int copyqueue_querysize() -{ - if( used_copyqueue <= 0 || - head_copyqueue >= used_copyqueue) - return 0; - return (used_copyqueue - head_copyqueue); -} - -/* end copy temp queue operation ----------------------------------- */ - -void -a_copyitem(const char *fpath, const char *title, const char *owner, int mode) -{ - CopyQueue cq; - static int flFirstAlert = 1; - - memset(&cq, 0, sizeof(CopyQueue)); - strcpy(cq.copyfile, fpath); - strcpy(cq.copytitle, title); - if (owner) - strcpy(cq.copyowner, owner); - - //copyqueue_append(&cq); - copyqueue_toggle(&cq); - if (mode && flFirstAlert) { -#if 0 - move(b_lines-2, 0); clrtoeol(); - prints("目前已標記 %d 個檔案。[注意] 拷貝後才能刪除原文!", - copyqueue_querysize()); -#else - vmsg("[注意] 提醒您複製/標記後要貼上(p)或附加(a)後才能刪除原文!"); - flFirstAlert = 0; -#endif - } -} - -#define FHSZ sizeof(fileheader_t) - -static int -a_loadname(menu_t * pm) -{ - char buf[PATHLEN]; - int len; - - if(p_lines != pm->header_size) { - pm->header_size = p_lines; - pm->header = (fileheader_t *) realloc(pm->header, pm->header_size*FHSZ); - assert(pm->header); - } - - setadir(buf, pm->path); - len = get_records(buf, pm->header, FHSZ, pm->page + 1, pm->header_size); // XXX if get_records() return -1 - - // if len < 0, the directory is not valid anymore. - if (len < 0) - return 0; - - if (len < pm->header_size) - bzero(&pm->header[len], FHSZ * (pm->header_size - len)); - return 1; -} - -static void -a_timestamp(char *buf, const time4_t *time) -{ - struct tm *pt = localtime4(time); - - sprintf(buf, "%02d/%02d/%02d", pt->tm_mon + 1, pt->tm_mday, (pt->tm_year + 1900) % 100); -} - -static int -a_showmenu(menu_t * pm) -{ - char *title, *editor; - int n; - fileheader_t *item; - time4_t dtime; - - showtitle("精華文章", pm->mtitle); - prints(" " ANSI_COLOR(1;36) "編號 標 題%56s" ANSI_COLOR(0), - "編 選 日 期"); - - if (!pm->num) - { - outs("\n 《精華區》尚在吸取天地間的日月精華中... :)"); - } - else - { - char buf[PATHLEN]; - - // determine if path is valid. - if (!a_loadname(pm)) - return 0; - - for (n = 0; n < p_lines && pm->page + n < pm->num; n++) { - int flTagged = 0; - item = &pm->header[n]; - title = item->title; - editor = item->owner; - /* - * Ptt 把時間改為取檔案時間 dtime = atoi(&item->filename[2]); - */ - snprintf(buf, sizeof(buf), "%s/%s", pm->path, item->filename); - if(copyqueue_querysize() > 0 && copyqueue_fileinqueue(buf)) - { - flTagged = 1; - } - dtime = dasht(buf); - a_timestamp(buf, &dtime); - prints("\n%6d%c%c%-47.46s%-13s[%s]", pm->page + n + 1, - (item->filemode & FILE_BM) ? 'X' : - (item->filemode & FILE_HIDE) ? ')' : '.', - flTagged ? 'c' : ' ', - title, editor, - buf); - } - } - - move(b_lines, 0); - if(copyqueue_querysize() > 0) - { // something in queue - prints( - ANSI_COLOR(37;44) "【已標記(複製) %d 項】" - ANSI_COLOR(31;47) " (c)" ANSI_COLOR(30) "標記/複製 " - , copyqueue_querysize()); - - if(pm->level == 0) - outs(" - 無管理權限,無法貼上 " ANSI_RESET); - else - outs( ANSI_COLOR(31) "(p)" ANSI_COLOR(30) "貼上/取消/重設標記 " - ANSI_COLOR(31) "(a)" ANSI_COLOR(30) "附加至文章後 " - ANSI_RESET); - } - else if(pm->level) - { // BM - outs( - ANSI_COLOR(34;46) " 【板 主】 " - ANSI_COLOR(31;47) " (h)" ANSI_COLOR(30) "說明 " - ANSI_COLOR(31) "(q/←)" ANSI_COLOR(30) "離開 " - ANSI_COLOR(31) "(n)" ANSI_COLOR(30) "新增文章 " - ANSI_COLOR(31) "(g)" ANSI_COLOR(30) "新增目錄 " - ANSI_COLOR(31) "(e)" ANSI_COLOR(30) "編輯檔案 " ANSI_RESET - ); - } - else - { // normal user - outs( - ANSI_COLOR(34;46) " 【功\能鍵】 " - ANSI_COLOR(31;47) " (h)" ANSI_COLOR(30) "說明 " - ANSI_COLOR(31) "(q/←)" ANSI_COLOR(30) "離開 " - ANSI_COLOR(31) "(k↑j↓)" ANSI_COLOR(30) "移動游標 " - ANSI_COLOR(31) "(enter/→)" ANSI_COLOR(30) "讀取資料 " ANSI_RESET); - } - return 1; -} - -static int -a_searchtitle(menu_t * pm, int rev) -{ - static char search_str[40] = ""; - int pos; - - getdata(b_lines - 1, 1, "[搜尋]關鍵字:", search_str, sizeof(search_str), DOECHO); - - if (!*search_str) - return pm->now; - - str_lower(search_str, search_str); - - rev = rev ? -1 : 1; - pos = pm->now; - do { - pos += rev; - if (pos == pm->num) - pos = 0; - else if (pos < 0) - pos = pm->num - 1; - if (pos < pm->page || pos >= pm->page + p_lines) { - pm->page = pos - pos % p_lines; - - if (!a_loadname(pm)) - return pm->now; - } - if (strcasestr(pm->header[pos - pm->page].title, search_str)) - return pos; - } while (pos != pm->now); - return pm->now; -} - -enum { - NOBODY, MANAGER, SYSOP -}; - -static void -a_showhelp(int level) -{ - clear(); - outs(ANSI_COLOR(36) "【 " BBSNAME "公佈欄使用說明 】" ANSI_RESET "\n\n" - "[←][q] 離開到上一層目錄\n" - "[↑][k] 上一個選項\n" - "[↓][j] 下一個選項\n" - "[→][r][enter] 進入目錄/讀取文章\n" - "[^B][PgUp] 上頁選單\n" - "[^F][PgDn][Spc] 下頁選單\n" - "[##] 移到該選項\n" - "[F][U] 將文章寄回 Internet 郵箱/" - "將文章 uuencode 後寄回郵箱\n"); - if (level >= MANAGER) { - outs("\n" ANSI_COLOR(36) "【 板主專用鍵 】" ANSI_RESET "\n" - "[H] 切換為 公開/會員/板主 才能閱\讀\n" - "[n/g/G] 收錄精華文章/開闢目錄/建立連線\n" - "[m/d/D] 移動/刪除文章/刪除一個範圍的文章\n" - "[f/T/e] 編輯標題符號/修改文章標題/內容\n" - "[c/p/a] 精華區內 標記(複製)/貼上(可多篇)/附加單篇文章\n" - "[^P/^A] 貼上/附加精華區外已用't'標記文章\n"); - } - if (level >= SYSOP) { - outs("\n" ANSI_COLOR(36) "【 站長專用鍵 】" ANSI_RESET "\n" - "[l] 建 symbolic link\n" - "[N] 查詢檔名\n"); - } - pressanykey(); -} - -static void -a_forward(const char *path, const fileheader_t * pitem, int mode) -{ - fileheader_t fhdr; - - strlcpy(fhdr.filename, pitem->filename, sizeof(fhdr.filename)); - strlcpy(fhdr.title, pitem->title, sizeof(fhdr.title)); - switch (doforward(path, &fhdr, mode)) { - case 0: - outmsg(msg_fwd_ok); - break; - case -1: - outmsg(msg_fwd_err1); - break; - case -2: - outmsg(msg_fwd_err2); - break; - } -} - -static void -a_additem(menu_t * pm, const fileheader_t * myheader) -{ - char buf[PATHLEN]; - - setadir(buf, pm->path); - if (append_record(buf, myheader, FHSZ) == -1) - return; - pm->now = pm->num++; - - if (pm->now >= pm->page + p_lines) { - pm->page = pm->now - ((pm->page == 10000 && pm->now > p_lines / 2) ? - (p_lines / 2) : (pm->now % p_lines)); - } - /* Ptt */ - strlcpy(pm->header[pm->now - pm->page].filename, - myheader->filename, - sizeof(pm->header[pm->now - pm->page].filename)); -} - -#define ADDITEM 0 -#define ADDGROUP 1 - -static void -a_newitem(menu_t * pm, int mode) -{ - char *mesg[3] = { - "[新增文章] 請輸入標題:", /* ADDITEM */ - "[新增目錄] 請輸入標題:", /* ADDGROUP */ - }; - - char fpath[PATHLEN]; - fileheader_t item; - - strlcpy(fpath, pm->path, sizeof(fpath)); - if (strlen(pm->path) + FNLEN*2 >= PATHLEN) - return; - - switch (mode) { - case ADDITEM: - stampfile(fpath, &item); - strlcpy(item.title, "◇ ", sizeof(item.title)); /* A1BA */ - break; - - case ADDGROUP: - stampdir(fpath, &item); - strlcpy(item.title, "◆ ", sizeof(item.title)); /* A1BB */ - break; - } - - if (!getdata(b_lines - 1, 1, mesg[mode], &item.title[3], 55, DOECHO)) { - if (mode == ADDGROUP) - rmdir(fpath); - else - unlink(fpath); - return; - } - switch (mode) { - case ADDITEM: - { - int edflags = 0; -# ifdef GLOBAL_BBSMOVIE - if (pm && pm->bid && - strcmp(getbcache(pm->bid)->brdname, - GLOBAL_BBSMOVIE) == 0) - { - edflags |= EDITFLAG_UPLOAD; - edflags |= EDITFLAG_ALLOWLARGE; - } -# endif // GLOBAL_BBSMOVIE - if (vedit2(fpath, 0, NULL, edflags) == -1) { - unlink(fpath); - pressanykey(); - return; - } - } - break; - case ADDGROUP: - // do nothing - break; - } - - strlcpy(item.owner, cuser.userid, sizeof(item.owner)); - a_additem(pm, &item); -} - -void -a_pasteitem(menu_t * pm, int mode) -{ - char newpath[PATHLEN]; - char buf[PATHLEN]; - char ans[2], skipAll = 0, multiple = 0; - int i, copied = 0; - fileheader_t item; - - CopyQueue *cq; - - move(b_lines - 1, 0); - if(copyqueue_querysize() <= 0) - { - vmsg("請先執行複製(copy)命令後再貼上(paste)"); - return; - } - if(mode && copyqueue_querysize() > 1) - { - multiple = 1; - move(b_lines-2, 0); clrtobot(); - outs("c: 對各項目個別確認是否要貼上, z: 全部不貼,同時重設並取消全部標記\n"); - snprintf(buf, sizeof(buf), - "確定要貼上全部共 %d 個項目嗎 (c/z/y/N)? ", - copyqueue_querysize()); - getdata(b_lines - 1, 0, buf, ans, sizeof(ans), LCECHO); - if(ans[0] == 'y') - skipAll = 1; - else if(ans[0] == 'z') - { - copyqueue_reset(); - vmsg("已重設複製記錄。"); - return; - } - else if (ans[0] != 'c') - return; - clear(); - } - while (copyqueue_querysize() > 0) - { - cq = copyqueue_gethead(); - if(!cq->copyfile[0]) - continue; - if(mode && multiple) - { - scroll(); - move(b_lines-2, 0); clrtobot(); - prints("%d. %s\n", ++copied,cq->copytitle); - - } - - if (dashd(cq->copyfile)) { - for (i = 0; cq->copyfile[i] && cq->copyfile[i] == pm->path[i]; i++); - if (!cq->copyfile[i]) { - vmsg("將目錄拷進自己的子目錄中,會造成無窮迴圈!"); - continue; - } - } - if (mode && !skipAll) { - snprintf(buf, sizeof(buf), - "確定要拷貝[%s]嗎(Y/N)?[N] ", cq->copytitle); - getdata(b_lines - 1, 0, buf, ans, sizeof(ans), LCECHO); - } else - ans[0] = 'y'; - if (ans[0] == 'y') { - strlcpy(newpath, pm->path, sizeof(newpath)); - - if (*cq->copyowner) { - char *fname = strrchr(cq->copyfile, '/'); - - if (fname) - strcat(newpath, fname); - else - return; - if (access(pm->path, X_OK | R_OK | W_OK)) - mkdir(pm->path, 0755); - memset(&item, 0, sizeof(fileheader_t)); - strlcpy(item.filename, fname + 1, sizeof(item.filename)); - memcpy(cq->copytitle, "◎", 2); - Copy(cq->copyfile, newpath); - } else if (dashf(cq->copyfile)) { - stampfile(newpath, &item); - memcpy(cq->copytitle, "◇", 2); - Copy(cq->copyfile, newpath); - } else if (dashd(cq->copyfile)) { - stampdir(newpath, &item); - memcpy(cq->copytitle, "◆", 2); - copy_file(cq->copyfile, newpath); - } else { - copyqueue_reset(); - vmsg("無法拷貝!"); - return; - } - strlcpy(item.owner, *cq->copyowner ? cq->copyowner : cuser.userid, - sizeof(item.owner)); - strlcpy(item.title, cq->copytitle, sizeof(item.title)); - a_additem(pm, &item); - cq->copyfile[0] = '\0'; - } - } -} - -static void -a_appenditem(const menu_t * pm, int isask) -{ - char fname[PATHLEN]; - char buf[ANSILINELEN]; - char ans[2] = "y"; - FILE *fp, *fin; - - move(b_lines - 1, 0); - if(copyqueue_querysize() <= 0) - { - vmsg("請先執行 copy 命令後再 append"); - copyqueue_reset(); - return; - } - else - { - CopyQueue *cq = copyqueue_gethead(); - off_t sz; - - if (!dashf(cq->copyfile)) { - vmsg("目錄不得附加於檔案後!"); - return; - } - - snprintf(fname, sizeof(fname), "%s/%s", pm->path, - pm->header[pm->now - pm->page].filename); - - if (!dashf(fname)) { - vmsg("檔案不得附加於此!"); - return; - } - - sz = dashs(fname); - if (sz >= MAX_FILE_SIZE) - { - vmsg("檔案已超過最大限制,無法再附加"); - return; - } - - if (isask) { - snprintf(buf, sizeof(buf), - "確定要將[%s]附加於此嗎(Y/N)?[N] ", cq->copytitle); - getdata(b_lines - 2, 1, buf, ans, sizeof(ans), LCECHO); - } - - if (ans[0] != 'y' || !(fp = fopen(fname, "a+"))) - return; - - if (!(fin = fopen(cq->copyfile, "r"))) { - fclose(fp); - return; - } - - memset(buf, '-', 74); - buf[74] = '\0'; - fprintf(fp, "\n> %s <\n\n", buf); - if (isask) - getdata(b_lines - 1, 1, - "是否收錄簽名檔部份(Y/N)?[Y] ", - ans, sizeof(ans), LCECHO); - - while (fgets(buf, sizeof(buf), fin)) { - if ((ans[0] == 'n') && - !strcmp(buf, "--\n")) - break; - fputs(buf, fp); - } - fclose(fin); - fclose(fp); - cq->copyfile[0] = '\0'; - } -} - -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]; - - if (TagBoard == 0){ - sethomedir(dirname, cuser.userid); - } - else{ - bh = getbcache(TagBoard); - setbdir(dirname, bh->brdname); - } - tagnum = TagNum; - - // prevent if anything wrong - if (tagnum > MAXTAGS || tagnum < 0) - { - vmsg("內部錯誤。請把你剛剛進行的完整步驟貼到 " - GLOBAL_BUGREPORT " 板。"); - return ans; - } - - if (tagnum < 1) - return ans; - - /* since we use different tag features, - * copyqueue is not required/used. */ - copyqueue_reset(); - - 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 項處理發生錯誤。 請把你剛剛進行的完整步驟貼到 " - GLOBAL_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; -} - -static void -a_moveitem(menu_t * pm) -{ - fileheader_t *tmp; - char newnum[5]; - int num, max, min; - char buf[PATHLEN]; - int fail; - - snprintf(buf, sizeof(buf), "請輸入第 %d 選項的新次序:", pm->now + 1); - if (!getdata(b_lines - 1, 1, buf, newnum, sizeof(newnum), DOECHO)) - return; - num = (newnum[0] == '$') ? 9999 : atoi(newnum) - 1; - if (num >= pm->num) - num = pm->num - 1; - else if (num < 0) - num = 0; - setadir(buf, pm->path); - min = num < pm->now ? num : pm->now; - max = num > pm->now ? num : pm->now; - tmp = (fileheader_t *) calloc(max + 1, FHSZ); - - fail = 0; - if (get_records(buf, tmp, FHSZ, 1, min) != min) - fail = 1; - if (num > pm->now) { - if (get_records(buf, &tmp[min], FHSZ, pm->now + 2, max - min) != max - min) - fail = 1; - if (get_records(buf, &tmp[max], FHSZ, pm->now + 1, 1) != 1) - fail = 1; - } else { - if (get_records(buf, &tmp[min], FHSZ, pm->now + 1, 1) != 1) - fail = 1; - if (get_records(buf, &tmp[min + 1], FHSZ, num + 1, max - min) != max - min) - fail = 1; - } - if (!fail) - substitute_record(buf, tmp, FHSZ * (max + 1), 1); - pm->now = num; - free(tmp); -} - -static void -a_delrange(menu_t * pm) -{ - char fname[PATHLEN]; - - snprintf(fname, sizeof(fname), "%s/" FN_DIR, pm->path); - del_range(0, NULL, fname); - pm->num = get_num_records(fname, FHSZ); -} - -static void -a_delete(menu_t * pm) -{ - char fpath[PATHLEN], buf[PATHLEN], cmd[PATHLEN]; - char ans[4]; - fileheader_t backup; - - snprintf(fpath, sizeof(fpath), - "%s/%s", pm->path, pm->header[pm->now - pm->page].filename); - setadir(buf, pm->path); - - if (pm->header[pm->now - pm->page].filename[0] == 'H' && - pm->header[pm->now - pm->page].filename[1] == '.') { - getdata(b_lines - 1, 1, "您確定要刪除此精華區連線嗎(Y/N)?[N] ", - ans, sizeof(ans), LCECHO); - if (ans[0] != 'y') - return; - if (delete_record(buf, FHSZ, pm->now + 1) == -1) - return; - } else if (dashl(fpath)) { - getdata(b_lines - 1, 1, "您確定要刪除此 symbolic link 嗎(Y/N)?[N] ", - ans, sizeof(ans), LCECHO); - if (ans[0] != 'y') - return; - if (delete_record(buf, FHSZ, pm->now + 1) == -1) - return; - unlink(fpath); - } else if (dashf(fpath)) { - getdata(b_lines - 1, 1, "您確定要刪除此檔案嗎(Y/N)?[N] ", ans, - sizeof(ans), LCECHO); - if (ans[0] != 'y') - return; - if (delete_record(buf, FHSZ, pm->now + 1) == -1) - return; - - setbpath(buf, "deleted"); - stampfile(buf, &backup); - strlcpy(backup.owner, cuser.userid, sizeof(backup.owner)); - strlcpy(backup.title, - pm->header[pm->now - pm->page].title + 2, - sizeof(backup.title)); - - snprintf(cmd, sizeof(cmd), - "mv -f %s %s", fpath, buf); - system(cmd); - setbdir(buf, "deleted"); - append_record(buf, &backup, sizeof(backup)); - } else if (dashd(fpath)) { - getdata(b_lines - 1, 1, "您確定要刪除整個目錄嗎(Y/N)?[N] ", ans, - sizeof(ans), LCECHO); - if (ans[0] != 'y') - return; - if (delete_record(buf, FHSZ, pm->now + 1) == -1) - return; - - setapath(buf, "deleted"); - stampdir(buf, &backup); - - snprintf(cmd, sizeof(cmd), - "rm -rf %s;/bin/mv -f %s %s", buf, fpath, buf); - system(cmd); - - strlcpy(backup.owner, cuser.userid, sizeof(backup.owner)); - strcpy(backup.title, "◆"); - strlcpy(backup.title + 2, - pm->header[pm->now - pm->page].title + 2, - sizeof(backup.title) - 3); - - /* merge setapath(buf, "deleted"); setadir(buf, buf); */ - snprintf(buf, sizeof(buf), "man/boards/%c/%s/" FN_DIR, - 'd', "deleted"); - append_record(buf, &backup, sizeof(backup)); - } else { /* Ptt 損毀的項目 */ - getdata(b_lines - 1, 1, "您確定要刪除此損毀的項目嗎(Y/N)?[N] ", - ans, sizeof(ans), LCECHO); - if (ans[0] != 'y') - return; - if (delete_record(buf, FHSZ, pm->now + 1) == -1) - return; - } - pm->num--; -} - -static void -a_newtitle(const menu_t * pm) -{ - char buf[PATHLEN]; - fileheader_t item; - - memcpy(&item, &pm->header[pm->now - pm->page], FHSZ); - strlcpy(buf, item.title + 3, sizeof(buf)); - if (getdata_buf(b_lines - 1, 1, "新標題:", buf, 60, DOECHO)) { - strlcpy(item.title + 3, buf, sizeof(item.title) - 3); - setadir(buf, pm->path); - substitute_record(buf, &item, FHSZ, pm->now + 1); - } -} -static void -a_hideitem(const menu_t * pm) -{ - fileheader_t *item = &pm->header[pm->now - pm->page]; - char buf[PATHLEN]; - if (item->filemode & FILE_BM) { - item->filemode &= ~FILE_BM; - item->filemode &= ~FILE_HIDE; - } else if (item->filemode & FILE_HIDE) - item->filemode |= FILE_BM; - else - item->filemode |= FILE_HIDE; - setadir(buf, pm->path); - substitute_record(buf, item, FHSZ, pm->now + 1); -} -static void -a_editsign(const menu_t * pm) -{ - char buf[PATHLEN]; - fileheader_t item; - - memcpy(&item, &pm->header[pm->now - pm->page], FHSZ); - snprintf(buf, sizeof(buf), "%c%c", item.title[0], item.title[1]); - if (getdata_buf(b_lines - 1, 1, "符號", buf, 5, DOECHO)) { - item.title[0] = buf[0] ? buf[0] : ' '; - item.title[1] = buf[1] ? buf[1] : ' '; - item.title[2] = buf[2] ? buf[2] : ' '; - setadir(buf, pm->path); - substitute_record(buf, &item, FHSZ, pm->now + 1); - } -} - -static void -a_showname(const menu_t * pm) -{ - char buf[PATHLEN]; - int len; - int i; - int sym; - - move(b_lines - 1, 0); - snprintf(buf, sizeof(buf), - "%s/%s", pm->path, pm->header[pm->now - pm->page].filename); - if (dashl(buf)) { - prints("此 symbolic link 名稱為 %s\n", - pm->header[pm->now - pm->page].filename); - if ((len = readlink(buf, buf, PATHLEN - 1)) >= 0) { - buf[len] = '\0'; - for (i = 0; BBSHOME[i] && buf[i] == BBSHOME[i]; i++); - if (!BBSHOME[i] && buf[i] == '/') { - if (HasUserPerm(PERM_BBSADM)) - sym = 1; - else { - sym = 0; - for (i++; BBSHOME "/man"[i] && buf[i] == BBSHOME "/man"[i]; - i++); - if (!BBSHOME "/man"[i] && buf[i] == '/') - sym = 1; - } - if (sym) { - vmsgf("此 symbolic link 指向 %s\n", &buf[i + 1]); - } - } - } - } else if (dashf(buf)) - prints("此文章名稱為 %s", pm->header[pm->now - pm->page].filename); - else if (dashd(buf)) - prints("此目錄名稱為 %s", pm->header[pm->now - pm->page].filename); - else - outs("此項目已損毀, 建議將其刪除!"); - pressanykey(); -} -#ifdef CHESSCOUNTRY -static void -a_setchesslist(const menu_t * me) -{ - char buf[4]; - char buf_list[PATHLEN]; - char buf_photo[PATHLEN]; - char buf_this[PATHLEN]; - char buf_real[PATHLEN]; - int list_exist, photo_exist; - fileheader_t* fhdr = me->header + me->now - me->page; - int n; - - snprintf(buf_this, sizeof(buf_this), "%s/%s", me->path, fhdr->filename); - if((n = readlink(buf_this, buf_real, sizeof(buf_real) - 1)) == -1) - strcpy(buf_real, fhdr->filename); - else - // readlink doesn't garentee zero-ended - buf_real[n] = 0; - - if (strcmp(buf_real, "chess_list") == 0 - || strcmp(buf_real, "chess_photo") == 0) { - vmsg("不需重設!"); - return; - } - - snprintf(buf_list, sizeof(buf_list), "%s/chess_list", me->path); - snprintf(buf_photo, sizeof(buf_photo), "%s/chess_photo", me->path); - - list_exist = dashf(buf_list); - photo_exist = dashd(buf_photo); - - if (!list_exist && !photo_exist) { - vmsg("此看板非棋國!"); - return; - } - - getdata(b_lines, 0, "將此項目設定為 (1) 棋國名單 (2) 棋國照片檔目錄:", - buf, sizeof(buf), 1); - if (buf[0] == '1') { - if (list_exist) - getdata(b_lines, 0, "原有之棋國名單將被取代,請確認 (y/N)", - buf, sizeof(buf), 1); - else - buf[0] = 'y'; - - if (buf[0] == 'y' || buf[0] == 'Y') { - Rename(buf_this, buf_list); - symlink("chess_list", buf_this); - } - } else if (buf[0] == '2') { - if (photo_exist) - getdata(b_lines, 0, "原有之棋國照片將被取代,請確認 (y/N)", - buf, sizeof(buf), 1); - else - buf[0] = 'y'; - - if (buf[0] == 'y' || buf[0] == 'Y') { - if(strncmp(buf_photo, "man/boards/", 11) == 0 && // guarding - buf_photo[11] && buf_photo[12] == '/' && // guarding - snprintf(buf_list, sizeof(buf_list), "rm -rf %s", buf_photo) - == strlen(buf_photo) + 7) - system(buf_list); - Rename(buf_this, buf_photo); - symlink("chess_photo", buf_this); - } - } -} -#endif /* defined(CHESSCOUNTRY) */ - -static int -isvisible_man(const menu_t * me) -{ - fileheader_t *fhdr = &me->header[me->now - me->page]; - /* board friend only effact when in board reading mode */ - if (me->level >= MANAGER) - return 1; - if (fhdr->filemode & FILE_BM) - return 0; - if (fhdr->filemode & FILE_HIDE) - { - if (currstat == ANNOUNCE || - !is_hidden_board_friend(me->bid, currutmp->uid)) - return 0; - } - return 1; -} -int -a_menu(const char *maintitle, const char *path, - int lastlevel, int lastbid, - char *trans_buffer) -{ - static char Fexit; // 用來跳出 recursion - menu_t me; - char fname[PATHLEN]; - int ch, returnvalue = FULLUPDATE; - - // prevent deep resursive directories - if (strlen(path) + FNLEN >= PATHLEN) - { - // it is not save to enter such directory. - return returnvalue; - } - - if(trans_buffer) - trans_buffer[0] = '\0'; - - memset(&me, 0, sizeof(me)); - Fexit = 0; - me.header_size = p_lines; - me.header = (fileheader_t *) calloc(me.header_size, FHSZ); - me.path = path; - strlcpy(me.mtitle, maintitle, sizeof(me.mtitle)); - setadir(fname, me.path); - me.num = get_num_records(fname, FHSZ); - me.bid = lastbid; - - /* 精華區-tree 中部份結構屬於 cuser ==> BM */ - - if (!(me.level = lastlevel)) { - char *ptr; - - if ((ptr = strrchr(me.mtitle, '['))) - me.level = is_BM(ptr + 1); - } - me.page = 9999; - me.now = 0; - for (;;) { - if (me.now >= me.num) - me.now = me.num - 1; - if (me.now < 0) - me.now = 0; - - if (me.now < me.page || me.now >= me.page + me.header_size) { - me.page = me.now - ((me.page == 10000 && me.now > p_lines / 2) ? - (p_lines / 2) : (me.now % p_lines)); - if (!a_showmenu(&me)) - { - // some directories are invalid, restart! - Fexit = 1; - break; - } - } - ch = cursor_key(2 + me.now - me.page, 0); - - if (ch == 'q' || ch == 'Q' || ch == KEY_LEFT) - break; - - if (ch >= '1' && ch <= '9') { - if ((ch = search_num(ch, me.num)) != -1) - me.now = ch; - me.page = 10000; - continue; - } - switch (ch) { - case KEY_UP: - case 'k': - if (--me.now < 0) - me.now = me.num - 1; - break; - - case KEY_DOWN: - case 'j': - if (++me.now >= me.num) - me.now = 0; - break; - - case KEY_PGUP: - case Ctrl('B'): - if (me.now >= p_lines) - me.now -= p_lines; - else if (me.now > 0) - me.now = 0; - else - me.now = me.num - 1; - break; - - case ' ': - case KEY_PGDN: - case Ctrl('F'): - if (me.now < me.num - p_lines) - me.now += p_lines; - else if (me.now < me.num - 1) - me.now = me.num - 1; - else - me.now = 0; - break; - - case '0': - me.now = 0; - break; - case '?': - case '/': - if(me.num) { - me.now = a_searchtitle(&me, ch == '?'); - me.page = 9999; - } - break; - case '$': - me.now = me.num - 1; - break; - case 'h': - a_showhelp(me.level); - me.page = 9999; - break; - - case Ctrl('I'): - t_idle(); - me.page = 9999; - break; - - case 'e': - case 'E': - snprintf(fname, sizeof(fname), - "%s/%s", path, me.header[me.now - me.page].filename); - if (dashf(fname) && me.level >= MANAGER) { - int edflags = 0; - *quote_file = 0; - -# ifdef GLOBAL_BBSMOVIE - if (me.bid && strcmp(getbcache(me.bid)->brdname, - GLOBAL_BBSMOVIE) == 0) - { - edflags |= EDITFLAG_UPLOAD; - edflags |= EDITFLAG_ALLOWLARGE; - } -# endif // GLOBAL_BBSMOVIE - - if (vedit2(fname, NA, NULL, edflags) != -1) { - char fpath[PATHLEN]; - fileheader_t fhdr; - strlcpy(fpath, path, sizeof(fpath)); - stampfile(fpath, &fhdr); - unlink(fpath); - strlcpy(fhdr.filename, - me.header[me.now - me.page].filename, - sizeof(fhdr.filename)); - strlcpy(me.header[me.now - me.page].owner, - cuser.userid, - sizeof(me.header[me.now - me.page].owner)); - setadir(fpath, path); - substitute_record(fpath, me.header + me.now - me.page, - sizeof(fhdr), me.now + 1); - - } - me.page = 9999; - } - break; - - case 't': - case 'c': - if (me.now < me.num) { - if (!isvisible_man(&me)) - break; - - snprintf(fname, sizeof(fname), "%s/%s", path, - me.header[me.now - me.page].filename); - - /* XXX: dirty fix - 應該要改成如果發現該目錄裡面有隱形目錄的話才拒絕. - 不過這樣的話須要整個搜一遍, 而且目前判斷該資料是目錄 - 還是檔案竟然是用 fstat(2) 而不是直接存在 .DIR 內 |||b - 須等該資料寫入 .DIR 內再 implement才有效率. - */ - if( !lastlevel && !HasUserPerm(PERM_SYSOP) && - (me.bid==0 || !is_BM_cache(me.bid)) && dashd(fname) ) - vmsg("只有板主才可以拷貝目錄唷!"); - else - a_copyitem(fname, me.header[me.now - me.page].title, 0, 1); - me.page = 9999; - /* move down */ - if (++me.now >= me.num) - me.now = 0; - break; - } - case '\n': - case '\r': - case KEY_RIGHT: - case 'r': - if (me.now < me.num) { - fileheader_t *fhdr = &me.header[me.now - me.page]; - if (!isvisible_man(&me)) - break; -#ifdef DEBUG - vmsgf("%s/%s", &path[11], fhdr->filename);; -#endif - snprintf(fname, sizeof(fname), "%s/%s", path, fhdr->filename); - if (*fhdr->filename == 'H' && fhdr->filename[1] == '.') { - vmsg("不再支援 gopher mode, 請使用瀏覽器直接瀏覽"); - vmsgf("gopher://%s/1/",fhdr->filename+2); - } else if (dashf(fname)) { - int more_result; - - while ((more_result = more(fname, YEA))) { - /* Ptt 範本精靈 plugin */ - if (trans_buffer && - (currstat == EDITEXP || currstat == OSONG)) { - char ans[4]; - - move(22, 0); - clrtoeol(); - getdata(22, 1, - currstat == EDITEXP ? - "要把範例 Plugin 到文章嗎?[y/N]" : - "確定要點這首歌嗎?[y/N]", - ans, sizeof(ans), LCECHO); - if (ans[0] == 'y') { - strlcpy(trans_buffer, fname, PATHLEN); - Fexit = 1; - if (currstat == OSONG) { - log_filef(FN_USSONG, LOG_CREAT, "%s\n", fhdr->title); - } - free(me.header); - return FULLUPDATE; - } - } - if (more_result == READ_PREV) { - if (--me.now < 0) { - me.now = 0; - break; - } - } else if (more_result == READ_NEXT) { - if (++me.now >= me.num) { - me.now = me.num - 1; - break; - } - /* we only load me.header_size pages */ - if (me.now - me.page >= me.header_size) - break; - } else - break; - if (!isvisible_man(&me)) - break; - snprintf(fname, sizeof(fname), "%s/%s", path, - me.header[me.now - me.page].filename); - if (!dashf(fname)) - break; - } - } else if (dashd(fname)) { - a_menu(me.header[me.now - me.page].title, fname, - me.level, me.bid, trans_buffer); - /* Ptt 強力跳出recursive */ - if (Fexit) { - free(me.header); - return FULLUPDATE; - } - } - me.page = 9999; - } - break; - - case 'F': - case 'U': - if (me.now < me.num) { - fileheader_t *fhdr = &me.header[me.now - me.page]; - if (!isvisible_man(&me)) - break; - snprintf(fname, sizeof(fname), - "%s/%s", path, fhdr->filename); - if (HasUserPerm(PERM_LOGINOK) && dashf(fname)) { - a_forward(path, fhdr, ch /* == 'U' */ ); - /* By CharlieL */ - } else - vmsg("無法轉寄此項目"); - me.page = 9999; - } - - break; - - } - - if (me.level >= MANAGER) { - switch (ch) { - case 'n': - a_newitem(&me, ADDITEM); - me.page = 9999; - break; - case 'g': - a_newitem(&me, ADDGROUP); - me.page = 9999; - break; - case 'p': - a_pasteitem(&me, 1); - me.page = 9999; - break; - case 'f': - a_editsign(&me); - me.page = 9999; - break; - case Ctrl('P'): - a_pastetagpost(&me, -1); - returnvalue = DIRCHANGED; - me.page = 9999; - break; - case Ctrl('A'): - a_pastetagpost(&me, 1); - returnvalue = DIRCHANGED; - me.page = 9999; - break; - case 'a': - a_appenditem(&me, 1); - me.page = 9999; - break; -#ifdef BLOG - case 'b': - if (me.bid) - { - char genbuf[128]; - char *bname = getbcache(me.bid)->brdname; - snprintf(genbuf, sizeof(genbuf), - "bin/builddb.pl -f -n %d %s", me.now, bname); - system(genbuf); - vmsg("資料更新完成"); - } - me.page = 9999; - break; - - case 'B': - if (me.bid && me.bid == currbid) - { - BlogMain(me.now); - }; - me.page = 9999; - break; -#endif - } - - if (me.num) - switch (ch) { - case 'm': - a_moveitem(&me); - me.page = 9999; - break; - - case 'D': - /* Ptt me.page = -1; */ - a_delrange(&me); - me.page = 9999; - break; - case 'd': - a_delete(&me); - me.page = 9999; - break; - case 'H': - a_hideitem(&me); - me.page = 9999; - break; - case 'T': - a_newtitle(&me); - me.page = 9999; - break; -#ifdef CHESSCOUNTRY - case 'L': - a_setchesslist(&me); - break; -#endif - } - } - if (me.level >= SYSOP) { - switch (ch) { - case 'N': - a_showname(&me); - me.page = 9999; - break; - } - } - } - free(me.header); - return returnvalue; -} - -int -Announce(void) -{ - setutmpmode(ANNOUNCE); - a_menu(BBSNAME "佈告欄", "man", - ((HasUserPerm(PERM_SYSOP) ) ? SYSOP : NOBODY), - 0, - NULL); - return 0; -} - -#ifdef BLOG -#include <mysql/mysql.h> -void BlogMain(int num) -{ - int oldmode = currutmp->mode; - char genbuf[128], exit = 0; - - // WARNING: 要確認 currboard/currbid 已正確設定才能用此API。 - - //setutmpmode(BLOGGING); /* will crash someone using old program */ - sprintf(genbuf, "%s的部落格", currboard); - showtitle("部落格", genbuf); - while( !exit ){ - move(1, 0); - outs("請選擇您要執行的重作:\n" - "0.回到上一層\n" - "1.製作部落格樣板格式\n" - " 使用新的 config 目錄下樣板資料\n" - " 通常在第一次使用部落格或樣板更新的時候使用\n" - "\n" - "2.重新製作部落格\n" - " 只在部落格資料整個亂掉的時候才使用\n" - "\n" - "3.將本文加入部落格\n" - " 將游標所在位置的文章加入部落格\n" - "\n" - "4.刪除迴響\n" - "\n" - "5.刪除一篇部落格\n" - "\n" - "C.建立部落格目錄 (您只有第一次時需要)\n" - ); - switch( getans("請選擇(0-5,C)?[0]") ){ - case '1': - snprintf(genbuf, sizeof(genbuf), - "bin/builddb.pl -c %s", currboard); - system(genbuf); - break; - case '2': - snprintf(genbuf, sizeof(genbuf), - "bin/builddb.pl -a %s", currboard); - system(genbuf); - break; - case '3': - snprintf(genbuf, sizeof(genbuf), - "bin/builddb.pl -f -n %d %s", num, currboard); - system(genbuf); - break; - case '4':{ - char hash[33]; - int i; - getdata(16, 0, "請輸入該篇的雜湊值: ", - hash, sizeof(hash), DOECHO); - for( i = 0 ; hash[i] != 0 ; ++i ) /* 前面用 getdata() 保證有 \0 */ - if( !islower(hash[i]) && !isdigit(hash[i]) ) - break; - if( i != 32 ){ - vmsg("輸入錯誤"); - break; - } - if( hash[0] != 0 && - getans("請確定刪除(Y/N)?[N] ") == 'y' ){ - MYSQL mysql; - char cmd[256]; - - snprintf(cmd, sizeof(cmd), "delete from comment where " - "hash='%s'&&brdname='%s'", hash, currboard); -#ifdef DEBUG - vmsg(cmd); -#endif - if( !(!mysql_init(&mysql) || - !mysql_real_connect(&mysql, BLOGDB_HOST, BLOGDB_USER, - BLOGDB_PASSWD, BLOGDB_DB, - BLOGDB_PORT, BLOGDB_SOCK, 0) || - mysql_query(&mysql, cmd)) ) - vmsg("資料刪除完成"); - else - vmsg( -#ifdef DEBUG - mysql_error(&mysql) -#else - "database internal error" -#endif - ); - mysql_close(&mysql); - } - } - break; - - case '5': { - char date[9]; - int i; - getdata(16, 0, "請輸入該篇的日期(yyyymmdd): ", - date, sizeof(date), DOECHO); - for( i = 0 ; i < 9 ; ++i ) - if( !isdigit(date[i]) ) - break; - if( i != 8 ){ - vmsg("輸入錯誤"); - break; - } - snprintf(genbuf, sizeof(genbuf), - "bin/builddb.pl -D %s %s", date, currboard); - system(genbuf); - } - break; - - case 'C': case 'c': { - fileheader_t item; - char fpath[PATHLEN], adir[PATHLEN], buf[256]; - setapath(fpath, currboard); - stampdir(fpath, &item); - strlcpy(item.title, "◆ Blog", sizeof(item.title)); - strlcpy(item.owner, cuser.userid, sizeof(item.owner)); - - setapath(adir, currboard); - strcat(adir, "/" FN_DIR); - append_record(adir, &item, FHSZ); - - snprintf(buf, sizeof(buf), - "cp -R etc/Blog.Default/" FN_DIR " etc/Blog.Default/* %s/", - fpath); - system(buf); - - more("etc/README.BLOG", YEA); - } - break; - - default: - exit = 1; - break; - } - if( !exit ) - vmsg("部落格完成"); - } - currutmp->mode = oldmode; - pressanykey(); -} -#endif |