/*-------------------------------------------------------*/
/* 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;
}