/*-------------------------------------------------------*/
/* mail.c ( NTHU CS MapleBBS Ver 2.36 ) */
/*-------------------------------------------------------*/
/* target : local/internet mail routines */
/* create : 95/03/29 */
/* update : 95/12/15 */
/*-------------------------------------------------------*/
#include "bbs.h"
extern int del_range();
extern int cmpfmode();
char currmaildir[32];
static char msg_cc[] = "[群組名單]\n";
static char listfile[] = "list.0";
int
setforward() /* Ptt */
{
char buf[80],ip[50]="",yn[4];
FILE *fp;
sethomepath(buf, cuser.userid);
strcat(buf,"/.forward");
if(fp = fopen(buf,"r"))
{
fscanf(fp,"%s",ip);
fclose(fp);
}
getdata_buf(b_lines-1,0,"請輸入信箱自動轉寄的email地址:",ip,41, DOECHO);
if(ip[0] && ip[0] != ' ')
{
getdata(b_lines,0,"確定開啟自動轉信功\能?(Y/n)",yn,3,
LCECHO);
if(yn[0] != 'n' && (fp=fopen(buf,"w")))
{
move(b_lines,0);
clrtoeol();
fprintf(fp,"%s",ip);
fclose(fp);
outs("設定完成!");
refresh();
sleep(1);
return 0;
}
}
move(b_lines,0);
clrtoeol();
outs("取消自動轉信!");
unlink(buf);
refresh();
sleep(1);
return 0;
}
#ifdef INTERNET_PRIVATE_EMAIL
int
invalidaddr(addr)
char *addr;
{
if (*addr == '\0')
return 1; /* blank */
while (*addr)
{
if (not_alnum(*addr) && !strchr("[].%!@:-_;", *addr))
return 1;
addr++;
}
return 0;
}
int
m_internet()
{
char receiver[60];
getdata(20, 0, "收信人:", receiver, 60, DOECHO);
if (strchr(receiver, '@') && !invalidaddr(receiver) &&
getdata(21, 0, "主 題:", save_title, TTLEN, DOECHO))
{
do_send(receiver, save_title);
}
else
{
move(22, 0);
outs("收信人或主題不正確, 請重新選取指令");
pressanykey();
}
return 0;
}
#endif
void
m_init()
{
sethomedir(currmaildir, cuser.userid);
}
int
chkmailbox(void)
{
if (!HAVE_PERM(PERM_SYSOP) && !HAVE_PERM(PERM_MAILLIMIT))
{
int keep, sum;
int sumlimit;
if (HAS_PERM(PERM_BM))
sumlimit = 300;
else if (HAS_PERM(PERM_LOGINOK))
sumlimit = 150;
else
sumlimit = 100;
m_init();
if ((keep = get_num_records(currmaildir, sizeof(fileheader))) > MAXKEEPMAIL)
{
move(b_lines, 0);
clrtoeol();
bell();
prints("您保存信件數目 %d 超出上限 %d, 請整理", keep, MAXKEEPMAIL);
bell();
refresh();
igetch();
return keep;
}
if ((sum = get_sum_records(currmaildir, sizeof(fileheader))) > sumlimit)
{
move(b_lines, 0);
clrtoeol();
bell();
prints("您保存信件容量 %d(k)超出上限 %d(k), 請整理", sum, sumlimit);
bell();
refresh();
igetch();
return keep;
}
}
return 0;
}
static void
do_hold_mail(fpath, receiver, holder)
char *fpath;
char *receiver;
char *holder;
{
char buf[80], title[128];
fileheader mymail;
sethomepath(buf, holder);
stampfile(buf, &mymail);
mymail.savemode = 'H'; /* hold-mail flag */
mymail.filemode = FILE_READ;
strcpy(mymail.owner, "[備.忘.錄]");
if (receiver)
{
sprintf(title, "(%s) %s", receiver, save_title);
strncpy(mymail.title, title, TTLEN);
}
else
strcpy(mymail.title, save_title);
sethomedir(title, holder);
if (append_record(title, &mymail, sizeof(mymail)) != -1)
{
unlink(buf);
Link(fpath, buf);
}
}
void
hold_mail(fpath, receiver)
char *fpath;
char *receiver;
{
char buf[4];
getdata(b_lines - 1, 0, "已順利寄出,是否自存底稿(Y/N)?[N] ", buf, 4, LCECHO);
if (buf[0] == 'y')
do_hold_mail(fpath, receiver, cuser.userid);
if (is_watched(cuser.userid))
do_hold_mail(fpath, receiver, "SYSOP");
}
int
do_send(userid, title)
char *userid, *title;
{
fileheader mhdr;
struct stat st;
char fpath[STRLEN], buf[80], *ip;
char receiver[IDLEN];
int fp;
char genbuf[200];
#ifdef INTERNET_PRIVATE_EMAIL
int internet_mail;
if (strchr(userid, '@'))
{
internet_mail = 1;
}
else
{
internet_mail = 0;
#endif
if (!getuser(userid))
return -1;
if (!(xuser.userlevel & PERM_READMAIL))
return -3;
if (!title)
getdata(2, 0, "主題:", save_title, TTLEN, DOECHO);
curredit |= EDIT_MAIL;
#ifdef INTERNET_PRIVATE_EMAIL
}
#endif
setutmpmode(SMAIL);
fpath[0] = '\0';
#ifdef INTERNET_PRIVATE_EMAIL
if (internet_mail)
{
int res, ch;
if (vedit(fpath, NA) == -1)
{
unlink(fpath);
clear();
return -2;
}
clear();
prints("信件即將寄給 %s\n標題為:%s\n確定要寄出嗎? (Y/N) [Y]",
userid, title);
ch = igetch();
switch (ch)
{
case 'N':
case 'n':
outs("N\n信件已取消");
res = -2;
break;
default:
outs("Y\n請稍候, 信件傳遞中...\n");
res = bbs_sendmail(fpath, title, userid);
hold_mail(fpath, userid);
}
unlink(fpath);
return res;
}
else
{
#endif
strcpy(receiver, userid);
if (vedit(fpath, YEA) == -1)
{
unlink(fpath);
clear();
return -2;
}
clear();
strcpy(userid, receiver);
sethomepath(genbuf, userid);
stampfile(genbuf, &mhdr);
Rename(fpath, genbuf);
strcpy(mhdr.owner, cuser.userid);
strncpy(mhdr.title, save_title, TTLEN);
mhdr.savemode = '\0';
sethomedir(fpath, userid);
if (append_record(fpath, &mhdr, sizeof(mhdr)) == -1)
return -1;
hold_mail(genbuf, userid);
return 0;
#ifdef INTERNET_PRIVATE_EMAIL
}
#endif
}
void
my_send(uident)
char *uident;
{
switch (do_send(uident, NULL))
{
case -1:
outs(err_uid);
break;
case -2:
outs(msg_cancel);
break;
case -3:
prints("使用者 [%s] 無法收信", uident);
break;
}
pressanykey();
}
int
m_send()
{
char uident[40];
stand_title("且聽風的話");
usercomplete(msg_uid, uident);
if (uident[0])
my_send(uident);
return 0;
}
/* ------------------------------------------------------------ */
/* 群組寄信、回信 : multi_send, multi_reply */
/* ------------------------------------------------------------ */
extern struct word *toplev;
static void
multi_list(reciper)
int *reciper;
{
char uid[16];
char genbuf[200];
while (1)
{
stand_title("群組寄信名單");
ShowNameList(3, 0, msg_cc);
getdata(1, 0,
"(I)引入好友 (O)引入上線通知 (N)引入新文章通知 (0-9)引入其他特別名單\n"
"(A)增加 (D)刪除 (M)確認寄信名單 (Q)取消 ?[M]",
genbuf, 4, LCECHO);
switch (genbuf[0])
{
case 'a':
while (1)
{
move(1, 0);
usercomplete("請輸入要增加的代號(只按 ENTER 結束新增): ", uid);
if (uid[0] == '\0')
break;
move(2, 0);
clrtoeol();
if (!searchuser(uid))
outs(err_uid);
else if (!InNameList(uid))
{
AddNameList(uid);
(*reciper)++;
}
ShowNameList(3, 0, msg_cc);
}
break;
case 'd':
while (*reciper)
{
move(1, 0);
namecomplete("請輸入要刪除的代號(只按 ENTER 結束刪除): ", uid);
if (uid[0] == '\0')
break;
if (RemoveNameList(uid))
{
(*reciper)--;
}
ShowNameList(3, 0, msg_cc);
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
listfile[5] = genbuf[0];
genbuf[0] = '1';
case 'i':
setuserfile(genbuf, genbuf[0] == '1' ? listfile : fn_overrides);
ToggleNameList(reciper, genbuf, msg_cc);
break;
case 'o':
setuserfile(genbuf, "alohaed");
ToggleNameList(reciper, genbuf, msg_cc);
break;
case 'n':
setuserfile(genbuf, "postlist");
ToggleNameList(reciper, genbuf, msg_cc);
break;
case 'q':
*reciper = 0;
return;
break;
default:
return;
}
}
}
static int
multi_send(title)
char *title;
{
FILE *fp;
struct word *p;
fileheader mymail;
char fpath[TTLEN], *ptr;
int reciper, listing;
char genbuf[256];
CreateNameList();
listing = reciper = 0;
if (*quote_file)
{
AddNameList(quote_user);
reciper = 1;
fp = fopen(quote_file, "r");
while (fgets(genbuf, 256, fp))
{
if (strncmp(genbuf, "※ ", 3))
{
if (listing)
break;
}
else
{
if (listing)
{
strtok(ptr = genbuf + 3, " \n\r");
do
{
if (searchuser(ptr) && !InNameList(ptr) && strcmp(cuser.userid, ptr))
{
AddNameList(ptr);
reciper++;
}
} while (ptr = (char *) strtok(NULL, " \n\r"));
}
else if (!strncmp(genbuf + 3, "[通告]", 6))
listing = 1;
}
}
ShowNameList(3, 0, msg_cc);
}
multi_list(&reciper);
move(1, 0);
clrtobot();
if (reciper)
{
setutmpmode(SMAIL);
if (title)
{
do_reply_title(2, title);
}
else
{
getdata(2, 0, "主題:", fpath, 64, DOECHO);
sprintf(save_title, "[通告] %s", fpath);
}
setuserfile(fpath, fn_notes);
if (fp = fopen(fpath, "w"))
{
fprintf(fp, "※ [通告] 共 %d 人收件", reciper);
listing = 80;
for (p = toplev; p; p = p->next)
{
reciper = strlen(p->word) + 1;
if (listing + reciper > 75)
{
listing = reciper;
fprintf(fp, "\n※");
}
else
listing += reciper;
fprintf(fp, " %s", p->word);
}
memset(genbuf, '-', 75);
genbuf[75] = '\0';
fprintf(fp, "\n%s\n\n", genbuf);
fclose(fp);
}
curredit |= EDIT_LIST;
if (vedit(fpath, YEA) == -1)
{
unlink(fpath);
curredit = 0;
outs(msg_cancel);
pressanykey();
return;
}
stand_title("寄信中...");
refresh();
listing = 80;
for (p = toplev; p; p = p->next)
{
reciper = strlen(p->word) + 1;
if (listing + reciper > 75)
{
listing = reciper;
outc('\n');
}
else
{
listing += reciper;
outc(' ');
}
outs(p->word);
if (searchuser(p->word) && strcmp(STR_GUEST, p->word) )
sethomepath(genbuf, p->word);
else
continue;
stampfile(genbuf, &mymail);
unlink(genbuf);
Link(fpath, genbuf);
strcpy(mymail.owner, cuser.userid);
strcpy(mymail.title, save_title);
mymail.savemode = 'M'; /* multi-send flag */
sethomedir(genbuf, p->word);
if (append_record(genbuf, &mymail, sizeof(mymail)) == -1)
outs(err_uid);
}
hold_mail(fpath, NULL);
unlink(fpath);
curredit = 0;
}
else
{
outs(msg_cancel);
}
pressanykey();
}
static int
multi_reply(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
if (fhdr->savemode != 'M')
return mail_reply(ent, fhdr, direct);
stand_title("群組回信");
strcpy(quote_user, fhdr->owner);
setuserfile(quote_file, fhdr->filename);
multi_send(fhdr->title);
return 0;
}
int
mail_list()
{
stand_title("群組作業");
multi_send(NULL);
return 0;
}
extern int
bad_user_id(char userid[]);
int
mail_all()
{
FILE *fp;
fileheader mymail;
char fpath[TTLEN];
char genbuf[200];
extern struct UCACHE *uidshm;
int i, unum;
char* userid;
stand_title("給所有使用者的系統通告");
setutmpmode(SMAIL);
getdata(2, 0, "主題:", fpath, 64, DOECHO);
sprintf(save_title, "[系統通告] %s", fpath);
setuserfile(fpath, fn_notes);
if (fp = fopen(fpath, "w")) {
fprintf(fp, "※ [系統通告] 這是封給所有使用者的信\n");
fprintf(fp, "---------------------------------------------------------------------------\n");
fclose(fp);
}
*quote_file = 0;
curredit |= EDIT_MAIL;
if (vedit(fpath, YEA) == -1) {
curredit = 0;
unlink(fpath);
outs(msg_cancel);
pressanykey();
return;
}
curredit = 0;
setutmpmode(MAILALL);
stand_title("寄信中...");
sethomepath(genbuf, cuser.userid);
stampfile(genbuf, &mymail);
unlink(genbuf);
Link(fpath, genbuf);
unlink(fpath);
strcpy(fpath, genbuf);
strcpy(mymail.owner, cuser.userid); /*站長 ID*/
strcpy(mymail.title, save_title);
mymail.savemode = 0;
/* mymail.filemode |= FILE_TAGED; Ptt 公告改成不會mark */
sethomedir(genbuf, cuser.userid);
if (append_record(genbuf, &mymail, sizeof(mymail)) == -1)
outs(err_uid);
for (unum = uidshm->number, i = 0; i < unum; i++) {
if(bad_user_id(uidshm->userid[i])) continue; /* Ptt */
userid = uidshm->userid[i];
if (strcmp(userid, "guest") && strcmp(userid, "new") && strcmp(userid, cuser.userid)) {
sethomepath(genbuf, userid);
stampfile(genbuf, &mymail);
unlink(genbuf);
Link(fpath, genbuf);
strcpy(mymail.owner, cuser.userid);
strcpy(mymail.title, save_title);
mymail.savemode = 0;
/* mymail.filemode |= FILE_MARKED; Ptt 公告改成不會mark */
sethomedir(genbuf, userid);
if (append_record(genbuf, &mymail, sizeof(mymail)) == -1)
outs(err_uid);
sprintf(genbuf, "%*s %5d / %5d", IDLEN + 1, userid, i + 1, unum);
outmsg(genbuf);
refresh();
}
}
return;
}
mail_mbox()
{
char cmd[100];
fileheader fhdr;
sprintf(cmd, "/tmp/%s.tgz", cuser.userid);
sprintf(fhdr.title, "%s 私人資料", cuser.userid);
doforward(cmd, &fhdr, 'Z');
}
/* Ptt 拿掉
int
m_list()
{
int aborted;
char genbuf[4];
getdata(b_lines - 1, 0, "名單檔 (E)編輯 (D)刪除 (Q)取消?[Q] ",
genbuf, 4, LCECHO);
if (genbuf[0] == 'd')
aborted = 1;
else if (genbuf[0] == 'e')
aborted = 2;
else
aborted = 0;
if (aborted)
{
char listpath[64], ans[4];
getdata(b_lines - 1, 0, "請選擇名單 (0-9)?[0] ", ans, 3, DOECHO);
if (ans[0] == '\0')
ans[0] = '0';
if (ans[0] >= '0' && ans[0] <= '9')
{
listfile[5] = ans[0];
setuserfile(listpath, listfile);
if (aborted == 1)
{
if (more(listpath, NA) != -1)
getdata(b_lines - 1, 0, "確定刪除嗎(Y/N)?[N]", ans, 3, LCECHO);
if (*ans == 'y') {
unlink(listpath);
outmsg(msg_del_ok);
}
}
else
{
int reciper;
stand_title("編輯名單");
reciper = 0;
CreateNameList();
LoadNameList(&reciper, listpath, msg_cc);
multi_list(&reciper);
SaveNameList(listpath);
}
}
}
return FULLUPDATE;
}
*/
static int
m_forward(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char uid[STRLEN];
char *t;
FILE *fp;
stand_title("轉達信件");
usercomplete(msg_uid, uid);
if (uid[0] == '\0')
{
return FULLUPDATE;
}
strcpy(quote_user, fhdr->owner);
setuserfile(quote_file, fhdr->filename);
sprintf(save_title, "%.64s (fwd)", fhdr->title);
move(1, 0);
clrtobot();
prints("轉信給: %s\n標 題: %s\n", uid, save_title);
switch (do_send(uid, save_title))
{
case -1:
outs(err_uid);
break;
case -2:
outs(msg_cancel);
break;
case -3:
prints("使用者 [%s] 無法收信", uid);
break;
}
pressanykey();
return FULLUPDATE;
}
/* JhLin: At most 128 mail */
int delmsgs[128];
int delcnt;
int mrd;
static int
read_new_mail(fptr)
fileheader *fptr;
{
static int idc;
char done = NA, delete_it;
char fname[256];
char genbuf[4];
if (fptr == NULL)
{
delcnt = 0;
idc = 0;
return 0;
}
idc++;
if (fptr->filemode)
return 0;
clear();
move(10, 0);
prints("您要讀來自[%s]的訊息(%s)嗎?", fptr->owner, fptr->title);
getdata(11, 0, "請您確定(Y/N/Q)?[Y] ", genbuf, 3, DOECHO);
if (genbuf[0] == 'q')
return QUIT;
if (genbuf[0] == 'n')
return 0;
setuserfile(fname, fptr->filename);
fptr->filemode |= FILE_READ;
if (substitute_record(currmaildir, fptr, sizeof(*fptr), idc))
return -1;
mrd = 1;
delete_it = NA;
while (!done)
{
int more_result = more(fname, YEA);
switch (more_result) {
case 1:
return READ_PREV;
case 2:
return RELATE_PREV;
case 3:
return READ_NEXT;
case 4:
return RELATE_NEXT;
case 5:
return RELATE_FIRST;
case 6:
return 0;
case 7:
mail_reply(idc, fptr, currmaildir);
return FULLUPDATE;
case 8:
multi_reply(idc, fptr, currmaildir);
return FULLUPDATE;
}
move(b_lines, 0);
clrtoeol();
outs(msg_mailer);
refresh();
switch (egetch())
{
case 'r':
case 'R':
mail_reply(idc, fptr, currmaildir);
break;
case 'x':
m_forward(idc, fptr, currmaildir);
break;
case 'y':
multi_reply(idc, fptr, currmaildir);
break;
case 'd':
case 'D':
delete_it = YEA;
default:
done = YEA;
}
}
if (delete_it)
{
clear();
prints("刪除信件《%s》", fptr->title);
getdata(1, 0, msg_sure_ny, genbuf, 2, LCECHO);
if (genbuf[0] == 'y')
{
unlink(fname);
delmsgs[delcnt++] = idc;
}
}
clear();
return 0;
}
int
m_new()
{
clear();
mrd = 0;
setutmpmode(RMAIL);
read_new_mail(NULL);
clear();
curredit |= EDIT_MAIL;
if (apply_record(currmaildir, read_new_mail, sizeof(fileheader)) == -1)
{
outs("沒有新信件了");
pressanykey();
return -1;
}
curredit = 0;
if (delcnt)
{
while (delcnt--)
delete_record(currmaildir, sizeof(fileheader), delmsgs[delcnt]);
}
outs(mrd ? "信已閱\畢" : "沒有新信件了");
pressanykey();
return -1;
}
static void
mailtitle()
{
showtitle("\0郵件選單", BoardName);
outs("\
[←]離開 [↑,↓]選擇 [→,r]閱\讀信件 [R]回信 [x]轉達 [y]群組回信 求助[h]\n\
編號 日 期 作 者 信 件 標 題 ");
}
static void
maildoent(num, ent)
fileheader *ent;
{
char *title, *mark, color, type = "+ Mm"[ent->filemode];
/*
woju
taged for delete
*/
if (ent->filemode & FILE_TAGED)
type = 'D';
title = subject(mark = ent->title);
if (title == mark)
{
color = '1';
mark = "◇";
}
else
{
color = '3';
mark = "R:";
}
if (strncmp(currtitle, title, 40))
prints("%5d %c %-7s%-15.14s%s %.46s\n", num, type,
ent->date, ent->owner, mark, title);
else
prints("%5d %c %-7s%-15.14sm%s %.46s\n", num, type,
ent->date, ent->owner, color, mark, title);
}
#ifdef POSTBUG
extern int bug_possible;
#endif
/*
woju
*/
static int
mail_del_tag(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[3];
getdata(1, 0, "確定刪除標記信件(Y/N)? [Y]", genbuf, 3, LCECHO);
if (genbuf[0] != 'n')
{
char buf[STRLEN];
currfmode = FILE_TAGED;
if (delete_files(direct, cmpfmode))
return DIRCHANGED;
}
return FULLUPDATE;
}
m_idle(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
t_idle();
return FULLUPDATE;
}
static int
mail_del(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char genbuf[200];
if (fhdr->filemode & FILE_MARKED)
return DONOTHING;
getdata(1, 0, msg_del_ny, genbuf, 3, LCECHO);
if (genbuf[0] == 'y')
{
char buf[STRLEN];
char *t;
extern int cmpfilename();
strcpy(currfile, fhdr->filename);
if (!delete_file(direct, sizeof(*fhdr), ent, cmpfilename))
{
setdirpath(genbuf, direct, fhdr->filename);
unlink(genbuf);
if( currmode & MODE_SELECT ){
int now;
sethomedir(genbuf,cuser.userid);
now=getindex(genbuf,fhdr->filename,sizeof(fileheader));
delete_file (genbuf, sizeof(fileheader),now,cmpfilename);
}
return DIRCHANGED;
}
}
return FULLUPDATE;
}
/*
woju
static int
*/
mail_read(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char buf[64];
char *t;
char done, delete_it, replied;
clear();
setdirpath(buf, direct, fhdr->filename);
strncpy(currtitle, subject(fhdr->title), 40);
done = delete_it = replied = NA;
while (!done)
{
/*
woju
*/
int more_result = more(buf, YEA);
if (more_result != -1) {
fhdr->filemode |= FILE_READ;
if (!strncmp("[新]", fhdr->title, 4) && !(fhdr->filemode & FILE_MARKED))
fhdr->filemode |= FILE_TAGED;
substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
}
switch (more_result) {
case 1:
return READ_PREV;
case 2:
return RELATE_PREV;
case 3:
return READ_NEXT;
case 4:
return RELATE_NEXT;
case 5:
return RELATE_FIRST;
case 6:
return FULLUPDATE;
case 7:
mail_reply(ent, fhdr, direct);
return FULLUPDATE;
case 8:
multi_reply(ent, fhdr, direct);
return FULLUPDATE;
}
move(b_lines, 0);
clrtoeol();
refresh();
outs(msg_mailer);
switch (egetch())
{
case 'r':
case 'R':
replied = YEA;
mail_reply(ent, fhdr, direct);
break;
case 'x':
m_forward(ent, fhdr, direct);
break;
case 'y':
multi_reply(ent, fhdr, direct);
break;
case 'd':
delete_it = YEA;
default:
done = YEA;
}
}
if (delete_it)
mail_del(ent, fhdr, direct);
else
{
fhdr->filemode |= FILE_READ;
#ifdef POSTBUG
if (replied)
bug_possible = YEA;
#endif
substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
#ifdef POSTBUG
bug_possible = NA;
#endif
}
return FULLUPDATE;
}
/* ---------------------------------------------- */
/* in boards/mail 回信給原作者,轉信站亦可 */
/* ---------------------------------------------- */
int
mail_reply(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char uid[STRLEN];
char *t;
FILE *fp;
char genbuf[512];
stand_title("回 信");
/* 判斷是 boards 或 mail */
if (curredit & EDIT_MAIL)
setuserfile(quote_file, fhdr->filename);
else
setbfile(quote_file, currboard, fhdr->filename);
/* find the author */
strcpy(quote_user, fhdr->owner);
if (strchr(quote_user, '.'))
{
genbuf[0] = '\0';
if (fp = fopen(quote_file, "r"))
{
fgets(genbuf, 512, fp);
fclose(fp);
}
t = strtok(genbuf, str_space);
if (!strcmp(t, str_author1) || !strcmp(t, str_author2))
{
strcpy(uid, strtok(NULL, str_space));
}
else
{
outs("錯誤: 找不到作者。");
pressanykey();
return FULLUPDATE;
}
}
else
strcpy(uid, quote_user);
/* make the title */
do_reply_title(3, fhdr->title);
prints("\n收信人: %s\n標 題: %s\n", uid, save_title);
/* edit, then send the mail */
ent = curredit;
switch (do_send(uid, save_title))
{
case -1:
outs(err_uid);
break;
case -2:
outs(msg_cancel);
break;
case -3:
prints("使用者 [%s] 無法收信", uid);
break;
}
curredit = ent;
pressanykey();
return FULLUPDATE;
}
int
mail_edit(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char uid[STRLEN];
char *t;
FILE *fp;
char genbuf[200];
setdirpath(genbuf, direct, fhdr->filename);
vedit(genbuf, belong("etc/bbsadms", cuser.userid) ? 0 : 2);
return FULLUPDATE;
}
static int
mail_mark(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
fhdr->filemode ^= FILE_MARKED;
fhdr->filemode &= ~FILE_TAGED;
substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
return (PART_REDRAW);
}
/*
woju
*/
static int
mail_tag(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
fhdr->filemode ^= FILE_TAGED;
substitute_record(currmaildir, fhdr, sizeof(*fhdr), ent);
return POS_NEXT;
}
/* help for mail reading */
static char *mail_help[] =
{
"\0電子信箱操作說明",
"\01基本命令",
"(p)(↑) 前一篇文章",
"(n)(↓) 下一篇文章",
"(P)(PgUp) 前一頁",
"(N)(PgDn) 下一頁",
"(##)(cr) 跳到第 ## 筆",
"($) 跳到最後一筆",
"\01進階命令",
"(r)(→) 讀信",
"(R) 回信",
"(c/z) 收入此信件進入私人信件夾/進入私人信件夾",
"(x) 轉達信件",
"(X) 轉錄文章到其他看板",
"(y) 群組回信",
#ifdef INTERNET_EMAIL
"(F) 將信傳送回您的電子信箱",
#endif
"(d) 殺掉此信",
"(D) 殺掉指定範圍的信",
"(m) 將信標記,以防被清除",
"(t) 標記欲刪除信件",
"(^D) 刪除已標記信件",
NULL
};
static int
m_help()
{
show_help(mail_help);
return FULLUPDATE;
}
static int
mail_cross_post(ent, fhdr, direct)
int ent;
fileheader *fhdr;
char *direct;
{
char xboard[20], fname[80], xfpath[80], xtitle[80], inputbuf[10];
fileheader xfile;
FILE *xptr;
int author = 0;
char genbuf[200];
char genbuf2[4];
make_blist();
move(2, 0);
clrtoeol();
move(3, 0);
clrtoeol();
move(1, 0);
namecomplete("轉錄本文章於看板:", xboard);
if (*xboard == '\0' || !haspostperm(xboard))
return FULLUPDATE;
ent = 1;
if (HAS_PERM(PERM_SYSOP) || !strcmp(fhdr->owner, cuser.userid))
{
getdata(2, 0, "(1)原文轉載 (2)舊轉錄格式?[1] ",
genbuf, 3, DOECHO);
if (genbuf[0] != '2')
{
ent = 0;
getdata(2, 0, "保留原作者名稱嗎?[Y] ", inputbuf, 3, DOECHO);
if (inputbuf[0] != 'n' && inputbuf[0] != 'N') author = 1;
}
}
if (ent)
sprintf(xtitle, "[轉錄]%.66s", fhdr->title);
else
strcpy(xtitle, fhdr->title);
sprintf(genbuf, "採用原標題《%.60s》嗎?[Y] ", xtitle);
getdata(2, 0, genbuf, genbuf2, 4, LCECHO);
if (*genbuf2 == 'n')
{
if (getdata(2, 0, "標題:", genbuf, TTLEN, DOECHO))
strcpy(xtitle, genbuf);
}
getdata(2, 0, "(S)存檔 (L)站內 (Q)取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] == 'l' || genbuf[0] == 's')
{
int currmode0 = currmode;
currmode = 0;
setbpath(xfpath, xboard);
stampfile(xfpath, &xfile);
if (author)
strcpy(xfile.owner, fhdr->owner);
else
strcpy(xfile.owner, cuser.userid);
strcpy(xfile.title, xtitle);
if (genbuf[0] == 'l')
{
xfile.savemode = 'L';
xfile.filemode = FILE_LOCAL;
}
else
xfile.savemode = 'S';
setuserfile(fname, fhdr->filename);
if (ent)
{
xptr = fopen(xfpath, "w");
strcpy(save_title, xfile.title);
strcpy(xfpath, currboard);
strcpy(currboard, xboard);
write_header(xptr);
strcpy(currboard, xfpath);
fprintf(xptr, "※ [本文轉錄自 %s 信箱]\n\n", cuser.userid);
b_suckinfile(xptr, fname);
addsignature(xptr);
fclose(xptr);
}
else
{
unlink(xfpath);
Link(fname, xfpath);
}
setbdir(fname, xboard);
append_record(fname, (char *) &xfile, sizeof(xfile));
if (!xfile.filemode)
outgo_post(&xfile, xboard);
cuser.numposts++;
substitute_record(fn_passwd, &cuser, sizeof(userec), usernum);
outs("文章轉錄完成");
pressanykey();
currmode = currmode0;
}
return FULLUPDATE;
}
mail_cite(int ent, fileheader* fhdr, char* direct)
{
char fpath[256];
char title[TTLEN+1];
static char xboard[20];
char buf[20];
boardheader *bp;
boardheader *getbcache();
setuserfile(fpath, fhdr->filename);
strcpy(title, "◇ ");
strncpy(title+3, fhdr->title, TTLEN-3);
title[TTLEN] = '\0';
a_copyitem(fpath, title, 0);
if (cuser.userlevel >= PERM_BM) {
move(2, 0);
clrtoeol();
move(3, 0);
clrtoeol();
move(1, 0);
make_blist();
namecomplete("輸入看版名稱 \
(直接Enter進入私人信件夾):", buf);
if (*buf)
strcpy(xboard, buf);
if (*xboard && (bp = getbcache(xboard))) {
setapath(fpath, xboard);
a_menu(xboard, fpath, HAS_PERM(PERM_ALLBOARD) ? 2 :
is_BM(bp->BM) ? 1 : 0);
}
else
{
mail_man(); /* Ptt */
fhdr->filemode |= FILE_TAGED;
}
return FULLUPDATE;
}
else
{
mail_man(); /* Ptt */
fhdr->filemode |= FILE_TAGED;
return FULLUPDATE;
}
}
int
edit_title();
mail_man()
{
char buf[64],buf1[64];
if (HAS_PERM(PERM_MAILLIMIT)) {
int mode0 = currutmp->mode;
int stat0 = currstat;
sethomeman(buf, cuser.userid);
sprintf(buf1,"%s 的信件夾",cuser.userid);
a_menu(buf1, buf, belong("etc/bbsadms", cuser.userid) ? 2 : 1);
currutmp->mode = mode0;
currstat = stat0;
return FULLUPDATE;
}
return DONOTHING;
}
mail_save(int ent, fileheader* fhdr, char* direct)
{
char fpath[256];
char title[TTLEN+1];
static char xboard[20];
char buf[20];
if (HAS_PERM(PERM_MAILLIMIT)) {
setuserfile(fpath, fhdr->filename);
strcpy(title, "◇ ");
strncpy(title+3, fhdr->title, TTLEN-3);
title[TTLEN] = '\0';
a_copyitem(fpath, title, fhdr->owner);
sethomeman(fpath, cuser.userid);
a_menu(cuser.userid, fpath, belong("etc/bbsadms", cuser.userid) ? 2 : 1);
return FULLUPDATE;
}
return DONOTHING;
}
static struct one_key mail_comms[] = {
'z', mail_man,
'c', mail_cite,
's', mail_save,
'd', mail_del,
'D', del_range,
'r', mail_read,
'R', mail_reply,
'E', mail_edit,
'm', mail_mark,
't', mail_tag,
'T', edit_title,
'x', m_forward,
'X', mail_cross_post,
Ctrl('D'), mail_del_tag,
'y', multi_reply,
Ctrl('I'), m_idle,
'h', m_help,
'\0', NULL
};
int
m_read()
{
if (get_num_records(currmaildir, sizeof(fileheader)))
{
curredit = EDIT_MAIL;
i_read(RMAIL, currmaildir, mailtitle, maildoent, mail_comms);
currfmode = FILE_TAGED;
if (search_rec(currmaildir, cmpfmode))
mail_del_tag(0, 0, currmaildir);
curredit = 0;
return 0;
}
else
{
outs("您沒有來信");
return XEASY;
}
}
#ifdef INTERNET_EMAIL
#include <netdb.h>
#include <pwd.h>
#include <time.h>
/* 寄信交給 sendmail,下列可以省略 */
#if 0
#define BBSMAILDIR "/usr/spool/mqueue"
static void
spacestozeros(s)
char *s;
{
while (*s)
{
if (*s == ' ')
*s = '0';
s++;
}
}
static int
getqsuffix(s)
char *s;
{
struct stat stbuf;
char qbuf[STRLEN], dbuf[STRLEN];
char c1 = 'A', c2 = 'A';
int pos = strlen(BBSMAILDIR) + 3;
sprintf(dbuf, "%s/dfAA%5d", BBSMAILDIR, currpid);
sprintf(qbuf, "%s/qfAA%5d", BBSMAILDIR, currpid);
spacestozeros(dbuf);
spacestozeros(qbuf);
while (1)
{
if (stat(dbuf, &stbuf) && stat(qbuf, &stbuf))
break;
if (c2 == 'Z')
{
c2 = 'A';
if (c1 == 'Z')
return -1;
else
c1++;
dbuf[pos] = c1;
qbuf[pos] = c1;
}
else
c2++;
dbuf[pos + 1] = c2;
qbuf[pos + 1] = c2;
}
strcpy(s, &(qbuf[pos]));
return 0;
}
static void
convert_tz(local, gmt, buf)
int gmt, local;
char *buf;
{
local -= gmt;
if (local < -11)
local += 24;
else if (local > 12)
local -= 24;
sprintf(buf, " %4d", abs(local * 100));
spacestozeros(buf);
if (local < 0)
buf[0] = '-';
else if (local > 0)
buf[0] = '+';
else
buf[0] = '\0';
}
static int
createqf(title, qsuffix)
char *title, *qsuffix;
{
static int configured = 0;
static char myhostname[STRLEN];
static char myusername[20];
char mytime[STRLEN];
char idtime[STRLEN];
char qfname[STRLEN];
char t_offset[6];
FILE *qfp;
time_t timenow;
int savehour;
struct tm *gtime, *ltime;
struct hostent *hbuf;
struct passwd *pbuf;
if (!configured)
{
/* get host name */
gethostname(myhostname, STRLEN);
hbuf = gethostbyname(myhostname);
if (hbuf)
strncpy(myhostname, hbuf->h_name, STRLEN);
/* get bbs uident */
pbuf = getpwuid(getuid());
if (pbuf)
strncpy(myusername, pbuf->pw_name, 20);
if (hbuf && pbuf)
configured = 1;
else
return -1;
}
/* get file name */
sprintf(qfname, "%s/qf%s", BBSMAILDIR, qsuffix);
if ((qfp = fopen(qfname, "w")) == NULL)
return -1;
/* get time */
time(&timenow);
ltime = localtime(&timenow);
#ifdef SYSV
ascftime(mytime, "%a, %d %b %Y %T ", ltime);
#else
strftime(mytime, sizeof(mytime), "%a, %d %b %Y %T ", ltime);
#endif
savehour = ltime->tm_hour;
gtime = gmtime(&timenow);
strftime(idtime, sizeof(idtime), "%Y%m%d%y%H%M", gtime);
convert_tz(savehour, gtime->tm_hour, t_offset);
strcat(mytime, t_offset);
fprintf(qfp, "P1000\nT%lu\nDdf%s\nS%s\nR%s\n", timenow, qsuffix,
myusername, cuser.email);
/* do those headers! */
fprintf(qfp, "HReceived: by %s (" MYVERSION ")\n\tid %s; %s\n",
myhostname, qsuffix, mytime);
fprintf(qfp, "HReturn-Path: <%s@%s>\n", myusername, myhostname);
fprintf(qfp, "HDate: %s\n", mytime);
fprintf(qfp, "HMessage-Id: <%s.%s@%s>\n", idtime, qsuffix,
myhostname);
fprintf(qfp, "HFrom: %s@%s (%s in NTHU CS BBS)\n", myusername, myhostname, cuser.userid);
fprintf(qfp, "HSubject: %s (fwd)\n", title);
fprintf(qfp, "HTo: %s\n", cuser.email);
fprintf(qfp, "HX-Forwarded-By: %s (%s)\n", cuser.userid,
#ifdef REALNAME
cuser.realname);
#else
cuser.username);
#endif
fprintf(qfp, "HX-Disclaimer: %s 對本信內容恕不負責。\n", BoardName);
fclose(qfp);
return 0;
}
#endif
int
bbs_sendmail(fpath, title, receiver)
char *fpath, *title, *receiver;
{
static int configured = 0;
static char myhostname[STRLEN];
static char myusername[20];
struct hostent *hbuf;
struct passwd *pbuf;
char *ptr;
char genbuf[200];
FILE *fin, *fout;
/* 中途攔截 */
if (ptr = strchr(receiver, ';'))
{
struct tm *ptime;
time_t now;
/*
if (fout = fopen("hackerlog", "a+"))
{
time(&now);
ptime = localtime(&now);
fprintf(fout, "[%d/%d %d:%02d] %s from %s\n\t\t寄出 %s\n",
ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min,
cuser.userid, getenv("RFC931"), receiver);
fclose(fout);
}
*/
*ptr = '\0';
}
if ((ptr = strstr(receiver, str_mail_address)) || !strchr(receiver,'@'))
{
fileheader mymail;
char hacker[20];
int len;
if(strchr(receiver,'@') )
{
len = ptr - receiver;
memcpy(hacker, receiver, len);
hacker[len] = '\0';
}
else
{
strcpy(hacker,receiver);
}
if (!searchuser(hacker))
{
return -2;
}
sethomepath(genbuf, hacker);
stampfile(genbuf, &mymail);
if (!strcmp(hacker, cuser.userid))
{
strcpy(mymail.owner, "[批踢踢實業坊]");
mymail.filemode = FILE_READ;
}
else
strcpy(mymail.owner, cuser.userid);
strncpy(mymail.title, title, TTLEN);
unlink(genbuf);
Link(fpath, genbuf);
sethomedir(genbuf, hacker);
return do_append(genbuf, &mymail, sizeof(mymail));
}
/* setup the hostname and username */
if (!configured)
{
/* get host name */
gethostname(myhostname, STRLEN);
hbuf = gethostbyname(myhostname);
if (hbuf)
strncpy(myhostname, hbuf->h_name, STRLEN);
/* get bbs uident */
pbuf = getpwuid(getuid());
if (pbuf)
strncpy(myusername, pbuf->pw_name, 20);
if (hbuf && pbuf)
configured = 1;
else
return -1;
}
/* Running the sendmail */
#ifdef INTERNET_PRIVATE_EMAIL
if (fpath == NULL)
{
sprintf(genbuf, "/usr/sbin/sendmail %s > /dev/null", receiver);
fin = fopen("etc/confirm", "r");
}
else
{
sprintf(genbuf, "/usr/sbin/sendmail -f %s%s %s > /dev/null"
, cuser.userid, str_mail_address, receiver);
fin = fopen(fpath, "r");
}
fout = popen(genbuf, "w");
if (fin == NULL || fout == NULL)
return -1;
if (fpath)
fprintf(fout, "Reply-To: %s%s\nFrom: %s%s\n",
cuser.userid, str_mail_address, cuser.userid, str_mail_address);
#else
sprintf(genbuf, "/usr/sbin/sendmail %s > /dev/null", receiver);
fout = popen(genbuf, "w");
fin = fopen(fpath ? fpath : "etc/confirm", "r");
if (fin == NULL || fout == NULL)
return -1;
if (fpath)
fprintf(fout, "From: %s@%s (%s)\n",
myusername, myhostname, BBSNAME);
#endif
fprintf(fout, "To: %s\nSubject: %s\n", receiver, title);
fprintf(fout, "X-Disclaimer: 批踢踢實業坊" BOARDNAME
"對本信內容恕不負責。\n\n");
while (fgets(genbuf, 255, fin))
{
if (genbuf[0] == '.' && genbuf[1] == '\n')
fputs(". \n", fout);
else
fputs(genbuf, fout);
}
fclose(fin);
fprintf(fout, ".\n");
pclose(fout);
return 0;
}
int
doforward(direct, fh, mode)
char *direct;
fileheader *fh;
int mode; /* 是否 uuencode */
{
static char address[60];
char fname[STRLEN];
int return_no;
char genbuf[200];
if (!address[0])
strcpy(address, cuser.email);
if (address[0])
{
sprintf(genbuf, "確定轉寄給 [%s] 嗎(Y/N/Q)?[Y] ", address);
getdata(b_lines - 1, 0, genbuf, fname, 3, LCECHO);
if (fname[0] == 'q')
{
outmsg("取消轉寄");
return 1;
}
if (fname[0] == 'n')
address[0] = '\0';
}
if (!address[0])
{
getdata(b_lines - 1, 0, "請輸入轉寄地址:", fname, 60, DOECHO);
if (fname[0])
{
if (strchr(fname, '.'))
strcpy(address, fname);
else
sprintf(address, "%s.bbs@%s", fname, MYHOSTNAME);
}
else
{
outmsg("取消轉寄");
return 1;
}
}
if (invalidaddr(address))
return -2;
sprintf(fname, "正轉寄給 %s, 請稍候...", address);
outmsg(fname);
move(b_lines - 1, 0);
refresh();
if (mode)
{
char tmp_buf[128];
sprintf(fname, "/tmp/bbs.uu%05d", currpid);
sprintf(tmp_buf, "/usr/bin/uuencode %s/%s uu.%05d > %s",
direct, fh->filename, currpid, fname);
system(tmp_buf);
sleep(1);
}
else
sprintf(fname, "%s/%s", direct, fh->filename);
return_no = bbs_sendmail(fname, fh->title, address);
if (mode)
unlink(fname);
return (return_no);
}
#endif
int
chkmail(rechk)
int rechk;
{
static time_t lasttime = 0;
static int ismail = 0;
struct stat st;
fileheader fh;
int fd;
register numfiles;
unsigned char ch;
if (!HAS_PERM(PERM_BASIC))
return 0;
if (stat(currmaildir, &st) < 0)
return (ismail = 0);
if ((lasttime >= st.st_mtime) && !rechk)
return ismail;
lasttime = st.st_mtime;
numfiles = st.st_size / sizeof(fileheader);
if (numfiles <= 0)
return (ismail = 0);
/* ------------------------------------------------ */
/* 看看有沒有信件還沒讀過?從檔尾回頭檢查,效率較高 */
/* ------------------------------------------------ */
if ((fd = open(currmaildir, O_RDONLY)) > 0)
{
lseek(fd, st.st_size - 1, SEEK_SET);
while (numfiles--)
{
read(fd, &ch, 1);
if (!(ch & FILE_READ))
{
close(fd);
return (ismail = 1);
}
lseek(fd, (off_t) -sizeof(fileheader) - 1, SEEK_CUR);
}
close(fd);
}
return (ismail = 0);
}
#ifdef EMAIL_JUSTIFY
void
mail_justify(userec muser)
{
fileheader mhdr;
char title[128], buf1[80];
FILE* fp;
sethomepath(buf1, muser.userid);
stampfile(buf1, &mhdr);
unlink(buf1);
strcpy(mhdr.owner, cuser.userid);
strncpy(mhdr.title, "[審核通過]", TTLEN);
mhdr.savemode = 0;
mhdr.filemode = 0;
/*
woju
more("etc/justify", NA);
*/
if (valid_ident(muser.email) && !invalidaddr(muser.email))
{
char title[80], *ptr;
ushort checksum; /* 16-bit is enough */
char ch;
checksum = getuser(muser.userid);
ptr = muser.email;
while (ch = *ptr++)
{
if (ch <= ' ')
break;
if (ch >= 'A' && ch <= 'Z')
ch |= 0x20;
checksum = (checksum << 1) ^ ch;
}
sprintf(title, "[PTT BBS]To %s(%d:%d) [User Justify]",
muser.userid, getuser(muser.userid) + MAGIC_KEY, checksum);
if (bbs_sendmail(NULL, title, muser.email) < 0)
Link("etc/bademail", buf1);
else
Link("etc/replyemail", buf1);
}
else
Link("etc/bademail", buf1);
sethomedir(title, muser.userid);
append_record(title, &mhdr, sizeof(mhdr));
}
#endif /* EMAIL_JUSTIFY */