/*-------------------------------------------------------*/
/* user.c ( NTHU CS MapleBBS Ver 2.36 ) */
/*-------------------------------------------------------*/
/* author : opus.bbs@bbs.cs.nthu.edu.tw */
/* target : user configurable setting routines */
/* create : 95/03/29 */
/* update : 95/12/15 */
/*-------------------------------------------------------*/
#include "bbs.h"
extern int numboards;
extern boardheader *bcache;
extern void resolve_boards();
char *sex[8] = { MSG_BIG_BOY, MSG_BIG_GIRL, MSG_LITTLE_BOY, MSG_LITTLE_GIRL,
MSG_MAN, MSG_WOMAN, MSG_PLANT, MSG_MIME };
void
user_display(u, real)
userec *u;
{
int diff;
char genbuf[200];
clrtobot();
prints(
"代號 :%s\n"
"暱稱 :%s\n"
"真實姓名 :%s\n"
"居住住址 :%s\n"
"電子郵件信箱:%s\n"
"性別 :%s\n"
"銀行帳戶 :%ld 銀兩\n"
"生日 :%02i/%02i/%02i\n",
u->userid,
u->username,
u->realname,
u->address,
u->email,
sex[u->sex],
u->money,
u->month, u->day, u->year);
prints(/*"終端機形態 :%s\n"*/
"註冊日期 :%s",
/*u->termtype,*/
ctime(&u->firstlogin));
prints("最近光臨日期:%s", ctime(&u->lastlogin));
if (real)
prints("最近光臨機器:%s\n", u->lasthost);
prints("上站次數 :%d 次\n", u->numlogins);
prints("文章數目 :%d 篇\n", u->numposts);
sethomedir(genbuf, u->userid);
prints("私人信箱 :%d 封\n", get_num_records(genbuf, sizeof(fileheader)));
if (real)
{
strcpy(genbuf, "bTCPRp#@XWBA#VS");
for (diff = 0; diff < 15; diff++)
if (!(u->userlevel & (1 << diff)))
genbuf[diff] = '-';
prints("認證資料 :%s\n使用者權限 :%s\n", u->justify, genbuf);
}
else
{
diff = (time(0) - login_start_time) / 60;
prints("停留期間 :%d 小時 %2d 分\n", diff / 60, diff % 60);
}
/* Thor: 想看看這個 user 是那些版的版主 */
if (u->userlevel >= PERM_BM)
{
int i, len, ch;
boardheader *bhdr;
char *list;
resolve_boards();
len = strlen(u->userid);
outs("擔任板主 :");
for (i = 0, bhdr = bcache; i < numboards; i++, bhdr++)
{
list = bhdr->BM;
ch = list[0];
if ((ch > ' ') && (ch < 128))
{
do
{
if (!ci_strncmp(list, u->userid, len))
{
ch = list[len];
if ((ch == 0) || (ch == '/'))
{
outs(bhdr->brdname);
outc(' ');
break;
}
}
while (ch = *list++)
if (ch == '/')
break;
} while (ch);
}
}
outc('\n');
}
outs((u->userlevel & PERM_LOGINOK) ?
"\n您的註冊程序已經完成,歡迎加入本站" :
"\n如果要提昇權限,請參考本站公佈欄辦理註冊");
#ifdef NEWUSER_LIMIT
if ((u->lastlogin - u->firstlogin < 3 * 86400) && !HAS_PERM(PERM_POST))
outs("\n新手上路,三天後開放權限");
#endif
}
void
uinfo_query(u, real, unum)
userec *u;
{
userec x;
register int i, fail, mail_changed;
char ans[4], buf[STRLEN];
char genbuf[200];
int flag=0,temp;
char *genpasswd();
fail = mail_changed = 0;
memcpy(&x, u, sizeof(userec));
getdata(b_lines - 1, 0, real ?
"(1)修改資料 (2)設定密碼 (3)設定權限 (4)清除帳號 (5)改ID [0]結束 " :
"請選擇 (1)修改資料 (2)設定密碼 ==> [0]結束 ",
ans, 3, DOECHO);
if (ans[0] > '2' && !real)
{
ans[0] = '0';
}
if (ans[0] == '1' || ans[0] == '3')
{
clear();
i = 2;
move(i++, 0);
outs(msg_uid);
outs(x.userid);
}
switch (ans[0])
{
case '1':
move(0, 0);
outs("請逐項修改。");
getdata_buf(i++, 0," 暱 稱 :",x.username, 24, DOECHO);
getdata_buf(i++, 0,"真實姓名:",x.realname, 20, DOECHO);
getdata_buf(i++, 0,"居住地址:",x.address, 50, DOECHO);
getdata_str(i++, 0,"電子信箱:",buf, 50, DOECHO,x.email);
if ( strcmp(buf,x.email) && strchr(buf, '@'))
{
strcpy(x.email,buf);
mail_changed = 1 - real;
}
sprintf(genbuf,
"%i", u->sex + 1);
getdata_str(i++, 0,
"性別 (1)葛格 (2)姐接 (3)底迪 (4)美眉 (5)薯叔 (6)阿姨 (7)植物 (8)礦物:",
buf, 3, DOECHO,genbuf);
if (buf[0] >= '1' && buf[0] <= '8')
x.sex = buf[0] - '1';
else
x.sex = u->sex;
while (1)
{
int len;
sprintf(genbuf, "%02i/%02i/%02i",
u->month, u->day, u->year);
len = getdata_str(i, 0, "生日 月月/日日/西元:", buf, 9, DOECHO,genbuf);
if (len && len != 8)
continue;
if (!len)
{
x.month = u->month;
x.day = u->day;
x.year = u->year;
}
else if (len == 8)
{
x.month = (buf[0] - '0') * 10 + (buf[1] - '0');
x.day = (buf[3] - '0') * 10 + (buf[4] - '0');
x.year = (buf[6] - '0') * 10 + (buf[7] - '0');
}
else
continue;
if (!real && (x.month > 12 || x.month < 1 ||
x.day > 31 || x.day < 1 || x.year > 90 || x.year < 40))
continue;
i++;
break;
}
if (real)
{
unsigned long int l;
sprintf(genbuf, "%ld", x.money);
if (getdata_str(i++, 0,"銀行帳戶:", buf, 10, DOECHO,genbuf))
if ((l = atol(buf)) >= 0)
x.money = l;
getdata_buf(i++, 0,"認證資料:", x.justify, 44, DOECHO);
getdata_buf(i++, 0,"最近光臨機器:", x.lasthost, 16, DOECHO);
sprintf(genbuf, "%d", x.numlogins);
if (getdata_str(i++, 0,"上線次數:", buf, 10, DOECHO,genbuf))
if ((fail = atoi(buf)) >= 0)
x.numlogins = fail;
sprintf(genbuf,"%d", u->numposts);
if (getdata_str(i++, 0, "文章數目:", buf, 10, DOECHO,genbuf))
if ((fail = atoi(buf)) >= 0)
x.numposts = fail;
fail = 0;
}
break;
case '2':
i = 19;
if (!real)
{
if (!getdata(i++, 0, "請輸入原密碼:", buf, PASSLEN, NOECHO) ||
!checkpasswd(u->passwd, buf))
{
outs("\n\n您輸入的密碼不正確\n");
fail++;
break;
}
}
if (!getdata(i++, 0, "請設定新密碼:", buf, PASSLEN, NOECHO))
{
outs("\n\n密碼設定取消, 繼續使用舊密碼\n");
fail++;
break;
}
strncpy(genbuf, buf, PASSLEN);
getdata(i++, 0, "請檢查新密碼:", buf, PASSLEN, NOECHO);
if (strncmp(buf, genbuf, PASSLEN))
{
outs("\n\n新密碼確認失敗, 無法設定新密碼\n");
fail++;
break;
}
buf[8] = '\0';
strncpy(x.passwd, genpasswd(buf), PASSLEN);
break;
case '3':
i = setperms(x.userlevel);
if (i == x.userlevel)
fail++;
else {
flag=1;
temp=x.userlevel;
x.userlevel = i;
}
break;
case '4':
i = QUIT;
break;
case '5':
if (getdata_str(b_lines - 3, 0, "新的使用者代號:", genbuf, IDLEN + 1,
DOECHO,x.userid))
{
if (searchuser(genbuf))
{
outs("錯誤! 已經有同樣 ID 的使用者");
fail++;
}
else
{
strcpy(x.userid, genbuf);
}
}
break;
default:
return;
}
if (fail)
{
pressanykey();
return;
}
getdata(b_lines - 1, 0, msg_sure_ny, ans, 3, LCECHO);
if (*ans == 'y')
{
if (flag) Security(temp,i,cuser.userid,x.userid);
if (strcmp(u->userid, x.userid))
{
char src[STRLEN], dst[STRLEN];
sethomepath(src, u->userid);
sethomepath(dst, x.userid);
Rename(src, dst);
setuserid(unum, x.userid);
}
memcpy(u, &x, sizeof(x));
if (mail_changed)
{
#ifdef EMAIL_JUSTIFY
x.userlevel &= ~PERM_LOGINOK;
mail_justify();
#endif
}
if (i == QUIT)
{
char src[STRLEN], dst[STRLEN];
sprintf(src, "home/%s", x.userid);
sprintf(dst, "tmp/%s", x.userid);
if (Rename(src, dst))
{
sprintf(genbuf, "/bin/rm -fr %s", src);
system(genbuf);
}
/*
woju
*/
log_usies("KILL", x.userid);
x.userid[0] = '\0';
setuserid(unum, x.userid);
}
else
log_usies("SetUser", x.userid);
substitute_record(fn_passwd, &x, sizeof(x), unum);
}
}
int
u_info()
{
move(2, 0);
user_display(&cuser, 0);
uinfo_query(&cuser, 0, usernum);
strcpy(currutmp->realname, cuser.realname);
strcpy(currutmp->username, cuser.username);
return 0;
}
int
u_ansi()
{
showansi ^= 1;
cuser.uflag ^= COLOR_FLAG;
outs(reset_color);
return 0;
}
int
u_cloak()
{
outs((currutmp->invisible ^= 1) ? MSG_CLOAKED : MSG_UNCLOAK);
return XEASY;
}
int
u_switchproverb()
{
/* char *state[4]={"用功\型","安逸型","自定型","SHUTUP"}; */
char buf[100];
cuser.proverb =(cuser.proverb +1) %4;
setuserfile(buf,fn_proverb);
if( cuser.proverb==2 && dashd(buf))
{
FILE *fp=fopen(buf,"a");
fprintf(fp,"座右銘狀態為[自定型]要記得設座右銘的內容唷!!");
fclose(fp);
}
substitute_record(fn_passwd, &cuser, sizeof(cuser), usernum);
/*
move(22,2);
clrtoeol();
sprintf(buf,"座右銘(半點callin) 已切換成 [%s] "
,state[cuser.proverb]);
outs(buf);
pressanykey();
*/
return 0;
}
int
u_editproverb()
{
char buf[100];
setutmpmode(PROVERB);
setuserfile(buf,fn_proverb);
move(1,0);
clrtobot();
outs("\n\n 請一行一行依序鍵入想系統提醒你的內容,"
"\n 儲存後記得把狀態設為 [自定型] 才有作用"
"\n 座右銘最多100條");
pressanykey();
vedit(buf,NA);
return 0;
}
/* Ptt拿掉
int
u_lock()
{
char genbuf[PASSLEN];
log_usies("LOCK ", "screen");
do
{
getdata(b_lines - 1, 0, "▲ 請輸入密碼,以解除螢幕鎖定:",
genbuf, PASSLEN, NOECHO);
} while (!checkpasswd(cuser.passwd, genbuf));
return FULLUPDATE;
}
*/
#ifdef HAVE_SUICIDE
int
u_kill()
{
char genbuf[200];
getdata(b_lines - 1, 0, "▲ 如果確定要清除您的帳號,請輸入密碼:",
genbuf, PASSLEN, NOECHO);
if (*genbuf == '\0' || !checkpasswd(cuser.passwd, genbuf))
{
outmsg("您輸入的密碼不正確,帳號未清除。");
igetch();
return FULLUPDATE;
}
#ifdef HAVE_REPORT
report("suicide");
#endif
sprintf(genbuf, "#%d %s:%s %d %d",
usernum, cuser.realname, cuser.username, cuser.numlogins, cuser.numposts);
log_usies("SUCI ", genbuf);
sprintf(genbuf, "%s %s", fromhost, Cdate(&(cuser.firstlogin)));
log_usies("SUCI ", genbuf);
sethomepath(genbuf, cuser.userid);
if (Rename(genbuf, "tmp"))
{
/*
woju
*/
sprintf(genbuf, "(cd home; tar cvf SUCI_%s.tar %s); /bin/rm -fr home/%s",
cuser.userid, cuser.userid, cuser.userid);
system(genbuf);
}
cuser.userid[0] = '\0';
substitute_record(fn_passwd, &cuser, sizeof(cuser), usernum);
setuserid(usernum, cuser.userid);
purge_utmp(currutmp);
clear();
outs("親愛的朋友,青山長在,綠水長流,咱們後會有期吧!");
pressanykey();
sleep(1);
reset_tty();
exit(0);
}
#endif
void
showplans(uid)
char *uid;
{
FILE *planfile;
int i;
char genbuf[200];
sethomefile(genbuf, uid, fn_plans);
if (planfile = fopen(genbuf, "r"))
{
prints("%s 的名片:\n", uid);
i = 0;
while (i++ < MAXQUERYLINES && fgets(genbuf, 256, planfile))
{
strip_ansi(genbuf,genbuf,1);
outs(Ptt_prints(genbuf));
}
fclose(planfile);
}
else
prints("%s 目前沒有名片", uid);
}
int
showsignature(fname)
char *fname;
{
FILE *fp;
char buf[256];
int i, j;
char ch;
clear();
move(2, 0);
setuserfile(fname, "sig.0");
j = strlen(fname) - 1;
for (ch = '1'; ch <= '9'; ch++)
{
fname[j] = ch;
if (fp = fopen(fname, "r"))
{
prints("【 簽名檔.%c 】\n", ch);
for (i = 0; i++ < MAXSIGLINES && fgets(buf, 256, fp); outs(buf));
fclose(fp);
}
}
return j;
}
int
u_editsig()
{
int aborted;
char ans[4];
int j;
char genbuf[200];
j = showsignature(genbuf);
getdata(0, 0, "簽名檔 (E)編輯 (D)刪除 (Q)取消?[Q] ", ans, 4, LCECHO);
aborted = 0;
if (ans[0] == 'd')
aborted = 1;
if (ans[0] == 'e')
aborted = 2;
if (aborted)
{
if (!getdata(1, 0, "請選擇簽名檔(1-9)?[1] ", ans, 4, DOECHO))
ans[0] = '1';
if (ans[0] >= '1' && ans[0] <= '9')
{
genbuf[j] = ans[0];
if (aborted == 1)
{
unlink(genbuf);
outs(msg_del_ok);
}
else
{
setutmpmode(EDITSIG);
aborted = vedit(genbuf, NA);
if (aborted != -1)
outs("簽名檔更新完畢");
}
}
pressanykey();
}
return 0;
}
int
u_editplan()
{
char genbuf[200];
getdata(b_lines - 1, 0, "名片 (D)刪除 (E)編輯 [Q]取消?[Q] ", genbuf, 3, LCECHO);
if (genbuf[0] == 'e')
{
int aborted;
setutmpmode(EDITPLAN);
setuserfile(genbuf, fn_plans);
aborted = vedit(genbuf, NA);
if (aborted != -1)
outs("名片更新完畢");
pressanykey();
return 0;
}
else if (genbuf[0] == 'd')
{
setuserfile(genbuf, fn_plans);
unlink(genbuf);
outmsg("名片刪除完畢");
}
return 0;
}
/* --------------------------------------------- */
/* 使用者填寫註冊表格 */
/* --------------------------------------------- */
static void
getfield(line, info, desc, buf, len)
int line, len;
char *info, *desc, *buf;
{
char prompt[STRLEN];
char genbuf[200];
sprintf(genbuf, "原先設定:%-30.30s (%s)", buf, info);
move(line, 2);
outs(genbuf);
sprintf(prompt, "%s:", desc);
if (getdata(line + 1, 2, prompt, genbuf, len, DOECHO))
strcpy(buf, genbuf);
move(line, 2);
prints("%s:%s", desc, buf);
clrtoeol();
}
int
u_register()
{
char rname[20], addr[50];
char phone[20], career[40], email[50],birthday[9],sex_is[2],year,mon,day;
char ans[3], *ptr;
FILE *fn;
time_t now;
char genbuf[200];
if (cuser.userlevel & PERM_LOGINOK)
{
outs("您的身份確認已經完成,不需填寫申請表");
return XEASY;
}
if (fn = fopen(fn_register, "r"))
{
while (fgets(genbuf, STRLEN, fn))
{
if (ptr = strchr(genbuf, '\n'))
*ptr = '\0';
if (strncmp(genbuf, "uid: ", 5) == 0 &&
strcmp(genbuf + 5, cuser.userid) == 0)
{
fclose(fn);
outs("您的註冊申請單尚在處理中,請耐心等候");
return XEASY;
}
}
fclose(fn);
}
getdata(b_lines - 1, 0, "您確定要填寫註冊單嗎(Y/N)?[N] ", ans, 3, LCECHO);
if (ans[0] != 'y')
return FULLUPDATE;
move(2, 0);
clrtobot();
strcpy(rname, cuser.realname);
strcpy(addr, cuser.address);
strcpy(email, cuser.email);
sprintf(birthday, "%02i/%02i/%02i",
cuser.month, cuser.day, cuser.year);
sex_is[0]=cuser.sex+'1';sex_is[1]=0;
career[0] = phone[0] = '\0';
while (1)
{
clear();
move(3, 0);
prints("%s(%s) 您好,請據實填寫以下的資料:",
cuser.userid, cuser.username);
getfield(6, "請用中文", "真實姓名", rname, 20);
getfield(8, "學校系級或單位職稱", "服務單位", career, 40);
getfield(10, "包括寢室或門牌號碼", "目前住址", addr, 50);
getfield(12, "包括長途撥號區域碼", "連絡電話", phone, 20);
while (1)
{
int len;
getfield(14, "月月/日日/西元 如:09/27/76","生日",birthday,9);
len = strlen(birthday);
if(!len)
{
sprintf(birthday, "%02i/%02i/%02i",
cuser.month, cuser.day, cuser.year);
mon=cuser.month;
day=cuser.day;
year=cuser.year;
}
else if (len==8)
{
mon = (birthday[0] - '0') * 10 + (birthday[1] - '0');
day = (birthday[3] - '0') * 10 + (birthday[4] - '0');
year = (birthday[6] - '0') * 10 + (birthday[7] - '0');
}
else
continue;
if (mon > 12 || mon < 1 || day > 31 || day < 1 || year > 90 || year < 40)
continue;
break;
}
getfield(16,
"1.葛格 2.姐接 ","性別",sex_is,2);
getfield(18, "身分認證用", "E-Mail Address", email, 50);
getdata(b_lines - 1, 0, "以上資料是否正確(Y/N)?(Q)取消註冊 [N] ", ans, 3, LCECHO);
if (ans[0] == 'q')
return 0;
if (ans[0] == 'y')
break;
}
strcpy(cuser.realname, rname);
strcpy(cuser.address, addr);
strcpy(cuser.email, email);
cuser.sex= sex_is[0]-'1';
cuser.month=mon;cuser.day=day;cuser.year=year;
if (fn = fopen(fn_register, "a"))
{
now = time(NULL);
trim(career);
trim(addr);
trim(phone);
fprintf(fn, "num: %d, %s", usernum, ctime(&now));
fprintf(fn, "uid: %s\n", cuser.userid);
fprintf(fn, "name: %s\n", rname);
fprintf(fn, "career: %s\n", career);
fprintf(fn, "addr: %s\n", addr);
fprintf(fn, "phone: %s\n", phone);
fprintf(fn, "email: %s\n", email);
fprintf(fn, "----\n");
fclose(fn);
}
clear();
move(9,3);
prints("最後Post一篇自我介紹文章給大家吧,告訴所有老骨頭我來啦^$。\
\n\n\n\n");
pressanykey();
brc_initial("WhoAmI");
set_board();
do_post();
return 0;
}
/* --------------------------------------------- */
/* 列出所有註冊使用者 */
/* --------------------------------------------- */
extern struct UCACHE *uidshm;
int usercounter, totalusers, showrealname;
ushort u_list_special;
extern int
bad_user_id(char userid[]);
static int
u_list_CB(uentp)
userec *uentp;
{
static int i;
char permstr[8], *ptr;
register int level;
if (uentp == NULL)
{
move(2, 0);
clrtoeol();
prints(" 使用者代號 %-25s 上站 文章 %s 最近光臨日期 \n",
showrealname ?
/*#if defined(REALINFO) && defined(ACTS_REALNAMES)*/
"真實姓名" :
/*#else*/
"綽號暱稱"
/*#endif*/
,HAS_PERM(PERM_SEEULEVELS) ? "等級" : "");
i = 3;
return 0;
}
if (bad_user_id(uentp->userid)) /* Ptt */
return 0;
if (uentp->userlevel < u_list_special)
return 0;
if (i == b_lines)
{
prints(" 已顯示 %d/%d 人(%d%%) (Space) 看下一頁 (Q) 離開 ",
usercounter, totalusers, usercounter * 100 / totalusers);
i = igetch();
if (i == 'q' || i == 'Q')
return QUIT;
i = 3;
}
if (i == 3)
{
move(3, 0);
clrtobot();
}
level = uentp->userlevel;
strcpy(permstr, "----");
if (level & PERM_SYSOP)
permstr[0] = 'S';
else if (level & PERM_ACCOUNTS)
permstr[0] = 'A';
else if (level & PERM_DENYPOST)
permstr[0] = 'p';
if (level & (PERM_BOARD))
permstr[1] = 'B';
else if (level & (PERM_BM))
permstr[1] = 'b';
if (level & (PERM_XEMPT))
permstr[2] = 'X';
else if (level & (PERM_LOGINOK))
permstr[2] = 'R';
if (level & (PERM_CLOAK | PERM_SEECLOAK))
permstr[3] = 'C';
ptr = (char *) Cdate(&uentp->lastlogin);
ptr[18] = '\0';
prints("%-14s %-27.27s%5d %5d %s %s\n",
uentp->userid,
showrealname ?
/*#if defined(REALINFO) && defined(ACTS_REALNAMES)*/
uentp->realname :
/*#else*/
uentp->username
/*#endif*/
,uentp->numlogins, uentp->numposts,
HAS_PERM(PERM_SEEULEVELS) ? permstr : "", ptr);
usercounter++;
i++;
return 0;
}
int
u_list()
{
char genbuf[3];
setutmpmode(LAUSERS);
showrealname = u_list_special = usercounter = 0;
totalusers = uidshm->number;
if (HAS_PERM(PERM_SEEULEVELS))
{
getdata(b_lines - 1, 0, "觀看 [1]特殊等級 (2)全部?", genbuf, 3, DOECHO);
if (genbuf[0] != '2')
u_list_special = 32;
}
if (HAS_PERM(PERM_CHATROOM) || HAS_PERM(PERM_SYSOP))
{
getdata(b_lines - 1, 0, "顯示 [1]真實姓名 (2)暱稱?", genbuf, 3, DOECHO);
if (genbuf[0] != '2')
showrealname = 1;
}
u_list_CB(NULL);
if (apply_record(fn_passwd, u_list_CB, sizeof(userec)) == -1)
{
outs(msg_nobody);
return XEASY;
}
move(b_lines, 0);
clrtoeol();
prints(" 已顯示 %d/%d 的使用者(系統容量無上限) (請按任意鍵繼續) ",
usercounter, totalusers);
egetch();
return 0;
}