精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* announce.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : 精華區閱讀、編選 */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ /*========== This file is re-edited by Tsai Menguang (mgtsai), Sep 10th, '96 Change the announce directory structure as .DIR format ==========*/ #include "bbs.h" #include <time.h> #define PATHLEN 256 #define FHSZ sizeof(fileheader) #define ADDITEM 0 #define ADDGROUP 1 #define ADDGOPHER 2 #define ADDLINK 3 char trans_buffer[256]; static char paste_fname[200]; enum { NOBODY, MANAGER, SYSOP }; static char copyfile[PATHLEN]; static char copytitle[TTLEN+1]; static char copyowner[IDLEN + 2]; static char *mytitle = BOARDNAME "佈告欄"; static char *err_dup_fn = "系統中已有同名檔案存在了!"; static char *a_title; static void g_showmenu(pm) GMENU *pm; { static char *mytype = "編 選 絲路之旅"; char *title, *editor, *fname, *fdate, ch; int n, max, mode; ITEM *item; showtitle("精華文章", pm->mtitle); prints(" ;36m編號 標 題%56sm", mytype); if (pm->num) { n = pm->page; max = n + p_lines; if (max > pm->num) max = pm->num; while (n < max) { item = pm->item[n++]; title = item->title; ch = title[1]; prints("\n%5d. %-72.71s", n, title); } } else { outs("\n 《精華區》尚在吸取天地間的日精月華 :)"); } move(b_lines, 1); outs(pm->level ? "4;46m 【板 主】 1;47m (h)0m說明 1m(q/←)0m離開 \ 1m(a)0m新增文章 1m(g)0m新增目錄 ^[[31m(e)0m編輯檔案 \ m" : "4;46m 【功\能鍵】 1;47m (h)0m說明 1m(q/←)0m離開 \ 1m(k↑j↓)0m移動游標 1m(enter/→)0m讀取資料 m"); } /*-------------------------------------------------------*/ #include <netinet/in.h> #include <sys/socket.h> #include <netdb.h> FILE * go_cmd(node, sock) ITEM *node; int *sock; { struct sockaddr_in sin; struct hostent *host; struct in_addr addr; /* u_long */ char *site; FILE *fp; *sock = socket(AF_INET, SOCK_STREAM, 0); if (*sock < 0) { perror("ERROR(get socket)"); return NULL; } (void) memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(node->X.G.port); host = gethostbyname(site = node->X.G.server); if (host == NULL) sin.sin_addr.s_addr = inet_addr(site); else (void) memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length); if (connect(*sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { perror("ERROR(connect)"); return NULL; } fp = fdopen(*sock, "r+"); if (fp != NULL) { setbuf(fp, (char *) 0); fprintf(fp, "%s\r\n", node->X.G.path); fflush(fp); } else close(*sock); return fp; } char * nextfield(data, field) register char *data, *field; { register int ch; while (ch = *data) { data++; if ((ch == '\t') || (ch == '\r' && *data == '\n')) break; *field++ = ch; } *field = '\0'; return data; } FILE* my_open(char* path) { FILE* ans = 0; char buf[80]; struct stat st; time_t now = time(0); if (stat(path, &st) == 0 && st.st_mtime < now - 3600 * 24 * 7) { /* woju getdata(b_lines - 1, 0, "已超過一星期沒更新,是否更新資料(Y/N)?[Y] ", buf, 4, LCECHO, 0); if (*buf != 'n') */ return fopen(path, "w"); } if (ans = fopen(path, "r+")) { fclose(ans); return 0; /* return directly due to currutmp->pager > 1 mode (real copy) */ fgets(buf, 80, ans); if (!strncmp(buf, str_author1, strlen(str_author1)) || *buf == '0' || *buf == '1') { fclose(ans); return 0; } rewind(ans); } else ans = fopen(path, "w"); return ans; } static jmp_buf jbuf; static void isig(sig) int sig; { longjmp(jbuf, 1); } go_proxy(char* fpath, ITEM *node, int update) { struct stat st; char *ptr, *str, *server; int ch, mode; FILE* fo; pid_t pid; #define PROXY_HOME "proxy/" strcpy(fpath, PROXY_HOME); ptr = fpath + sizeof(PROXY_HOME) - 1; str = server = node->X.G.server; while (ch = *str) { str++; if (ch == '.') { if (!strcmp(str, "edu.tw")) break; } else if ( ch >= 'A' && ch <= 'Z') { ch |= 0x20; } *ptr++ = ch; } *ptr = '\0'; mkdir(fpath, 0755); *ptr++ = '/'; str = node->X.G.path; while (ch = *str) { str++; if (ch == '/') { ch = '.'; } *ptr++ = ch; } *ptr = '\0'; /* expire proxy data */ if (fo = update ? fopen(fpath, "w") : my_open(fpath)) { FILE *fp; char buf[512]; int sock; if (fo == NULL) return; outmsg("★ 建立 proxy 資料連線中 ... "); refresh(); sock = -1; if (setjmp(jbuf)) { /* reset_tty();*/ if (sock != -1) close(sock); fseek(fo, 0, SEEK_SET); fwrite("", 0, 0, fo); fclose(fo); alarm(0); return; } signal(SIGALRM, isig); alarm(5); fp = go_cmd(node, &sock); alarm(0); str = node->title; ch = str[1]; if (ch == (char) 0xbc && !(HAS_PERM(PERM_SYSOP) && currutmp->pager > 1)) { time_t now; time(&now); fprintf(fo, "作者: %s (連線精華區)\n標題: %s\n時間: %s\n", server, str + 3, ctime(&now) ); } while (fgets(buf, 511, fp)) { if (!strcmp(buf, ".\r\n")) break; if (ptr = strstr(buf, "\r\n")) strcpy(ptr, "\n"); fputs(buf, fo); } fclose(fo); fclose(fp); } } g_additem(GMENU *pm, ITEM *myitem) { if (pm->num < MAXITEMS) { ITEM *newitem = (ITEM *) malloc(sizeof(ITEM)); memcpy(newitem, myitem, sizeof(ITEM)); pm->item[(pm->num)++] = newitem; } } go_menu(GMENU *pm, ITEM *node, int update) { FILE *fp; char buf[512], *ptr, *title; ITEM item; int ch; go_proxy(buf, node, update); pm->num = 0; if (fp = fopen(buf, "r")) { title = item.title; while (fgets(buf, 511, fp)) { ptr = buf; ch = *ptr++; if (ch != '0' && ch != '1') continue; strcpy(title, "□ "); if (ch == '1') title[1] = (char) 0xbd; ptr = nextfield(ptr, title + 3); if (!*ptr) continue; title[sizeof(item.title) - 1] = '\0'; ptr = nextfield(ptr, item.X.G.path); if (!*ptr) continue; ptr = nextfield(ptr, item.X.G.server); if (!*ptr) continue; nextfield(ptr, buf); item.X.G.port = atoi(buf); g_additem(pm, &item); } fclose(fp); } } g_searchtitle(GMENU* pm, int rev) { static char search_str[30]=""; int pos; if (getdata(b_lines - 1, 1,"[搜尋]關鍵字:", search_str, 40, DOECHO, 0)) 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 (strstr_lower(pm->item[pos]->title, search_str)) return pos; } while (pos != pm->now); return pm->now; } g_showhelp() { clear(); outs("6m【 " BOARDNAME "連線精華區使用說明 】m\n\n\ [←][q] 離開到上一層目錄\n\ [↑][k] 上一個選項\n\ [↓][j] 下一個選項\n\ [→][r][enter] 進入目錄/讀取文章\n\ [b][PgUp] 上頁選單\n\ [^F][PgDn][Spc] 下頁選單\n\ [##] 移到該選項\n\ [^S] 將文章存到信箱\n\ [R] 更新資料\n\ [N] 查詢檔名\n\ [c][C][^C] 拷貝文章/並跳至上次貼文章的地方/直接貼到上次貼的地方\n"); pressanykey(); } gem(char* maintitle, ITEM* path, int update) { GMENU me; int ch; char fname[PATHLEN]; strncpy(me.mtitle, maintitle, 40); me.mtitle[40] = 0; go_menu(&me, path, update); /* 精華區-tree 中部份結構屬於 cuser ==> BM */ me.level = 0; me.page = 9999; me.now = 0; for (;;) { if (me.now >= me.num && me.num > 0) me.now = me.num - 1; else if (me.now < 0) me.now = 0; if (me.now < me.page || me.now >= me.page + p_lines) { me.page = me.now - (me.now % p_lines); g_showmenu(&me); } ch = cursor_key(2 + me.now - me.page, 0); if (ch == 'q' || ch == 'Q' || ch == KEY_LEFT) break; if (ch >= '0' && ch <= '9') { if ((ch = search_num(ch, me.num)) != -1) me.now = ch; me.page = 9999; 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 '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 'h': g_showhelp(); me.page = 9999; break; case '?': case '/': me.now = g_searchtitle(&me, ch == '?'); me.page = 9999; break; case 'N': if (HAS_PERM(PERM_SYSOP)) { go_proxy(fname, me.item[me.now], 0); move(b_lines - 1, 0); outs(fname); pressanykey(); me.page = 9999; } break; case 'c': case 'C': case Ctrl('C'): if (me.now < me.num) { ITEM *node = me.item[me.now]; char *title = node->title; int mode = title[1]; load_paste(); if (mode == (char) 0xbc || ch == Ctrl('C')) { struct stat st; if (mode == (char) 0xbc) go_proxy(fname, node, 0); if (ch == Ctrl('C') && *paste_path && paste_level) { char newpath[PATHLEN]; fileheader item; strcpy(newpath, paste_path); if (mode == (char) 0xbc) { stampfile(newpath, &item); unlink(newpath); Link(fname, newpath); } else stampdir(newpath, &item); strcpy(item.owner, cuser.userid); sprintf(item.title, "%s%.72s", (currutmp->pager > 1) ? "" : (mode == (char) 0xbc) ? "◇ " : "◆ ", title + 3); strcpy(strrchr(newpath, '/') + 1, ".DIR"); append_record(newpath, &item, FHSZ); if (++me.now >= me.num) me.now = 0; break; } if (mode == (char) 0xbc) { a_copyitem(fname, title + ((currutmp->pager > 1) ? 3 :0), 0); if (ch == 'C' && *paste_path) a_menu(paste_title, paste_path, paste_level); me.page = 9999; } else bell(); } } break; /* woju */ case Ctrl('R'): if (currutmp->msgs[0].last_pid) { show_last_call_in(); my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); me.page = 9999; } break; case KEY_ESC: if (KEY_ESC_arg == 'n') { edit_note(); me.page = 9999; } break; case Ctrl('U'): t_users(); me.page = 9999; break; case Ctrl('B'): m_read(); me.page = 9999; break; case Ctrl('I'): t_idle(); me.page = 9999; break; case 's': AnnounceSelect(); me.page = 9999; break; case '\n': case '\r': case KEY_RIGHT: case 'r': case 'R': if (me.now < me.num) { ITEM *node = me.item[me.now]; char *title = node->title; int mode = title[1]; int update = (ch == 'R') ? 1 : 0; title += 3; if (mode == (char) 0xbc) { int more_result; go_proxy(fname, node, update); strcpy(vetitle, title); while (more_result = more(fname, YEA)) { if (more_result == 1) { if (--me.now < 0) { me.now = 0; break; } } else if (more_result == 3) { if (++me.now >= me.num) { me.now = me.num - 1; break; } } else break; node = me.item[me.now]; if (node->title[1] != (char) 0xbc) break; go_proxy(fname, node, update); strcpy(vetitle, title); } } else if (mode == (char) 0xbd) { gem(title, node, update); } me.page = 9999; } break; } } for (ch = 0; ch < me.num; ch++) free(me.item[ch]); } static void a_timestamp(buf, time) char *buf; time_t *time; { struct tm *pt = localtime(time); sprintf(buf, "%02d/%02d/%02d", pt->tm_mon + 1, pt->tm_mday, pt->tm_year); } static void a_additem(pm, myheader) MENU *pm; fileheader *myheader; { char buf[PATHLEN]; setadir(buf, pm->path); if (append_record(buf, myheader, FHSZ) == -1) return; pm->now = pm->num++; } static void a_loadname(pm) MENU *pm; { char buf[PATHLEN]; int len; setadir(buf, pm->path); len = get_records(buf, pm->header, FHSZ, pm->page+1, p_lines); if (len < p_lines) bzero(&pm->header[len], FHSZ*(p_lines-len)); } void atitle() { showtitle("精華文章", a_title); outs("\ [←]離開 [→]閱\讀 [^P]發表文章 [b]備忘錄 [d]刪除 [q]精華區 [TAB]文摘 [h]elp\n\ 7m 編號 日 期 作 者 文 章 標 題\ m"); } void adoent(num, ent) int num; fileheader *ent; { char *mark, *title, color; int type; time_t dtime; char buf[PATHLEN]; if (ent->filemode & FILE_TAGED) type = 'D'; else type = ' '; title = subject(mark = ent->title); if (title == mark) { color = '1'; mark = "□"; } else { color = '3'; mark = "R:"; } if (title[47]) strcpy(title + 44, " …"); /* 把多餘的 string 砍掉 */ sprintf(buf,"%s/%s","",ent->filename); /* Ptt 此處time會有問題*/ dtime = dasht(buf); a_timestamp(buf, &dtime); buf[5] = 0; if (strncmp(currtitle, title, 40)) prints("%6d %c %-7s%-13.12s%s %s\n", num, type, buf, ent->owner, mark, title); else prints("%6d %c %-7s%-13.12s;3%cm%s %s0m\n", num, type, buf, ent->owner, color, mark, title); } static void a_showmenu(pm) MENU *pm; { char *title, *editor; int n; fileheader *item; char buf[PATHLEN]; time_t dtime; showtitle("精華文章", pm->mtitle); prints(" ;36m編號 標 題%56s0m", "編 選 日 期"); if (pm->num) { setadir(buf, pm->path); a_loadname(pm); for (n = 0; n < p_lines && pm->page + n < pm->num; n++) { item = &pm->header[n]; title = item->title; editor = item->owner; /* Ptt 把時間改為取檔案時間 dtime = atoi(&item->filename[2]); */ sprintf(buf,"%s/%s",pm->path,item->filename); dtime = dasht(buf); a_timestamp(buf, &dtime); prints("\n%6d. %-47.46s%-13s[%s]", pm->page+n+1, title, editor, buf); } } else { outs("\n 《精華區》尚在吸取天地間的日月精華中... :)"); } move(b_lines, 1); outs(pm->level ? "4;46m 【板 主】 1;47m (h)0m說明 1m(q/←)0m離開 1m(a)0m新增文章 1m(g)0m新增目錄 1m(e)0m編輯檔案 0m" : "4;46m 【功\能鍵】 1;47m (h)0m說明 1m(q/←)0m離開 1m(k↑j↓)0m移動游標 1m(enter/→)0m讀取資料 0m"); } static void a_showhelp(level) int level; { clear(); outs("6m【 " BOARDNAME "公佈欄使用說明 】m\n\n\ [←][q] 離開到上一層目錄\n\ [↑][k] 上一個選項\n\ [↓][j] 下一個選項\n\ [→][r][enter] 進入目錄/讀取文章\n\ [^B][PgUp] 上頁選單\n\ [^F][PgDn][Spc] 下頁選單\n\ [##] 移到該選項\n\ [F][U] 將文章寄回 Internet 郵箱/將文章 uuencode 後寄回郵箱\n\ [c] 拷貝文章 (若無板主權, 不能粘貼文章, 小板主可利用此鍵轉貼)\n"); if (level >= MANAGER) { outs("\n6m【 板主專用鍵 】m\n\ [n/g/G] 收錄精華文章/開闢目錄/建立連線\n\ [m/d] 移動/刪除文章\n\ [t/e] 修改文章標題/內容\n\ [c/p/a] 拷貝/粘貼/附加文章\n"); } if (level >= SYSOP) { outs("\n6m【 站長專用鍵 】m\n\ [f] 編輯標題符號\n\ [l] 建 symbolic link\n\ [N] 查詢檔名\n"); } pressanykey(); } static void a_moveitem(pm) MENU *pm; { fileheader *tmp; char newnum[4]; int num, max, min; char buf[PATHLEN]; int fail; sprintf(buf, "請輸入第 %d 選項的新次序:", pm->now + 1); if (!getdata(b_lines - 1, 1, buf, newnum, 6, 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 *) 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_delete(pm) MENU *pm; { char fpath[PATHLEN], buf[PATHLEN]; char ans[4]; sprintf(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, 3, 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, 3, 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, 3, LCECHO); if (ans[0] != 'y') return; if (delete_record(buf, FHSZ, pm->now + 1) == -1) return; unlink(fpath); } else if (dashd(fpath)) { getdata(b_lines - 1, 1, "您確定要刪除整個目錄嗎(A/N)?[N] ", ans, 3, LCECHO); if (ans[0] != 'a') return; if (delete_record(buf, FHSZ, pm->now + 1) == -1) return; sprintf(buf, "/bin/rm -rf %s", fpath); system(buf); } else /* Ptt 損毀的項目 */ { getdata(b_lines - 1, 1, "您確定要刪除此損毀的項目嗎(Y/N)?[N] " , ans, 3, LCECHO); if (ans[0] != 'y') return; if (delete_record(buf, FHSZ, pm->now + 1) == -1) return; } pm->num--; } load_paste() { struct stat st; FILE* fp; if (!*paste_fname) setuserfile(paste_fname, "paste_path"); if (stat(paste_fname, &st) == 0 && st.st_mtime > paste_time && (fp = fopen(paste_fname, "r"))) { int i; fgets(paste_path, PATHLEN, fp); i = strlen(paste_path) - 1; if (paste_path[i] == '\n') paste_path[i] = 0; fgets(paste_title, STRLEN, fp); i = strlen(paste_title) - 1; if (paste_title[i] == '\n') paste_title[i] = 0; fscanf(fp, "%d", &paste_level); paste_time = st.st_mtime; fclose(fp); } } static void a_pasteitem(pm) MENU *pm; { char newpath[PATHLEN]; char buf[PATHLEN]; char ans[2]; int i; fileheader item; move(b_lines - 1, 1); if (copyfile[0]) { if (dashd(copyfile)) { for (i = 0; copyfile[i] && copyfile[i] == pm->path[i]; i++); if (!copyfile[i]) { outs("將目錄拷進自己的子目錄中,會造成無窮迴圈!"); igetch(); return; } } sprintf(buf, "確定要拷貝[%s]嗎(Y/N)?[N] ", copytitle); getdata(b_lines - 1, 1, buf, ans, 3, LCECHO); if (ans[0] == 'y') { strcpy(newpath, pm->path); if (*copyowner) { char* fname = strrchr(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)); strcpy(item.filename, fname + 1); memcpy(copytitle, "◎", 2); if (HAS_PERM(PERM_BBSADM)) Link(copyfile, newpath); else { sprintf(buf, "/bin/cp %s %s", copyfile, newpath); system(buf); } } else if (dashf(copyfile)) { stampfile(newpath, &item); memcpy(copytitle, "◇", 2); sprintf(buf, "/bin/cp %s %s", copyfile, newpath); } else if (dashd(copyfile)) { stampdir(newpath, &item); memcpy(copytitle, "◆", 2); sprintf(buf, "/bin/cp -r %s/* %s/.D* %s", copyfile, copyfile, newpath); } else { outs("無法拷貝!"); igetch(); return; } strcpy(item.owner, *copyowner ? copyowner : cuser.userid); strcpy(item.title, copytitle); if (!*copyowner) system(buf); a_additem(pm, &item); copyfile[0] = '\0'; } } else { outs("請先執行 copy 命令後再 paste"); igetch(); } } static void a_appenditem(pm) MENU *pm; { char newpath[PATHLEN]; char fname[PATHLEN]; char buf[ANSILINELEN]; char ans[2]; int i; fileheader item; FILE *fp, *fin; move(b_lines - 1, 1); if (copyfile[0]) { if (dashf(copyfile)) { sprintf(fname, "%s/%s", pm->path, pm->header[pm->now-pm->page].filename); if (dashf(fname)) { sprintf(buf, "確定要將[%s]附加於此嗎(Y/N)?[N] ", copytitle); getdata(b_lines - 2, 1, buf, ans, 3, LCECHO); if (ans[0] == 'y') { if (fp = fopen(fname, "a+")) { if (fin = fopen(copyfile, "r")) { memset(buf, '-', 74); buf[74] = '\0'; fprintf(fp, "\n> %s <\n\n", buf); getdata(b_lines - 1, 1, "是否收錄簽名檔部份(Y/N)?[Y] ", ans, 3, LCECHO); while (fgets(buf, sizeof(buf), fin)) { if ((ans[0] == 'n' || ans[0] == 'N') && !strcmp(buf, "--\n")) break; fputs(buf, fp); } fclose(fin); copyfile[0] = '\0'; } fclose(fp); } } } else { outs("檔案不得附加於此!"); igetch(); } } else { outs("不得附加整個目錄於檔案後!"); igetch(); } } else { outs("請先執行 copy 命令後再 append"); igetch(); } } static void a_forward(path, pitem, mode) char *path; fileheader *pitem; int mode; { fileheader fhdr; strcpy(fhdr.filename, pitem->filename); strcpy(fhdr.title, pitem->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; } } /* woju, mgtsai */ static int a_searchtitle(pm, rev) MENU *pm; int rev; { static char search_str[40]=""; int pos; getdata(b_lines - 1, 1, "[搜尋]關鍵字:", search_str, 40, 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; a_loadname(pm); } if (strstr_lower(pm->header[pos - pm->page].title, search_str)) return pos; } while (pos != pm->now); return pm->now; } /* ===== Added by mgtsai, Sep 10th, '96 ===== */ static void a_newtitle(pm) MENU *pm; { char buf[PATHLEN]; fileheader item; if (getdata(b_lines - 1, 1, "新標題:", buf, 60, DOECHO)) { memcpy(&item, &pm->header[pm->now - pm->page], FHSZ); strcpy(item.title + 3, buf); setadir(buf, pm->path); substitute_record(buf, &item, FHSZ, pm->now + 1); } } static void a_editsign(pm) MENU *pm; { char buf[PATHLEN]; fileheader item; memcpy(&item, &pm->header[pm->now - pm->page], FHSZ); sprintf(buf, "符號[%c%c]:", item.title[0], item.title[1]); if (getdata(b_lines - 1, 1, buf, 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(pm) MENU *pm; { char buf[PATHLEN]; int len; int i; int sym; move(b_lines - 1, 1); sprintf(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 (HAS_PERM(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) { pressanykey(); move(b_lines - 1, 1); prints("此 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(); } static void a_newitem(pm, mode) MENU *pm; { static char *mesg[4] = { "[新增文章] 請輸入標題:", /* ADDITEM */ "[新增目錄] 請輸入標題:", /* ADDGROUP */ "[新增連線] 請輸入標題:", /* ADDGOPHER */ "請輸入標題:"}; /* ADDLINK */ char fpath[PATHLEN], buf[PATHLEN], lpath[PATHLEN]; fileheader item; time_t dtime; int s, d; strcpy(fpath, pm->path); switch (mode) { case ADDITEM: stampfile(fpath, &item); strcpy(item.title, "◇ "); /* A1BA */ break; case ADDGROUP: stampdir(fpath, &item); strcpy(item.title, "◆ "); /* A1BB */ break; case ADDGOPHER: bzero(&item, sizeof(item)); strcpy(item.title, "⊙ "); /* A1BB */ if (!getdata(b_lines - 2, 1, "輸入URL位址:",item.filename+2,61, DOECHO)) return; break; case ADDLINK: stamplink(fpath, &item); if (!getdata(b_lines - 2, 1, "新增連線:", buf, 61, DOECHO)) return; /* for (s = 0; buf[s] == '/'; s++); for (d = 0; buf[s]; s++, d++) { buf[d] = buf[s]; if (buf[s] == '/') for (; buf[s+1] == '/' || buf[s+1] == '.'; s++); } buf[d] = buf[s]; */ if (invalid_pname(buf)) { unlink(fpath); outs("目的地路徑不合法!"); igetch(); return; } item.title[0]=0; for(d=0;d<=3;d++) { switch(d) { case 0: sprintf(lpath, "%s%s%s/%s", BBSHOME, "/man/boards/",currboard , buf); break; case 1: sprintf(lpath, "%s%s%s", BBSHOME, "/man/boards/" , buf); break; case 2: sprintf(lpath, "%s%s%s", BBSHOME, "/" , buf); break; case 3: sprintf(lpath, "%s%s%s", BBSHOME, "/etc/" , buf); break; } if (dashf(lpath)) { strcpy(item.title, "☆ "); /* A1B3 */ break; } else if (dashd(lpath)) { strcpy(item.title, "★ "); /* A1B4 */ break; } if (!HAS_PERM(PERM_BBSADM) && d==1 ) break; } if (!item.title[0]) { unlink(fpath); outs("目的地路徑不合法!"); igetch(); return; } } if (!getdata(b_lines - 1, 1, mesg[mode], &item.title[3], 55, DOECHO)) { if (mode == ADDGROUP) rmdir(fpath); else if (mode != ADDGOPHER) unlink(fpath); return; } switch (mode) { case ADDITEM: if (vedit(fpath, 0) == -1) { unlink(fpath); pressanykey(); return; } break; case ADDLINK: unlink(fpath); if (symlink(lpath, fpath) == -1) { outs("無法建立 symbolic link"); igetch(); return; } break; case ADDGOPHER: strcpy(item.date, "70"); strncpy(item.filename, "H.",2); break; } strcpy(item.owner, cuser.userid); a_additem(pm, &item); } a_copyitem(char* fpath, char* title, char* owner) { strcpy(copyfile, fpath); strcpy(copytitle, title); if (owner) strcpy(copyowner, owner); else *copyowner = 0; outmsg("檔案標記完成。[注意] 拷貝後才能刪除原文!"); igetch(); } /* ===== end ===== */ a_menu(maintitle, path, lastlevel) char *maintitle; char *path; int lastlevel; { static char Fexit; MENU me; char fname[PATHLEN]; int ch; extern struct one_key read_comms[]; trans_buffer[0]=0; if(strstr(path,"etc/editexp")) { setutmpmode(EDITEXP); } else { setutmpmode(ANNOUNCE); } Fexit=0; me.header = (fileheader *) calloc(p_lines, FHSZ); me.path = path; strcpy(me.mtitle, maintitle); setadir(fname, me.path); me.num = get_num_records(fname, FHSZ); /* 精華區-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 + p_lines) { me.page = me.now - ((me.page == 10000 && me.now > p_lines / 2) ? (p_lines / 2) : (me.now % p_lines)); a_showmenu(&me); } 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 '/': 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; /* woju */ case Ctrl('R'): if (currutmp->msgs[0].last_pid) { show_last_call_in(); my_write(currutmp->msgs[0].last_pid, "水球丟回去:"); me.page = 9999; } break; case Ctrl('C'): cal(); me.page = 9999; break; case KEY_ESC: if (KEY_ESC_arg == 'n') { edit_note(); me.page = 9999; } break; case Ctrl('U'): t_users(); me.page = 9999; break; case Ctrl('I'): t_idle(); me.page = 9999; break; case 's': AnnounceSelect(); me.page = 9999; break; case 'e': case 'E': sprintf(fname, "%s/%s", path, me.header[me.now-me.page].filename); if (dashf(fname)) { *quote_file = 0; if (vedit(fname, (me.level >= MANAGER) ? 0 : 2) != -1) { char fpath[200]; fileheader fhdr; strcpy(fpath, path); stampfile(fpath, &fhdr); unlink(fpath); Rename(fname, fpath); strcpy(me.header[me.now-me.page].filename, fhdr.filename); strcpy(me.header[me.now-me.page].owner, cuser.userid); setadir(fpath, path); substitute_record(fpath, me.header+me.now-me.page, sizeof(fhdr), me.now + 1); } me.page = 9999; } break; case 'c': if (me.now < me.num) { sprintf(fname, "%s/%s", path, me.header[me.now-me.page].filename); a_copyitem(fname, me.header[me.now-me.page].title, 0); me.page = 9999; break; } case '\n': case '\r': case KEY_RIGHT: case 'r': if (me.now < me.num) { fileheader *fhdr = &me.header[me.now-me.page]; sprintf(fname, "%s/%s", path, fhdr->filename); if (*fhdr->filename == 'H' && fhdr->filename[1] == '.') { ITEM item; strcpy(item.X.G.server, fhdr->filename + 2); strcpy(item.X.G.path, "1/"); item.X.G.port = 70; gem(fhdr->title, &item, (ch == 'R') ? 1 : 0); } else if (dashf(fname)) { int more_result; while (more_result = more(fname, YEA)) { /*Ptt 範本精靈plugin*/ char tes[10]; if(strstr(fname,"etc/editexp/")) { char ans[4]; move(22, 0); clrtoeol(); getdata(22, 1, "要把範例 Plugin 到文章嗎?[y/N]", ans, 3, LCECHO); if(ans[0]=='y') { strcpy(trans_buffer,fname); Fexit = 1; free(me.header); return; } } if (more_result == 1) { if (--me.now < 0) { me.now = 0; break; } } else if (more_result == 3) { if (++me.now >= me.num) { me.now = me.num - 1; break; } } else break; sprintf(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); /* Ptt */ /* 強力跳出recursive */ if (Fexit) { free(me.header); return; } } me.page = 9999; } break; case 'F': case 'U': case 'Z': sprintf(fname, "%s/%s", path, me.header[me.now-me.page].filename); if (me.now < me.num && HAS_PERM(PERM_BASIC) && dashf(fname)) { if (ch == 'Z') z_download(fname); else a_forward(path, &me.header[me.now-me.page], ch == 'U'); } else outmsg("無法轉寄此項目"); me.page = 9999; refresh(); sleep(1); break; } if (me.level >= MANAGER) { int page0 = me.page; switch (ch) { case 'n': a_newitem(&me, ADDITEM); me.page = 9999; break; case 'g': a_newitem(&me, ADDGROUP); me.page = 9999; break; case 'G': a_newitem(&me, ADDGOPHER); me.page = 9999; break; case 'p': a_pasteitem(&me); me.page = 9999; break; case 'a': a_appenditem(&me); me.page = 9999; break; default: me.page = page0; break; } if (me.num) switch (ch) { case 'm': a_moveitem(&me); me.page = 9999; break; case 'D': me.page = -1; case 'd': a_delete(&me); me.page = 9999; break; case 't': a_newtitle(&me); me.page = 9999; break; } } if (me.level == SYSOP) { switch (ch) { case 'f': a_editsign(&me); me.page = 9999; break; case 'l': a_newitem(&me, ADDLINK); me.page = 9999; break; case 'N': a_showname(&me); me.page = 9999; break; case 'B': setadir(fname, me.path); a_title = maintitle; i_read(0, fname, atitle, adoent, read_comms); me.page = 9999; break; } } } free(me.header); } AnnounceSelect() { static char xboard[20]; char buf[20]; char fpath[256]; boardheader *bp; boardheader *getbcache(); move(2, 0); clrtoeol(); move(3, 0); clrtoeol(); move(1, 0); make_blist(); namecomplete("選擇精華區看板:", buf); if (*buf) strcpy(xboard, buf); if (*xboard && (bp = getbcache(xboard))) { setapath(fpath, xboard); a_menu(xboard, fpath, (HAS_PERM(PERM_ALLBOARD) || HAS_PERM(PERM_BM) && is_BM(bp->BM)) ? 1 : 0); } return FULLUPDATE; } int Announce() { a_menu(mytitle, "man", ((HAS_PERM(PERM_SYSOP) || HAS_PERM(PERM_ANNOUNCE)) ? SYSOP : NOBODY)); return 0; }