summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-03-06 20:09:00 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-03-06 20:09:00 +0800
commit1ff37fcf607bfc356c60d423ad05fca9d9eab190 (patch)
tree86500ec110b3f80babee1bb958a3d553b54cded5
parent113ce755bf96bb52e5e6336be82363d79582aca0 (diff)
downloadpttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar.gz
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar.bz2
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar.lz
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar.xz
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.tar.zst
pttbbs-1ff37fcf607bfc356c60d423ad05fca9d9eab190.zip
- [code refine] move all registration code to register.c
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3966 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--include/common.h1
-rw-r--r--mbbsd/admin.c1087
-rw-r--r--mbbsd/register.c1811
-rw-r--r--mbbsd/user.c751
4 files changed, 1814 insertions, 1836 deletions
diff --git a/include/common.h b/include/common.h
index 1b51aced..24193642 100644
--- a/include/common.h
+++ b/include/common.h
@@ -6,6 +6,7 @@
#define DEFAULT_BOARD str_sysop
#define FN_PASSWD BBSHOME "/.PASSWDS" /* User records */
+#define FN_CHICKEN "chicken"
#define FN_USSONG "ussong" /* 點歌統計 */
#define FN_POST_NOTE "post.note" /* po文章備忘錄 */
#define FN_POST_BID "post.bid"
diff --git a/mbbsd/admin.c b/mbbsd/admin.c
index 0bb424db..d0efa3e1 100644
--- a/mbbsd/admin.c
+++ b/mbbsd/admin.c
@@ -164,9 +164,6 @@ search_key_user(const char *passwdfile, int mode)
else if ((!keytype || keytype == 7) &&
strcasestr(user.justify, key))
keymatch = user.justify;
- else if ((!keytype) &&
- strcasestr(user.mychicken.name, key))
- keymatch = user.mychicken.name;
}
if(keymatch) {
@@ -1061,1090 +1058,6 @@ int make_symbolic_link_interactively(int gid)
return 0;
}
-/* FIXME 真是一團垃圾
- *
- * fdata 用了太多 magic number
- * return value 應該是指 reason (return index + 1)
- * ans[0] 指的是帳管選擇的「錯誤的欄位」 (Register 選單裡看到的那些)
- */
-static int
-auto_scan(char fdata[][STRLEN], char ans[])
-{
- int good = 0;
- int count = 0;
- int i;
- char temp[10];
-
- if (!strncmp(fdata[1], "小", 2) || strstr(fdata[1], "丫")
- || strstr(fdata[1], "誰") || strstr(fdata[1], "不")) {
- ans[0] = '0';
- return 1;
- }
- strlcpy(temp, fdata[1], 3);
-
- /* 疊字 */
- if (!strncmp(temp, &(fdata[1][2]), 2)) {
- ans[0] = '0';
- return 1;
- }
- if (strlen(fdata[1]) >= 6) {
- if (strstr(fdata[1], "陳水扁")) {
- ans[0] = '0';
- return 1;
- }
- if (strstr("趙錢孫李周吳鄭王", temp))
- good++;
- else if (strstr("杜顏黃林陳官余辛劉", temp))
- good++;
- else if (strstr("蘇方吳呂李邵張廖應蘇", temp))
- good++;
- else if (strstr("徐謝石盧施戴翁唐", temp))
- good++;
- }
- if (!good)
- return 0;
-
- if (!strcmp(fdata[2], fdata[3]) ||
- !strcmp(fdata[2], fdata[4]) ||
- !strcmp(fdata[3], fdata[4])) {
- ans[0] = '4';
- return 5;
- }
- if (strstr(fdata[2], "大")) {
- if (strstr(fdata[2], "台") || strstr(fdata[2], "淡") ||
- strstr(fdata[2], "交") || strstr(fdata[2], "政") ||
- strstr(fdata[2], "清") || strstr(fdata[2], "警") ||
- strstr(fdata[2], "師") || strstr(fdata[2], "銘傳") ||
- strstr(fdata[2], "中央") || strstr(fdata[2], "成") ||
- strstr(fdata[2], "輔") || strstr(fdata[2], "東吳"))
- good++;
- } else if (strstr(fdata[2], "女中"))
- good++;
-
- if (strstr(fdata[3], "地球") || strstr(fdata[3], "宇宙") ||
- strstr(fdata[3], "信箱")) {
- ans[0] = '2';
- return 3;
- }
- if (strstr(fdata[3], "市") || strstr(fdata[3], "縣")) {
- if (strstr(fdata[3], "路") || strstr(fdata[3], "街")) {
- if (strstr(fdata[3], "號"))
- good++;
- }
- }
- for (i = 0; fdata[4][i]; i++) {
- if (isdigit((int)fdata[4][i]))
- count++;
- }
-
- if (count <= 4) {
- ans[0] = '3';
- return 4;
- } else if (count >= 7)
- good++;
-
- if (good >= 3) {
- ans[0] = 'y';
- return -1;
- } else
- return 0;
-}
-
-#define REJECT_REASONS (6)
-#define FN_REGISTER_LOG "register.log"
-
-// read count entries from regsrc to a temp buffer
-FILE *
-pull_regform(const char *regfile, char *workfn, int count)
-{
- FILE *fp = NULL;
-
- snprintf(workfn, PATHLEN, "%s.tmp", regfile);
- if (dashf(workfn)) {
- vmsg("其他 SYSOP 也在審核註冊申請單");
- return NULL;
- }
-
- // count < 0 means unlimited pulling
- Rename(regfile, workfn);
- if ((fp = fopen(workfn, "r")) == NULL) {
- vmsgf("系統錯誤,無法讀取註冊資料檔: %s", workfn);
- return NULL;
- }
- return fp;
-}
-
-// write all left in "remains" to regfn.
-void
-pump_regform(const char *regfn, FILE *remains)
-{
- // restore trailing tickets
- char buf[PATHLEN];
- FILE *fout = fopen(regfn, "at");
- if (!fout)
- return;
-
- while (fgets(buf, sizeof(buf), remains))
- fputs(buf, fout);
- fclose(fout);
-}
-
-/* 處理 Register Form */
-// TODO XXX process someone directly, according to target_uid.
-int
-scan_register_form(const char *regfile, int automode, const char *target_uid)
-{
- char genbuf[200];
- char *logfile = FN_REGISTER_LOG;
- char *field[] = {
- "uid", "name", "career", "addr", "phone", "email", NULL
- };
- char *finfo[] = {
- "帳號", "真實姓名", "服務單位", "目前住址",
- "連絡電話", "電子郵件信箱", NULL
- };
- char *reason[REJECT_REASONS+1] = {
- "輸入真實姓名",
- "詳填「(畢業)學校及『系』『級』」或「服務單位(含所屬縣市及職稱)」",
- "填寫完整的住址資料 (含縣市名稱, 台北市請含行政區域)",
- "詳填連絡電話 (含區域碼, 中間不用加 '-', '(', ')'等符號",
- "精確並完整填寫註冊申請表",
- "用中文填寫申請單",
- NULL
- };
- char *autoid = "AutoScan";
- userec_t muser;
- FILE *fn, *fout, *freg;
- char fdata[6][STRLEN];
- char fname[STRLEN] = "", buf[STRLEN];
- char ans[4], *ptr, *uid;
- int n = 0, unum = 0, tid = 0;
- int nSelf = 0, nAuto = 0;
-
- uid = cuser.userid;
- move(2, 0);
-
- fn = pull_regform(regfile, fname, -1);
- if (!fn)
- return -1;
-
- while( fgets(genbuf, STRLEN, fn) ){
- memset(fdata, 0, sizeof(fdata));
- do {
- if( genbuf[0] == '-' )
- break;
- if ((ptr = (char *)strstr(genbuf, ": "))) {
- *ptr = '\0';
- for (n = 0; field[n]; n++) {
- if (strcmp(genbuf, field[n]) == 0) {
- strlcpy(fdata[n], ptr + 2, sizeof(fdata[n]));
- if ((ptr = (char *)strchr(fdata[n], '\n')))
- *ptr = '\0';
- }
- }
- }
- } while( fgets(genbuf, STRLEN, fn) );
- tid ++;
-
- if ((unum = getuser(fdata[0], &muser)) == 0) {
- move(2, 0);
- clrtobot();
- outs("系統錯誤,查無此人\n\n");
- for (n = 0; field[n]; n++)
- prints("%s : %s\n", finfo[n], fdata[n]);
- pressanykey();
- } else {
- if (automode)
- uid = autoid;
-
- if ((!automode || !auto_scan(fdata, ans))) {
- uid = cuser.userid;
-
- move(1, 0);
- clrtobot();
- prints("帳號位置 : %d\n", unum);
- user_display(&muser, 1);
- move(14, 0);
- prints(ANSI_COLOR(1;32) "------------- "
- "請站長嚴格審核使用者資料,這是第 %d 份"
- "------------" ANSI_RESET "\n", tid);
- prints(" %-12s: %s\n", finfo[0], fdata[0]);
-#ifdef FOREIGN_REG
- prints("0.%-12s: %s%s\n", finfo[1], fdata[1],
- muser.uflag2 & FOREIGN ? " (外籍)" : "");
-#else
- prints("0.%-12s: %s\n", finfo[1], fdata[1]);
-#endif
- for (n = 2; field[n]; n++) {
- prints("%d.%-12s: %s\n", n - 1, finfo[n], fdata[n]);
- }
- if (muser.userlevel & PERM_LOGINOK) {
- ans[0] = getkey("此帳號已經完成註冊, "
- "更新(Y/N/Skip)?[N] ");
- if (ans[0] != 'y' && ans[0] != 's')
- ans[0] = 'd';
- } else {
- if (search_ulist(unum) == NULL)
- {
- move(b_lines, 0); clrtoeol();
- outs("是否接受此資料(Y/N/Q/Del/Skip)?[S] ");
- // FIXME if the user got online here
- ans[0] = igetch();
- }
- else
- ans[0] = 's';
- ans[0] = tolower(ans[0]);
- if (ans[0] != 'y' && ans[0] != 'n' &&
- ans[0] != 'q' && ans[0] != 'd' &&
- !('0' <= ans[0] && ans[0] < ('0' + REJECT_REASONS)))
- ans[0] = 's';
- ans[1] = 0;
- }
- nSelf++;
- } else
- nAuto++;
-
- switch (ans[0]) {
- case 'q':
- if ((freg = fopen(regfile, "a"))) {
- for (n = 0; field[n]; n++)
- fprintf(freg, "%s: %s\n", field[n], fdata[n]);
- fprintf(freg, "----\n");
- while (fgets(genbuf, STRLEN, fn))
- fputs(genbuf, freg);
- fclose(freg);
- }
- case 'd':
- break;
-
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- /* please confirm match REJECT_REASONS here */
- case 'n':
- if (ans[0] == 'n') {
- int nf = 0;
- move(8, 0);
- clrtobot();
- outs("請提出退回申請表原因,按 <enter> 取消\n");
- for (n = 0; n < REJECT_REASONS; n++)
- prints("%d) 請%s\n", n, reason[n]);
- outs("\n"); // preserved for prompt
- for (nf = 0; field[nf]; nf++)
- prints("%s: %s\n", finfo[nf], fdata[nf]);
- } else
- buf[0] = ans[0];
-
- if (ans[0] != 'n' ||
- getdata(9 + n, 0, "退回原因: ", buf, 60, DOECHO))
- if ((buf[0] - '0') >= 0 && (buf[0] - '0') < n) {
- int i;
- fileheader_t mhdr;
- char title[128], buf1[80];
- FILE *fp;
-
- sethomepath(buf1, muser.userid);
- stampfile(buf1, &mhdr);
- strlcpy(mhdr.owner, cuser.userid, sizeof(mhdr.owner));
- strlcpy(mhdr.title, "[註冊失敗]", TTLEN);
- mhdr.filemode = 0;
- sethomedir(title, muser.userid);
- if (append_record(title, &mhdr, sizeof(mhdr)) != -1) {
- char rejfn[PATHLEN];
- fp = fopen(buf1, "w");
-
- for(i = 0; buf[i] && i < sizeof(buf); i++){
- if (buf[i] >= '0' && buf[i] < '0'+n)
- {
- fprintf(fp, "[退回原因] 請%s\n",
- reason[buf[i] - '0']);
- }
- }
-
- fclose(fp);
-
- // build reject file
- setuserfile(rejfn, "justify.reject");
- Copy(buf1, rejfn);
- }
- if ((fout = fopen(logfile, "a"))) {
- for (n = 0; field[n]; n++)
- fprintf(fout, "%s: %s\n", field[n], fdata[n]);
- fprintf(fout, "Date: %s\n", Cdate(&now));
- fprintf(fout, "Rejected: %s [%s]\n----\n",
- uid, buf);
- fclose(fout);
- }
- break;
- }
- move(10, 0);
- clrtobot();
- outs("取消退回此註冊申請表");
- /* no break? */
-
- case 's':
- if ((freg = fopen(regfile, "a"))) {
- for (n = 0; field[n]; n++)
- fprintf(freg, "%s: %s\n", field[n], fdata[n]);
- fprintf(freg, "----\n");
- fclose(freg);
- }
- break;
-
- default:
- outs("以下使用者資料已經更新:\n");
- mail_muser(muser, "[註冊成功\囉]", "etc/registered");
-
-#if FOREIGN_REG_DAY > 0
- if(muser.uflag2 & FOREIGN)
- mail_muser(muser, "[出入境管理局]", "etc/foreign_welcome");
-#endif
-
- muser.userlevel |= (PERM_LOGINOK | PERM_POST);
- strlcpy(muser.realname, fdata[1], sizeof(muser.realname));
- strlcpy(muser.address, fdata[3], sizeof(muser.address));
- strlcpy(muser.email, fdata[5], sizeof(muser.email));
- snprintf(genbuf, sizeof(genbuf), "%s:%s:%s",
- fdata[4], fdata[2], uid);
- strlcpy(muser.justify, genbuf, sizeof(muser.justify));
-
- passwd_update(unum, &muser);
- // XXX TODO notify users?
- sendalert(muser.userid, ALERT_PWD_PERM); // force to reload perm
-
- sethomefile(buf, muser.userid, "justify");
- log_file(buf, LOG_CREAT, genbuf);
-
- if ((fout = fopen(logfile, "a"))) {
- for (n = 0; field[n]; n++)
- fprintf(fout, "%s: %s\n", field[n], fdata[n]);
- fprintf(fout, "Date: %s\n", Cdate(&now));
- fprintf(fout, "Approved: %s\n", uid);
- fprintf(fout, "----\n");
- fclose(fout);
- }
- sethomefile(genbuf, muser.userid, "justify.wait");
- unlink(genbuf);
- break;
- }
- }
- }
-
- fclose(fn);
- unlink(fname);
-
- move(0, 0);
- clrtobot();
-
- move(5, 0);
- prints("您審了 %d 份註冊單,AutoScan 審了 %d 份", nSelf, nAuto);
-
- pressanykey();
- return (0);
-}
-
-#ifdef EXP_ADMIN_REGFORM
-
-#define FORMS_IN_PAGE (10)
-#define REASON_LEN (60)
-static const char *reasonstr[REJECT_REASONS] = {
- "輸入真實姓名",
- "詳填(畢業)學校『系』『級』或服務單位(含所屬縣市及職稱)",
- "填寫完整的住址資料 (含縣市名稱, 台北市請含行政區域)",
- "詳填連絡電話 (含區碼, 中間不加 '-', '(', ')' 等符號)",
- "精確並完整填寫註冊申請表",
- "用中文填寫申請單",
-};
-
-#define REASON_FIRSTABBREV '0'
-#define REASON_IN_ABBREV(x) \
- ((x) >= REASON_FIRSTABBREV && (x) - REASON_FIRSTABBREV < REJECT_REASONS)
-#define REASON_EXPANDABBREV(x) reasonstr[(x) - REASON_FIRSTABBREV]
-
-static void
-prompt_regform_ui()
-{
- move(b_lines, 0);
- outs(ANSI_COLOR(30;47) " "
- ANSI_COLOR(31) "y" ANSI_COLOR(30) "接受 "
- ANSI_COLOR(31) "n" ANSI_COLOR(30) "拒絕 "
- ANSI_COLOR(31) "d" ANSI_COLOR(30) "刪除 "
- ANSI_COLOR(31) "s" ANSI_COLOR(30) "跳過 "
- ANSI_COLOR(31) "u" ANSI_COLOR(30) "復原 "
- " "
- ANSI_COLOR(31) "0-9jk↑↓" ANSI_COLOR(30) "移動 "
- ANSI_COLOR(31) "空白/PgDn" ANSI_COLOR(30) "儲存+下頁 "
- " "
- ANSI_COLOR(31) "q/END" ANSI_COLOR(30) "結束 "
- ANSI_RESET);
-}
-
-void
-resolve_reason(char *s, int y)
-{
- // should start with REASON_FIRSTABBREV
- const char *reason_prompt =
- " (0)真實姓名 (1)詳填系級 (2)完整住址"
- " (3)詳填電話 (4)確實填寫 (5)中文填寫";
-
- s[0] = 0;
- move(y, 0);
- outs(reason_prompt); outs("\n");
-
- do {
- getdata(y+1, 0,
- "退回原因: ", s, REASON_LEN, DOECHO);
-
- // convert abbrev reasons (format: single digit, or multiple digites)
- if (REASON_IN_ABBREV(s[0]))
- {
- if (s[1] == 0) // simple replace ment
- {
- strlcpy(s+2, REASON_EXPANDABBREV(s[0]),
- REASON_LEN-2);
- s[0] = 0xbd; // '請'[0];
- s[1] = 0xd0; // '請'[1];
- } else {
- // strip until all digites
- char *p = s;
- while (*p)
- {
- if (!REASON_IN_ABBREV(*p))
- *p = ' ';
- p++;
- }
- strip_blank(s, s);
- strlcat(s, " [多重原因]", REASON_LEN);
- }
- }
-
- if (strlen(s) < 4)
- {
- if (vmsg("原因太短。 要取消退回嗎? (y/N): ") == 'y')
- {
- *s = 0;
- return;
- }
- }
- } while (strlen(s) < 4);
-}
-
-void
-regform_accept(const char *userid, const char *justify)
-{
- char buf[PATHLEN];
- int unum = 0;
- userec_t muser;
-
- unum = getuser(userid, &muser);
- if (unum == 0)
- return; // invalid user
-
- muser.userlevel |= (PERM_LOGINOK | PERM_POST);
- strlcpy(muser.justify, justify, sizeof(muser.justify));
- // manual accept sets email to 'x'
- strlcpy(muser.email, "x", sizeof(muser.email));
-
- // handle files
- sethomefile(buf, muser.userid, "justify.wait");
- unlink(buf);
- sethomefile(buf, muser.userid, "justify.reject");
- unlink(buf);
- sethomefile(buf, muser.userid, "justify");
- log_filef(buf, LOG_CREAT, "%s\n", muser.justify);
-
- // update password file
- passwd_update(unum, &muser);
-
- // alert online users?
- sendalert(muser.userid, ALERT_PWD_PERM|ALERT_PWD_JUSTIFY); // force to reload perm
-
-#if FOREIGN_REG_DAY > 0
- if(muser.uflag2 & FOREIGN)
- mail_muser(muser, "[出入境管理局]", "etc/foreign_welcome");
- else
-#endif
- // last: send notification mail
- mail_muser(muser, "[註冊成功\囉]", "etc/registered");
-}
-
-void
-regform_reject(const char *userid, char *reason)
-{
- char buf[PATHLEN];
- FILE *fp = NULL;
- int unum = 0;
- userec_t muser;
-
- unum = getuser(userid, &muser);
- if (unum == 0)
- return; // invalid user
-
- muser.userlevel &= ~(PERM_LOGINOK | PERM_POST);
-
- // handle files
- sethomefile(buf, muser.userid, "justify.wait");
- unlink(buf);
-
- // update password file
- passwd_update(unum, &muser);
-
- // alert notify users?
- sendalert(muser.userid, ALERT_PWD_PERM); // force to reload perm
-
- // last: send notification
- mkuserdir(muser.userid);
- sethomefile(buf, muser.userid, "justify.reject");
- fp = fopen(buf, "wt");
- assert(fp);
- syncnow();
- fprintf(fp, "%s 註冊失敗。\n", Cdate(&now));
-
- // multiple abbrev loop
- if (REASON_IN_ABBREV(reason[0]))
- {
- int i = 0;
- for (i = 0; i < REASON_LEN && REASON_IN_ABBREV(reason[i]); i++)
- fprintf(fp, "[退回原因] 請%s\n", REASON_EXPANDABBREV(reason[i]));
- } else {
- fprintf(fp, "[退回原因] %s\n", reason);
- }
- fclose(fp);
- mail_muser(muser, "[註冊失敗]", buf);
-}
-
-// TODO define and use structure instead, even in reg request file.
-//
-typedef struct {
- // current format:
- // (optional) num: unum, date
- // [0] uid: xxxxx (IDLEN=12)
- // [1] name: RRRRRR (20)
- // [2] career: YYYYYYYYYYYYYYYYYYYYYYYYYY (40)
- // [3] addr: TTTTTTTTT (50)
- // [4] phone: 02DDDDDDDD (20)
- // [5] email: x (50) (deprecated)
- // [6] mobile: (deprecated)
- // [7] ----
- // lasthost: 16
- char userid[IDLEN+1];
-
- char exist;
- char online;
- char pad [ 5]; // IDLEN(12)+1+1+1+5=20
-
- char name [20];
- char career[40];
- char addr [50];
- char phone [20];
-} RegformEntry;
-
-int
-load_regform_entry(RegformEntry *pre, FILE *fp)
-{
- char buf[STRLEN];
- char *v;
-
- memset(pre, 0, sizeof(RegformEntry));
- while (fgets(buf, sizeof(buf), fp))
- {
- if (buf[0] == '-')
- break;
- buf[sizeof(buf)-1] = 0;
- v = strchr(buf, ':');
- if (v == NULL)
- continue;
- *v++ = 0;
- if (*v == ' ') v++;
- chomp(v);
-
- if (strcmp(buf, "uid") == 0)
- strlcpy(pre->userid, v, sizeof(pre->userid));
- else if (strcmp(buf, "name") == 0)
- strlcpy(pre->name, v, sizeof(pre->name));
- else if (strcmp(buf, "career") == 0)
- strlcpy(pre->career, v, sizeof(pre->career));
- else if (strcmp(buf, "addr") == 0)
- strlcpy(pre->addr, v, sizeof(pre->addr));
- else if (strcmp(buf, "phone") == 0)
- strlcpy(pre->phone, v, sizeof(pre->phone));
- }
- return pre->userid[0] ? 1 : 0;
-}
-
-int
-print_regform_entry(const RegformEntry *pre, FILE *fp, int close)
-{
- fprintf(fp, "uid: %s\n", pre->userid);
- fprintf(fp, "name: %s\n", pre->name);
- fprintf(fp, "career: %s\n", pre->career);
- fprintf(fp, "addr: %s\n", pre->addr);
- fprintf(fp, "phone: %s\n", pre->phone);
- fprintf(fp, "email: %s\n", "x");
- if (close)
- fprintf(fp, "----\n");
- return 1;
-}
-
-int
-append_regform(const RegformEntry *pre, const char *logfn,
- const char *varname, const char *varval1, const char *varval2)
-{
- FILE *fout = fopen(logfn, "at");
- if (!fout)
- return 0;
-
- print_regform_entry(pre, fout, 0);
- if (varname && *varname)
- {
- syncnow();
- fprintf(fout, "Date: %s\n", Cdate(&now));
- if (!varval1) varval1 = "";
- fprintf(fout, "%s: %s", varname, varval1);
- if (varval2) fprintf(fout, " %s", varval2);
- fprintf(fout, "\n");
- }
- // close it
- fprintf(fout, "----\n");
- fclose(fout);
- return 1;
-}
-
-// #define REGFORM_DISABLE_ONLINE_USER
-
-int
-handle_register_form(const char *regfile, int dryrun)
-{
- int unum = 0;
- int yMsg = FORMS_IN_PAGE*2+1;
- FILE *fp = NULL;
- userec_t muser;
- RegformEntry forms [FORMS_IN_PAGE];
- char ans [FORMS_IN_PAGE];
- char rejects[FORMS_IN_PAGE][REASON_LEN]; // reject reason length
- char fname [PATHLEN] = "";
- char justify[REGLEN+1];
- char rsn [REASON_LEN];
- int cforms = 0, // current loaded forms
- parsed = 0, // total parsed forms
- ci = 0, // cursor index
- ch = 0, // input key
- i, blanks;
- long fsz = 0, fpos = 0;
-
- // prepare reg tickets
- if (dryrun)
- {
- // directly open regfile to try
- fp = fopen(regfile, "rt");
- } else {
- fp = pull_regform(regfile, fname, -1);
- }
-
- if (!fp)
- return 0;
-
- // retreieve file info
- fpos = ftell(fp);
- fseek(fp, 0, SEEK_END);
- fsz = ftell(fp);
- fseek(fp, fpos, SEEK_SET);
- if (!fsz) fsz = 1;
-
- while (ch != 'q')
- {
- // initialize and prepare
- memset(ans, 0, sizeof(ans));
- memset(rejects, 0, sizeof(rejects));
- memset(forms, 0, sizeof(forms));
- cforms = 0;
-
- // load forms
- while (cforms < FORMS_IN_PAGE && load_regform_entry(&forms[cforms], fp))
- cforms++, parsed ++;
-
- // if no more forms then leave.
- // TODO what if regform error?
- if (cforms < 1)
- break;
-
- // adjust cursor if required
- if (ci >= cforms)
- ci = cforms-1;
-
- // display them all.
- clear();
- for (i = 0; i < cforms; i++)
- {
- // fetch user information
- memset(&muser, 0, sizeof(muser));
- unum = getuser(forms[i].userid, &muser);
- forms[i].exist = unum ? 1 : 0;
- if (unum) forms[i].online = search_ulist(unum) ? 1 : 0;
-
- // if already got login level, delete by default.
- if (!unum)
- ans[i] = 'd';
- else {
- if (muser.userlevel & PERM_LOGINOK)
- ans[i] = 'd';
-#ifdef REGFORM_DISABLE_ONLINE_USER
- else if (forms[i].online)
- ans[i] = 's';
-#endif // REGFORM_DISABLE_ONLINE_USER
- }
-
- // print
- move(i*2, 0);
- prints(" %2d%s %s%-12s " ANSI_RESET,
- i+1,
- (unum == 0) ? ANSI_COLOR(1;31) "D" :
- ( (muser.userlevel & PERM_LOGINOK) ?
- ANSI_COLOR(1;33) "Y" :
-#ifdef REGFORM_DISABLE_ONLINE_USER
- forms[i].online ? "s" :
-#endif
- "."),
- forms[i].online ? ANSI_COLOR(1;35) : ANSI_COLOR(1),
- forms[i].userid);
-
- prints( ANSI_COLOR(1;31) "%19s "
- ANSI_COLOR(1;32) "%-40s" ANSI_RESET"\n",
- forms[i].name, forms[i].career);
-
- move(i*2+1, 0);
- prints(" %s %-50s%20s\n",
- (muser.userlevel & PERM_NOREGCODE) ?
- ANSI_COLOR(1;31) "T" ANSI_RESET : " ",
- forms[i].addr, forms[i].phone);
- }
-
- // display page info
- {
- char msg[STRLEN];
- fpos = ftell(fp);
- if (fpos > fsz) fsz = fpos*10;
- snprintf(msg, sizeof(msg),
- " 已顯示 %d 份註冊單 (%2d%%) ",
- parsed, (int)(fpos*100/fsz));
- prints(ANSI_COLOR(7) "\n%78s" ANSI_RESET "\n", msg);
- }
-
- // handle user input
- prompt_regform_ui();
- ch = 0;
- while (ch != 'q' && ch != ' ') {
- ch = cursor_key(ci*2, 0);
- switch (ch)
- {
- // nav keys
- case KEY_UP:
- case 'k':
- if (ci > 0) ci--;
- break;
-
- case KEY_DOWN:
- case 'j':
- ch = 'j'; // go next
- break;
-
- // quick nav (assuming to FORMS_IN_PAGE=10)
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- ci = ch - '1';
- if (ci >= cforms) ci = cforms-1;
- break;
- case '0':
- ci = 10-1;
- if (ci >= cforms) ci = cforms-1;
- break;
-
- /*
- case KEY_HOME: ci = 0; break;
- case KEY_END: ci = cforms-1; break;
- */
-
- // abort
- case KEY_END:
- case 'q':
- ch = 'q';
- if (getans("確定要離開了嗎? (本頁變更將不會儲存) [y/N]: ") != 'y')
- {
- prompt_regform_ui();
- ch = 0;
- continue;
- }
- break;
-
- // prepare to go next page
- case KEY_PGDN:
- case ' ':
- ch = ' ';
-
- // solving blank (undecided entries)
- for (i = 0, blanks = 0; i < cforms; i++)
- if (ans[i] == 0) blanks ++;
-
- if (!blanks)
- break;
-
- // have more blanks
- ch = getans("尚未指定的 %d 個項目要: (S跳過/y通過/n拒絕/e繼續編輯): ",
- blanks);
-
- if (ch == 'e')
- {
- prompt_regform_ui();
- ch = 0;
- continue;
- }
- if (ch == 'y') {
- // do nothing.
- } else if (ch == 'n') {
- // query reject reason
- resolve_reason(rsn, yMsg);
- if (*rsn == 0)
- ch = 's';
- } else ch = 's';
-
- // filling answers
- for (i = 0; i < cforms; i++)
- {
- if (ans[i] != 0)
- continue;
- ans[i] = ch;
- if (ch != 'n')
- continue;
- strlcpy(rejects[i], rsn, REASON_LEN);
- }
-
- ch = ' '; // go to page mode!
- break;
-
- // function keys
- case 'y': // accept
-#ifdef REGFORM_DISABLE_ONLINE_USER
- if (forms[ci].online)
- {
- vmsg("暫不開放審核在線上使用者。");
- break;
- }
-#endif
- case 's': // skip
- case 'd': // delete
- case KEY_DEL: //delete
- if (ch == KEY_DEL) ch = 'd';
-
- grayout(ci*2, ci*2+1, GRAYOUT_DARK);
- move_ansi(ci*2, 4); outc(ch);
- ans[ci] = ch;
- ch = 'j'; // go next
- break;
-
- case 'u': // undo
-#ifdef REGFORM_DISABLE_ONLINE_USER
- if (forms[ci].online)
- {
- vmsg("暫不開放審核在線上使用者。");
- break;
- }
-#endif
- grayout(ci*2, ci*2+1, GRAYOUT_NORM);
- move_ansi(ci*2, 4); outc('.');
- ans[ci] = 0;
- ch = 'j'; // go next
- break;
-
- case 'n': // reject
-#ifdef REGFORM_DISABLE_ONLINE_USER
- if (forms[ci].online)
- {
- vmsg("暫不開放審核在線上使用者。");
- break;
- }
-#endif
- // query for reason
- resolve_reason(rejects[ci], yMsg);
- prompt_regform_ui();
-
- if (!rejects[ci][0])
- break;
-
- move(yMsg, 0);
- prints("退回 %s 註冊單原因:\n %s\n", forms[ci].userid, rejects[ci]);
-
- // do reject
- grayout(ci*2, ci*2+1, GRAYOUT_DARK);
- move_ansi(ci*2, 4); outc(ch);
- ans[ci] = ch;
- ch = 'j'; // go next
-
- break;
- } // switch(ch)
-
- // change cursor
- if (ch == 'j' && ++ci >= cforms)
- ci = cforms -1;
- } // while(ch != QUIT/SAVE)
-
- // if exit, we still need to skip all read forms
- if (ch == 'q')
- {
- for (i = 0; i < cforms; i++)
- ans[i] = 's';
- }
-
- // page complete (save).
- assert(ch == ' ' || ch == 'q');
-
- // save/commit if required.
- if (dryrun)
- {
- // prmopt for debug
- clear();
- stand_title("測試模式");
- outs("您正在執行測試模式,所以剛審的註冊單並不會生效。\n"
- "下面列出的是剛才您審完的結果:\n\n");
-
- for (i = 0; i < cforms; i++)
- {
- if (ans[i] == 'y')
- snprintf(justify, sizeof(justify), // build justify string
- "%s:%s:%s", forms[i].phone, forms[i].career, cuser.userid);
-
- prints("%2d. %-12s - %c %s\n", i+1, forms[i].userid, ans[i],
- ans[i] == 'n' ? rejects[i] :
- ans[i] == 'y' ? justify : "");
- }
- if (ch != 'q')
- pressanykey();
- }
- else
- {
- // real functionality
- for (i = 0; i < cforms; i++)
- {
- if (ans[i] == 'y')
- {
- // build justify string
- snprintf(justify, sizeof(justify),
- "%s:%s:%s", forms[i].phone, forms[i].career, cuser.userid);
-
- regform_accept(forms[i].userid, justify);
- // log form to FN_REGISTER_LOG
- append_regform(&forms[i], FN_REGISTER_LOG,
- "Approved", cuser.userid, NULL);
- }
- else if (ans[i] == 'n')
- {
- regform_reject(forms[i].userid, rejects[i]);
- // log form to FN_REGISTER_LOG
- append_regform(&forms[i], FN_REGISTER_LOG,
- "Rejected", cuser.userid, rejects[i]);
- }
- else if (ans[i] == 's')
- {
- // append form back to fn_register
- append_regform(&forms[i], fn_register,
- NULL, NULL, NULL);
- }
- }
- } // !dryrun
-
- } // while (ch != 'q')
-
- // cleaning left regforms
- if (!dryrun)
- {
- pump_regform(regfile, fp);
- fclose(fp);
- unlink(fname);
- } else {
- // directly close file should be OK.
- fclose(fp);
- }
-
- return 0;
-}
-
-#endif // EXP_ADMIN_REGFORM
-
-int
-m_register(void)
-{
- FILE *fn;
- int x, y, wid, len;
- char ans[4];
- char genbuf[200];
-
- if ((fn = fopen(fn_register, "r")) == NULL) {
- outs("目前並無新註冊資料");
- return XEASY;
- }
- stand_title("審核使用者註冊資料");
- y = 2;
- x = wid = 0;
-
- while (fgets(genbuf, STRLEN, fn) && x < 65) {
- if (strncmp(genbuf, "uid: ", 5) == 0) {
- move(y++, x);
- outs(genbuf + 5);
- len = strlen(genbuf + 5);
- if (len > wid)
- wid = len;
- if (y >= t_lines - 3) {
- y = 2;
- x += wid + 2;
- }
- }
- }
- fclose(fn);
- getdata(b_lines - 1, 0,
-#ifdef EXP_ADMIN_REGFORM
- "開始審核嗎(Auto自動/Yes手動/No不審/Exp新界面)?[N] ",
-#else
- "開始審核嗎(Auto自動/Yes手動/No不審)?[N] ",
-#endif
- ans, sizeof(ans), LCECHO);
- if (ans[0] == 'a')
- scan_register_form(fn_register, 1, NULL);
- else if (ans[0] == 'y')
- scan_register_form(fn_register, 0, NULL);
-
-#ifdef EXP_ADMIN_REGFORM
- else if (ans[0] == 'e')
- {
-#ifdef EXP_ADMIN_REGFORM_DRYRUN
- int dryrun = 0;
- if (getans("你要進行純測試(T)還是真的執行審核(y)?") == 'y')
- {
- vmsg("進入實際執行模式,所有審核動作都是真的。");
- dryrun = 0;
- } else {
- vmsg("測試模式。");
- dryrun = 1;
- }
- handle_register_form(fn_register, dryrun);
-#else
- // run directly.
- handle_register_form(fn_register, 0);
-#endif
- }
-#endif
-
- return 0;
-}
-
-int
-cat_register(void)
-{
- if (system("cat register.new.tmp >> register.new") == 0 &&
- unlink("register.new.tmp") == 0)
- vmsg("OK 嚕~~ 繼續去奮鬥吧!!");
- else
- vmsg("沒辦法CAT過去呢 去檢查一下系統吧!!");
- return 0;
-}
-
static void
give_id_money(const char *user_id, int money, const char *mail_title)
{
diff --git a/mbbsd/register.c b/mbbsd/register.c
index 8ec38316..6475c8dd 100644
--- a/mbbsd/register.c
+++ b/mbbsd/register.c
@@ -1,6 +1,10 @@
/* $Id$ */
#include "bbs.h"
+////////////////////////////////////////////////////////////////////////////
+// Password Hash
+////////////////////////////////////////////////////////////////////////////
+
// prototype of crypt()
char *crypt(const char *key, const char *salt);
@@ -44,7 +48,50 @@ checkpasswd(const char *passwd, char *plain)
return ok;
}
-/* 檢查 user 註冊情況 */
+////////////////////////////////////////////////////////////////////////////
+// Value Validation
+////////////////////////////////////////////////////////////////////////////
+static int HaveRejectStr(const char *s, const char **rej)
+{
+ int i;
+ char *ptr, *rejectstr[] =
+ {"幹", "阿", "不", "你媽", "某", "笨", "呆", "..", "xx",
+ "你管", "管我", "猜", "天才", "超人",
+ "ㄅ", "ㄆ", "ㄇ", "ㄈ", "ㄉ", "ㄊ", "ㄋ", "ㄌ", "ㄍ", "ㄎ", "ㄏ",
+ "ㄐ", "ㄑ", "ㄒ", "ㄓ",/*"ㄔ",*/ "ㄕ", "ㄖ", "ㄗ", "ㄘ", "ㄙ",
+ "ㄧ", "ㄨ", "ㄩ", "ㄚ", "ㄛ", "ㄜ", "ㄝ", "ㄞ", "ㄟ", "ㄠ", "ㄡ",
+ "ㄢ", "ㄣ", "ㄤ", "ㄥ", "ㄦ", NULL};
+
+ if( rej != NULL )
+ for( i = 0 ; rej[i] != NULL ; ++i )
+ if( strstr(s, rej[i]) )
+ return 1;
+
+ for( i = 0 ; rejectstr[i] != NULL ; ++i )
+ if( strstr(s, rejectstr[i]) )
+ return 1;
+
+ if( (ptr = strstr(s, "ㄔ")) != NULL ){
+ if( ptr != s && strncmp(ptr - 1, "都市", 4) == 0 )
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+removespace(char *s)
+{
+ int i, index;
+
+ for (i = 0, index = 0; s[i]; i++) {
+ if (s[i] != ' ')
+ s[index++] = s[i];
+ }
+ s[index] = '\0';
+ return index;
+}
+
int
bad_user_id(const char *userid)
{
@@ -71,6 +118,94 @@ bad_user_id(const char *userid)
return 0;
}
+char *isvalidname(char *rname)
+{
+#ifdef FOREIGN_REG
+ return NULL;
+#else
+ const char *rejectstr[] =
+ {"肥", "胖", "豬頭", "小白", "小明", "路人", "老王", "老李", "寶貝",
+ "先生", "帥哥", "老頭", "小姊", "小姐", "美女", "小妹", "大頭",
+ "公主", "同學", "寶寶", "公子", "大頭", "小小", "小弟", "小妹",
+ "妹妹", "嘿", "嗯", "爺爺", "大哥", "無",
+ NULL};
+ if( removespace(rname) && rname[0] < 0 &&
+ strlen(rname) >= 4 &&
+ !HaveRejectStr(rname, rejectstr) &&
+ strncmp(rname, "小", 2) != 0 && //起頭是「小」
+ strncmp(rname, "我是", 4) != 0 && //起頭是「我是」
+ !(strlen(rname) == 4 && strncmp(&rname[2], "兒", 2) == 0) &&
+ !(strlen(rname) >= 4 && strncmp(&rname[0], &rname[2], 2) == 0))
+ return NULL;
+ return "您的輸入不正確";
+#endif
+
+}
+
+static char *isvalidcareer(char *career)
+{
+#ifndef FOREIGN_REG
+ const char *rejectstr[] = {NULL};
+ if (!(removespace(career) && career[0] < 0 && strlen(career) >= 6) ||
+ strcmp(career, "家裡") == 0 || HaveRejectStr(career, rejectstr) )
+ return "您的輸入不正確";
+ if (strcmp(&career[strlen(career) - 2], "大") == 0 ||
+ strcmp(&career[strlen(career) - 4], "大學") == 0 ||
+ strcmp(career, "學生大學") == 0)
+ return "麻煩請加學校系所";
+ if (strcmp(career, "學生高中") == 0)
+ return "麻煩輸入學校名稱";
+#else
+ if( strlen(career) < 6 )
+ return "您的輸入不正確";
+#endif
+ return NULL;
+}
+
+char *isvalidaddr(char *addr)
+{
+ const char *rejectstr[] =
+ {"地球", "銀河", "火星", NULL};
+
+ // addr[0] > 0: check if address is starting by Chinese.
+ if (!removespace(addr) || strlen(addr) < 15)
+ return "這個地址似乎並不完整";
+ if (strstr(addr, "信箱") != NULL || strstr(addr, "郵政") != NULL)
+ return "抱歉我們不接受郵政信箱";
+ if ((strstr(addr, "市") == NULL && strstr(addr, "巿") == NULL &&
+ strstr(addr, "縣") == NULL && strstr(addr, "室") == NULL) ||
+ HaveRejectStr(addr, rejectstr) ||
+ strcmp(&addr[strlen(addr) - 2], "段") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "路") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "巷") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "弄") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "區") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "市") == 0 ||
+ strcmp(&addr[strlen(addr) - 2], "街") == 0 )
+ return "這個地址似乎並不完整";
+ return NULL;
+}
+
+static char *isvalidphone(char *phone)
+{
+ int i;
+ for( i = 0 ; phone[i] != 0 ; ++i )
+ if( !isdigit((int)phone[i]) )
+ return "請不要加分隔符號";
+ if (!removespace(phone) ||
+ strlen(phone) < 9 ||
+ strstr(phone, "00000000") != NULL ||
+ strstr(phone, "22222222") != NULL ) {
+ return "這個電話號碼並不正確(請含區碼)" ;
+ }
+ return NULL;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+// Account Expiring
+////////////////////////////////////////////////////////////////////////////
+
/* -------------------------------- */
/* New policy for allocate new user */
/* (a) is the worst user currently */
@@ -124,6 +259,144 @@ check_and_expire_account(int uid, const userec_t * urec)
return val;
}
+////////////////////////////////////////////////////////////////////////////
+// Regcode Support
+////////////////////////////////////////////////////////////////////////////
+
+#define REGCODE_INITIAL "v6" // always 2 characters
+
+static char *
+getregfile(char *buf)
+{
+ // not in user's home because s/he could zip his/her home
+ snprintf(buf, PATHLEN, "jobspool/.regcode.%s", cuser.userid);
+ return buf;
+}
+
+static char *
+makeregcode(char *buf)
+{
+ char fpath[PATHLEN];
+ int fd, i;
+ // prevent ambigious characters: oOlI
+ const char *alphabet = "qwertyuipasdfghjkzxcvbnmoQWERTYUPASDFGHJKLZXCVBNM";
+
+ /* generate a new regcode */
+ buf[13] = 0;
+ buf[0] = REGCODE_INITIAL[0];
+ buf[1] = REGCODE_INITIAL[1];
+ for( i = 2 ; i < 13 ; ++i )
+ buf[i] = alphabet[random() % strlen(alphabet)];
+
+ getregfile(fpath);
+ if( (fd = open(fpath, O_WRONLY | O_CREAT, 0600)) == -1 ){
+ perror("open");
+ exit(1);
+ }
+ write(fd, buf, 13);
+ close(fd);
+
+ return buf;
+}
+
+static char *
+getregcode(char *buf)
+{
+ int fd;
+ char fpath[PATHLEN];
+
+ getregfile(fpath);
+ if( (fd = open(fpath, O_RDONLY)) == -1 ){
+ buf[0] = 0;
+ return buf;
+ }
+ read(fd, buf, 13);
+ close(fd);
+ buf[13] = 0;
+ return buf;
+}
+
+void
+delregcodefile(void)
+{
+ char fpath[PATHLEN];
+ getregfile(fpath);
+ unlink(fpath);
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Justify Utilities
+////////////////////////////////////////////////////////////////////////////
+
+static void
+justify_wait(char *userid, char *phone, char *career,
+ char *rname, char *addr, char *mobile)
+{
+ char buf[PATHLEN];
+ sethomefile(buf, userid, "justify.wait");
+ if (phone[0] != 0) {
+ FILE* fn = fopen(buf, "w");
+ assert(fn);
+ fprintf(fn, "%s\n%s\ndummy\n%s\n%s\n%s\n",
+ phone, career, rname, addr, mobile);
+ fclose(fn);
+ }
+}
+
+static void email_justify(const userec_t *muser)
+{
+ char tmp[IDLEN + 1], buf[256], genbuf[256];
+ /*
+ * It is intended to use BBSENAME instead of BBSNAME here.
+ * Because recently many poor users with poor mail clients
+ * (or evil mail servers) cannot handle/decode Chinese
+ * subjects (BBSNAME) correctly, so we'd like to use
+ * BBSENAME here to prevent subject being messed up.
+ * And please keep BBSENAME short or it may be truncated
+ * by evil mail servers.
+ */
+ snprintf(buf, sizeof(buf),
+ " " BBSENAME " - [ %s ]", makeregcode(genbuf));
+
+ strlcpy(tmp, cuser.userid, sizeof(tmp));
+ // XXX dirty, set userid=SYSOP
+ strlcpy(cuser.userid, str_sysop, sizeof(cuser.userid));
+#ifdef HAVEMOBILE
+ if (strcmp(muser->email, "m") == 0 || strcmp(muser->email, "M") == 0)
+ mobile_message(mobile, buf);
+ else
+#endif
+ bsmtp("etc/registermail", buf, muser->email);
+ strlcpy(cuser.userid, tmp, sizeof(cuser.userid));
+ move(20,0);
+ clrtobot();
+ outs("我們即將寄出認證信 (您應該會在 10 分鐘內收到)\n"
+ "收到後您可以根據認證信標題的認證碼\n"
+ "輸入到 (U)ser -> (R)egister 後就可以完成註冊");
+ pressanykey();
+ return;
+}
+
+
+/* 使用者填寫註冊表格 */
+static void
+getfield(int line, const char *info, const char *desc, char *buf, int len)
+{
+ char prompt[STRLEN];
+ char genbuf[200];
+
+ // clear first
+ move(line+1, 0); clrtoeol();
+ move(line, 0); clrtoeol();
+ prints(" 原先設定:%-30.30s (%s)", buf, info);
+ snprintf(prompt, sizeof(prompt), " %s:", desc);
+ if (getdata_str(line + 1, 0, prompt, genbuf, len, DOECHO, buf))
+ strcpy(buf, genbuf);
+ move(line+1, 0); clrtoeol();
+ move(line, 0); clrtoeol();
+ prints(" %s:%s", desc, buf);
+}
+
int
setupnewuser(const userec_t *user)
@@ -197,8 +470,9 @@ setupnewuser(const userec_t *user)
return uid;
}
-// checking functions (in user.c now...)
-char *isvalidname(char *rname);
+/////////////////////////////////////////////////////////////////////////////
+// New Registration (Phase 1)
+/////////////////////////////////////////////////////////////////////////////
void
new_register(void)
@@ -460,5 +734,1536 @@ check_register(void)
#endif
}
}
+
+/////////////////////////////////////////////////////////////////////////////
+// User Registration (Phase 2)
+/////////////////////////////////////////////////////////////////////////////
+
+static void
+toregister(char *email, char *phone, char *career,
+ char *rname, char *addr, char *mobile)
+{
+ FILE *fn = NULL;
+
+ justify_wait(cuser.userid, phone, career, rname, addr, mobile);
+
+ clear();
+ stand_title("認證設定");
+ if (cuser.userlevel & PERM_NOREGCODE){
+ strcpy(email, "x");
+ goto REGFORM2;
+ }
+ move(1, 0);
+ outs("您好, 本站認證認證的方式有:\n"
+ " 1.若您有 E-Mail (本站不接受 yahoo, kimo等免費的 E-Mail)\n"
+ " 請輸入您的 E-Mail , 我們會寄發含有認證碼的信件給您\n"
+ " 收到後請到 (U)ser => (R)egister 輸入認證碼, 即可通過認證\n"
+ "\n"
+ " 2.若您沒有 E-Mail 或是一直無法收到認證信, 請輸入 x \n"
+ " 會有站長親自人工審核註冊資料," ANSI_COLOR(1;33)
+ "但注意這可能會花上數週或更多時間。" ANSI_RESET "\n"
+ "**********************************************************\n"
+ "* 注意! *\n"
+ "* 通常應該會在輸入完成後十分鐘內收到認證信, 若過久未收到 *\n"
+ "* 請到郵件垃圾桶檢查是否被當作垃圾信(SPAM)了,另外若是 *\n"
+ "* 輸入後發生認證碼錯誤請重填一次 E-Mail *\n"
+ "**********************************************************\n");
+
+#ifdef HAVEMOBILE
+ outs(" 3.若您有手機門號且想採取手機簡訊認證的方式 , 請輸入 m \n"
+ " 我們將會寄發含有認證碼的簡訊給您 \n"
+ " 收到後請到(U)ser => (R)egister 輸入認證碼, 即可通過認證\n");
+#endif
+
+ while (1) {
+ email[0] = 0;
+ getfield(15, "身分認證用", "E-Mail Address", email, 50);
+ if (strcmp(email, "x") == 0 || strcmp(email, "X") == 0)
+ break;
+#ifdef HAVEMOBILE
+ else if (strcmp(email, "m") == 0 || strcmp(email, "M") == 0) {
+ if (isvalidmobile(mobile)) {
+ char yn[3];
+ getdata(16, 0, "請再次確認您輸入的手機號碼正確嘛? [y/N]",
+ yn, sizeof(yn), LCECHO);
+ if (yn[0] == 'Y' || yn[0] == 'y')
+ break;
+ } else {
+ move(15, 0); clrtobot();
+ move(17, 0);
+ outs("指定的手機號碼不正確,"
+ "若您無手機門號請選擇其他方式認證");
+ }
+
+ }
+#endif
+ else if (isvalidemail(email)) {
+ char yn[3];
+#ifdef USE_EMAILDB
+ int email_count = emaildb_check_email(email, strlen(email));
+
+ if (email_count < 0) {
+ move(15, 0); clrtobot();
+ move(17, 0);
+ outs("暫時不允許\ email 認證註冊, 請稍後再試\n");
+ pressanykey();
+ return;
+ } else if (email_count >= EMAILDB_LIMIT) {
+ move(15, 0); clrtobot();
+ move(17, 0);
+ outs("指定的 E-Mail 已註冊過多帳號, 請使用其他 E-Mail, 或輸入 x 採手動認證\n");
+ outs("但注意手動認證通常會花上數週以上的時間。\n");
+ } else {
+#endif
+ getdata(16, 0, "請再次確認您輸入的 E-Mail 位置正確嘛? [y/N]",
+ yn, sizeof(yn), LCECHO);
+ if (yn[0] == 'Y' || yn[0] == 'y')
+ break;
+#ifdef USE_EMAILDB
+ }
+#endif
+ } else {
+ move(15, 0); clrtobot();
+ move(17, 0);
+ outs("指定的 E-Mail 不正確, 若您無 E-Mail 請輸入 x 由站長手動認證\n");
+ outs("但注意手動認證通常會花上數週以上的時間。\n");
+ }
+ }
+#ifdef USE_EMAILDB
+ if (emaildb_update_email(cuser.userid, strlen(cuser.userid),
+ email, strlen(email)) < 0) {
+ move(15, 0); clrtobot();
+ move(17, 0);
+ outs("暫時不允許\ email 認證註冊, 請稍後再試\n");
+ pressanykey();
+ return;
+ }
+#endif
+ strlcpy(cuser.email, email, sizeof(cuser.email));
+ REGFORM2:
+ if (strcasecmp(email, "x") == 0) { /* 手動認證 */
+ if ((fn = fopen(fn_register, "a"))) {
+ fprintf(fn, "num: %d, %s", usernum, ctime4(&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, "mobile: %s\n", mobile);
+ fprintf(fn, "email: %s\n", email);
+ fprintf(fn, "----\n");
+ fclose(fn);
+ // save justify information
+ snprintf(cuser.justify, sizeof(cuser.justify),
+ "%s:%s:<Manual>", phone, career);
+ }
+ // XXX what if we cannot open register form?
+ } else {
+ // register by mail of phone
+ snprintf(cuser.justify, sizeof(cuser.justify),
+ "%s:%s:<Email>", phone, career);
+#ifdef HAVEMOBILE
+ if (phone != NULL && email[1] == 0 && tolower(email[0]) == 'm')
+ sprintf(cuser.justify, sizeof(cuser.justify),
+ "%s:%s:<Mobile>", phone, career);
+#endif
+ email_justify(&cuser);
+ }
+}
+
+
+int
+u_register(void)
+{
+ char rname[20], addr[50], mobile[16];
+#ifdef FOREIGN_REG
+ char fore[2];
+#endif
+ char phone[20], career[40], email[50], birthday[11], sex_is[2];
+ unsigned char year, mon, day;
+ char inregcode[14], regcode[50];
+ char ans[3], *ptr, *errcode;
+ char genbuf[200];
+ FILE *fn;
+
+ if (cuser.userlevel & PERM_LOGINOK) {
+ outs("您的身份確認已經完成,不需填寫申請表");
+ return XEASY;
+ }
+ if ((fn = fopen(fn_register, "r"))) {
+ int i =0;
+ while (fgets(genbuf, STRLEN, fn)) {
+ if ((ptr = strchr(genbuf, '\n')))
+ *ptr = '\0';
+ if (strncmp(genbuf, "uid: ", 5) != 0)
+ continue;
+ i++;
+ if(strcmp(genbuf + 5, cuser.userid) != 0)
+ continue;
+ fclose(fn);
+ /* idiots complain about this, so bug them */
+ clear();
+ move(3, 0);
+ prints(" 您的註冊申請單尚在處理中(處理順位: %d),請耐心等候\n\n", i);
+ outs(" 如果您已收到註冊碼卻看到這個畫面,那代表您在使用 Email 註冊後\n");
+ outs(" " ANSI_COLOR(1;31) "又另外申請了站長直接人工審核的註冊申請單。"
+ ANSI_RESET "\n\n");
+ // outs("該死,都不看說明的...\n");
+ outs(" 進入人工審核程序後 Email 註冊自動失效,有註冊碼也沒用,\n");
+ outs(" 要等到審核完成 (會多花很多時間,通常起碼數天) ,所以請耐心等候。\n\n");
+
+ /* 下面是國王的 code 所需要的 message */
+#if 0
+ outs(" 另外請注意,若站長審註冊單時您正在站上則會無法審核、自動跳過。\n");
+ outs(" 所以等候審核時請勿掛站。若超過兩三天仍未被審到,通常就是這個原因。\n");
+#endif
+
+ vmsg("您的註冊申請單尚在處理中");
+ return FULLUPDATE;
+ }
+ fclose(fn);
+ }
+ strlcpy(rname, cuser.realname, sizeof(rname));
+ strlcpy(addr, cuser.address, sizeof(addr));
+ strlcpy(email, cuser.email, sizeof(email));
+ if (cuser.mobile)
+ snprintf(mobile, sizeof(mobile), "0%09d", cuser.mobile);
+ else
+ mobile[0] = 0;
+ if (cuser.month == 0 && cuser.day == 0 && cuser.year == 0)
+ birthday[0] = 0;
+ else
+ snprintf(birthday, sizeof(birthday), "%04i/%02i/%02i",
+ 1900 + cuser.year, cuser.month, cuser.day);
+ sex_is[0] = (cuser.sex % 8) + '1';
+ sex_is[1] = 0;
+ career[0] = phone[0] = '\0';
+ sethomefile(genbuf, cuser.userid, "justify.wait");
+ if ((fn = fopen(genbuf, "r"))) {
+ fgets(genbuf, sizeof(genbuf), fn);
+ chomp(genbuf);
+ strlcpy(phone, genbuf, sizeof(phone));
+
+ fgets(genbuf, sizeof(genbuf), fn);
+ chomp(genbuf);
+ strlcpy(career, genbuf, sizeof(career));
+
+ fgets(genbuf, sizeof(genbuf), fn); // old version compatible
+
+ fgets(genbuf, sizeof(genbuf), fn);
+ chomp(genbuf);
+ strlcpy(rname, genbuf, sizeof(rname));
+
+ fgets(genbuf, sizeof(genbuf), fn);
+ chomp(genbuf);
+ strlcpy(addr, genbuf, sizeof(addr));
+
+ fgets(genbuf, sizeof(genbuf), fn);
+ chomp(genbuf);
+ strlcpy(mobile, genbuf, sizeof(mobile));
+
+ fclose(fn);
+ }
+
+ if (cuser.userlevel & PERM_NOREGCODE) {
+ vmsg("您不被允許\使用認證碼認證。請填寫註冊申請單");
+ goto REGFORM;
+ }
+
+ // getregcode(regcode);
+
+ // XXX why check by year?
+ // birthday is moved to earlier, so let's check email instead.
+ if (cuser.email[0] && // cuser.year != 0 && /* 已經第一次填過了~ ^^" */
+ strcmp(cuser.email, "x") != 0 && /* 上次手動認證失敗 */
+ strcmp(cuser.email, "X") != 0)
+ {
+ clear();
+ stand_title("EMail認證");
+ move(2, 0);
+
+ prints("請輸入您的認證碼。(由 %s 開頭無空白的十三碼)\n"
+ "或輸入 x 來重新填寫 E-Mail 或改由站長手動認證\n", REGCODE_INITIAL);
+ inregcode[0] = 0;
+
+ do{
+ getdata(10, 0, "您的認證碼:",
+ inregcode, sizeof(inregcode), DOECHO);
+ if( strcmp(inregcode, "x") == 0 || strcmp(inregcode, "X") == 0 )
+ break;
+ if( strlen(inregcode) != 13 || inregcode[0] == ' ')
+ vmsg("認證碼輸入不完整,總共應有十三碼,沒有空白字元。");
+ else if( inregcode[0] != REGCODE_INITIAL[0] || inregcode[1] != REGCODE_INITIAL[1] ) {
+ /* old regcode */
+ vmsg("輸入的認證碼錯誤," // "或因系統昇級已失效,"
+ "請輸入 x 重填一次 E-Mail");
+ }
+ else
+ break;
+ } while( 1 );
+
+ // make it case insensitive.
+ if (strcasecmp(inregcode, getregcode(regcode)) == 0) {
+ int unum;
+ delregcodefile();
+ if ((unum = searchuser(cuser.userid, NULL)) == 0) {
+ vmsg("系統錯誤,查無此人!");
+ u_exit("getuser error");
+ exit(0);
+ }
+ mail_muser(cuser, "[註冊成功\囉]", "etc/registeredmail");
+#if FOREIGN_REG_DAY > 0
+ if(cuser.uflag2 & FOREIGN)
+ mail_muser(cuser, "[出入境管理局]", "etc/foreign_welcome");
+#endif
+ cuser.userlevel |= (PERM_LOGINOK | PERM_POST);
+ outs("\n註冊成功\, 重新上站後將取得完整權限\n"
+ "請按下任一鍵跳離後重新上站~ :)");
+ sethomefile(genbuf, cuser.userid, "justify.wait");
+ unlink(genbuf);
+ snprintf(cuser.justify, sizeof(cuser.justify),
+ "%s:%s:email", phone, career);
+ sethomefile(genbuf, cuser.userid, "justify");
+ log_file(genbuf, LOG_CREAT, cuser.justify);
+ pressanykey();
+ u_exit("registed");
+ exit(0);
+ return QUIT;
+ } else if (strcasecmp(inregcode, "x") != 0) {
+ if (regcode[0])
+ {
+ vmsg("認證碼錯誤!");
+ return FULLUPDATE;
+ }
+ else
+ {
+ vmsg("認證碼已過期,請重新註冊。");
+ toregister(email, phone, career, rname, addr, mobile);
+ return FULLUPDATE;
+ }
+ } else {
+ toregister(email, phone, career, rname, addr, mobile);
+ return FULLUPDATE;
+ }
+ }
+
+ REGFORM:
+ getdata(b_lines - 1, 0, "您確定要填寫註冊單嗎(Y/N)?[N] ",
+ ans, 3, LCECHO);
+ if (ans[0] != 'y')
+ return FULLUPDATE;
+
+ move(2, 0);
+ clrtobot();
+ while (1) {
+ clear();
+ move(1, 0);
+ prints("%s(%s) 您好,請據實填寫以下的資料:",
+ cuser.userid, cuser.nickname);
+#ifdef FOREIGN_REG
+ fore[0] = 'y';
+ fore[1] = 0;
+ getfield(2, "Y/n", "是否現在住在台灣", fore, 2);
+ if (fore[0] == 'n')
+ fore[0] |= FOREIGN;
+ else
+ fore[0] = 0;
+#endif
+ while (1) {
+ getfield(8,
+#ifdef FOREIGN_REG
+ "請用本名",
+#else
+ "請用中文",
+#endif
+ "真實姓名", rname, 20);
+ if( (errcode = isvalidname(rname)) == NULL )
+ break;
+ else
+ vmsg(errcode);
+ }
+
+ move(11, 0);
+ outs(" 請盡量詳細的填寫您的服務單位,大專院校請麻煩"
+ "加" ANSI_COLOR(1;33) "系所" ANSI_RESET ",公司單位請加" ANSI_COLOR(1;33) "職稱" ANSI_RESET ",\n"
+ " 暫無工作請麻煩填寫" ANSI_COLOR(1;33) "畢業學校" ANSI_RESET "。\n");
+ while (1) {
+ getfield(9, "(畢業)學校(含" ANSI_COLOR(1;33) "系所年級" ANSI_RESET ")或單位職稱",
+ "服務單位", career, 40);
+ if( (errcode = isvalidcareer(career)) == NULL )
+ break;
+ else
+ vmsg(errcode);
+ }
+ move(10, 0); clrtobot();
+ while (1) {
+ getfield(10, "含" ANSI_COLOR(1;33) "縣市" ANSI_RESET "及門寢號碼"
+ "(台北請加" ANSI_COLOR(1;33) "行政區" ANSI_RESET ")",
+ "目前住址", addr, sizeof(addr));
+ if( (errcode = isvalidaddr(addr)) == NULL
+#ifdef FOREIGN_REG
+ || fore[0]
+#endif
+ )
+ break;
+ else
+ vmsg(errcode);
+ }
+ while (1) {
+ getfield(11, "不加-(), 包括長途區號", "連絡電話", phone, 11);
+ if( (errcode = isvalidphone(phone)) == NULL )
+ break;
+ else
+ vmsg(errcode);
+ }
+ getfield(12, "只輸入數字 如:0912345678 (可不填)",
+ "手機號碼", mobile, 20);
+ while (1) {
+ getfield(13, "西元/月月/日日 如:1984/02/29", "生日", birthday, sizeof(birthday));
+ if (birthday[0] == 0) {
+ snprintf(birthday, sizeof(birthday), "%04i/%02i/%02i",
+ 1900 + cuser.year, cuser.month, cuser.day);
+ mon = cuser.month;
+ day = cuser.day;
+ year = cuser.year;
+ } else {
+ int y, m, d;
+ if (ParseDate(birthday, &y, &m, &d)) {
+ vmsg("您的輸入不正確");
+ continue;
+ }
+ mon = (unsigned char)m;
+ day = (unsigned char)d;
+ year = (unsigned char)(y - 1900);
+ }
+ if (year < 40) {
+ vmsg("您的輸入不正確");
+ continue;
+ }
+ break;
+ }
+ getfield(14, "1.葛格 2.姐接 ", "性別", sex_is, 2);
+ getdata(20, 0, "以上資料是否正確(Y/N)?(Q)取消註冊 [N] ",
+ ans, 3, LCECHO);
+ if (ans[0] == 'q')
+ return 0;
+ if (ans[0] == 'y')
+ break;
+ }
+ strlcpy(cuser.realname, rname, sizeof(cuser.realname));
+ strlcpy(cuser.address, addr, sizeof(cuser.address));
+ strlcpy(cuser.email, email, sizeof(cuser.email));
+ cuser.mobile = atoi(mobile);
+ cuser.sex = (sex_is[0] - '1') % 8;
+ cuser.month = mon;
+ cuser.day = day;
+ cuser.year = year;
+#ifdef FOREIGN_REG
+ if (fore[0])
+ cuser.uflag2 |= FOREIGN;
+ else
+ cuser.uflag2 &= ~FOREIGN;
+#endif
+ trim(career);
+ trim(addr);
+ trim(phone);
+
+ toregister(email, phone, career, rname, addr, mobile);
+
+ // update cuser
+ passwd_update(usernum, &cuser);
+
+ return FULLUPDATE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Administration (SYSOP Validation)
+/////////////////////////////////////////////////////////////////////////////
+
+////////////
+/* FIXME 真是一團垃圾
+ *
+ * fdata 用了太多 magic number
+ * return value 應該是指 reason (return index + 1)
+ * ans[0] 指的是帳管選擇的「錯誤的欄位」 (Register 選單裡看到的那些)
+ */
+static int
+auto_scan(char fdata[][STRLEN], char ans[])
+{
+ int good = 0;
+ int count = 0;
+ int i;
+ char temp[10];
+
+ if (!strncmp(fdata[1], "小", 2) || strstr(fdata[1], "丫")
+ || strstr(fdata[1], "誰") || strstr(fdata[1], "不")) {
+ ans[0] = '0';
+ return 1;
+ }
+ strlcpy(temp, fdata[1], 3);
+
+ /* 疊字 */
+ if (!strncmp(temp, &(fdata[1][2]), 2)) {
+ ans[0] = '0';
+ return 1;
+ }
+ if (strlen(fdata[1]) >= 6) {
+ if (strstr(fdata[1], "陳水扁")) {
+ ans[0] = '0';
+ return 1;
+ }
+ if (strstr("趙錢孫李周吳鄭王", temp))
+ good++;
+ else if (strstr("杜顏黃林陳官余辛劉", temp))
+ good++;
+ else if (strstr("蘇方吳呂李邵張廖應蘇", temp))
+ good++;
+ else if (strstr("徐謝石盧施戴翁唐", temp))
+ good++;
+ }
+ if (!good)
+ return 0;
+
+ if (!strcmp(fdata[2], fdata[3]) ||
+ !strcmp(fdata[2], fdata[4]) ||
+ !strcmp(fdata[3], fdata[4])) {
+ ans[0] = '4';
+ return 5;
+ }
+ if (strstr(fdata[2], "大")) {
+ if (strstr(fdata[2], "台") || strstr(fdata[2], "淡") ||
+ strstr(fdata[2], "交") || strstr(fdata[2], "政") ||
+ strstr(fdata[2], "清") || strstr(fdata[2], "警") ||
+ strstr(fdata[2], "師") || strstr(fdata[2], "銘傳") ||
+ strstr(fdata[2], "中央") || strstr(fdata[2], "成") ||
+ strstr(fdata[2], "輔") || strstr(fdata[2], "東吳"))
+ good++;
+ } else if (strstr(fdata[2], "女中"))
+ good++;
+
+ if (strstr(fdata[3], "地球") || strstr(fdata[3], "宇宙") ||
+ strstr(fdata[3], "信箱")) {
+ ans[0] = '2';
+ return 3;
+ }
+ if (strstr(fdata[3], "市") || strstr(fdata[3], "縣")) {
+ if (strstr(fdata[3], "路") || strstr(fdata[3], "街")) {
+ if (strstr(fdata[3], "號"))
+ good++;
+ }
+ }
+ for (i = 0; fdata[4][i]; i++) {
+ if (isdigit((int)fdata[4][i]))
+ count++;
+ }
+
+ if (count <= 4) {
+ ans[0] = '3';
+ return 4;
+ } else if (count >= 7)
+ good++;
+
+ if (good >= 3) {
+ ans[0] = 'y';
+ return -1;
+ } else
+ return 0;
+}
+
+#define REJECT_REASONS (6)
+#define FN_REGISTER_LOG "register.log"
+
+// read count entries from regsrc to a temp buffer
+FILE *
+pull_regform(const char *regfile, char *workfn, int count)
+{
+ FILE *fp = NULL;
+
+ snprintf(workfn, PATHLEN, "%s.tmp", regfile);
+ if (dashf(workfn)) {
+ vmsg("其他 SYSOP 也在審核註冊申請單");
+ return NULL;
+ }
+
+ // count < 0 means unlimited pulling
+ Rename(regfile, workfn);
+ if ((fp = fopen(workfn, "r")) == NULL) {
+ vmsgf("系統錯誤,無法讀取註冊資料檔: %s", workfn);
+ return NULL;
+ }
+ return fp;
+}
+
+// write all left in "remains" to regfn.
+void
+pump_regform(const char *regfn, FILE *remains)
+{
+ // restore trailing tickets
+ char buf[PATHLEN];
+ FILE *fout = fopen(regfn, "at");
+ if (!fout)
+ return;
+
+ while (fgets(buf, sizeof(buf), remains))
+ fputs(buf, fout);
+ fclose(fout);
+}
+
+/* 處理 Register Form */
+// TODO XXX process someone directly, according to target_uid.
+int
+scan_register_form(const char *regfile, int automode, const char *target_uid)
+{
+ char genbuf[200];
+ char *logfile = FN_REGISTER_LOG;
+ char *field[] = {
+ "uid", "name", "career", "addr", "phone", "email", NULL
+ };
+ char *finfo[] = {
+ "帳號", "真實姓名", "服務單位", "目前住址",
+ "連絡電話", "電子郵件信箱", NULL
+ };
+ char *reason[REJECT_REASONS+1] = {
+ "輸入真實姓名",
+ "詳填「(畢業)學校及『系』『級』」或「服務單位(含所屬縣市及職稱)」",
+ "填寫完整的住址資料 (含縣市名稱, 台北市請含行政區域)",
+ "詳填連絡電話 (含區域碼, 中間不用加 '-', '(', ')'等符號",
+ "精確並完整填寫註冊申請表",
+ "用中文填寫申請單",
+ NULL
+ };
+ char *autoid = "AutoScan";
+ userec_t muser;
+ FILE *fn, *fout, *freg;
+ char fdata[6][STRLEN];
+ char fname[STRLEN] = "", buf[STRLEN];
+ char ans[4], *ptr, *uid;
+ int n = 0, unum = 0, tid = 0;
+ int nSelf = 0, nAuto = 0;
+
+ uid = cuser.userid;
+ move(2, 0);
+
+ fn = pull_regform(regfile, fname, -1);
+ if (!fn)
+ return -1;
+
+ while( fgets(genbuf, STRLEN, fn) ){
+ memset(fdata, 0, sizeof(fdata));
+ do {
+ if( genbuf[0] == '-' )
+ break;
+ if ((ptr = (char *)strstr(genbuf, ": "))) {
+ *ptr = '\0';
+ for (n = 0; field[n]; n++) {
+ if (strcmp(genbuf, field[n]) == 0) {
+ strlcpy(fdata[n], ptr + 2, sizeof(fdata[n]));
+ if ((ptr = (char *)strchr(fdata[n], '\n')))
+ *ptr = '\0';
+ }
+ }
+ }
+ } while( fgets(genbuf, STRLEN, fn) );
+ tid ++;
+
+ if ((unum = getuser(fdata[0], &muser)) == 0) {
+ move(2, 0);
+ clrtobot();
+ outs("系統錯誤,查無此人\n\n");
+ for (n = 0; field[n]; n++)
+ prints("%s : %s\n", finfo[n], fdata[n]);
+ pressanykey();
+ } else {
+ if (automode)
+ uid = autoid;
+
+ if ((!automode || !auto_scan(fdata, ans))) {
+ uid = cuser.userid;
+
+ move(1, 0);
+ clrtobot();
+ prints("帳號位置 : %d\n", unum);
+ user_display(&muser, 1);
+ move(14, 0);
+ prints(ANSI_COLOR(1;32) "------------- "
+ "請站長嚴格審核使用者資料,這是第 %d 份"
+ "------------" ANSI_RESET "\n", tid);
+ prints(" %-12s: %s\n", finfo[0], fdata[0]);
+#ifdef FOREIGN_REG
+ prints("0.%-12s: %s%s\n", finfo[1], fdata[1],
+ muser.uflag2 & FOREIGN ? " (外籍)" : "");
+#else
+ prints("0.%-12s: %s\n", finfo[1], fdata[1]);
+#endif
+ for (n = 2; field[n]; n++) {
+ prints("%d.%-12s: %s\n", n - 1, finfo[n], fdata[n]);
+ }
+ if (muser.userlevel & PERM_LOGINOK) {
+ ans[0] = getkey("此帳號已經完成註冊, "
+ "更新(Y/N/Skip)?[N] ");
+ if (ans[0] != 'y' && ans[0] != 's')
+ ans[0] = 'd';
+ } else {
+ if (search_ulist(unum) == NULL)
+ {
+ move(b_lines, 0); clrtoeol();
+ outs("是否接受此資料(Y/N/Q/Del/Skip)?[S] ");
+ // FIXME if the user got online here
+ ans[0] = igetch();
+ }
+ else
+ ans[0] = 's';
+ ans[0] = tolower(ans[0]);
+ if (ans[0] != 'y' && ans[0] != 'n' &&
+ ans[0] != 'q' && ans[0] != 'd' &&
+ !('0' <= ans[0] && ans[0] < ('0' + REJECT_REASONS)))
+ ans[0] = 's';
+ ans[1] = 0;
+ }
+ nSelf++;
+ } else
+ nAuto++;
+
+ switch (ans[0]) {
+ case 'q':
+ if ((freg = fopen(regfile, "a"))) {
+ for (n = 0; field[n]; n++)
+ fprintf(freg, "%s: %s\n", field[n], fdata[n]);
+ fprintf(freg, "----\n");
+ while (fgets(genbuf, STRLEN, fn))
+ fputs(genbuf, freg);
+ fclose(freg);
+ }
+ case 'd':
+ break;
+
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ /* please confirm match REJECT_REASONS here */
+ case 'n':
+ if (ans[0] == 'n') {
+ int nf = 0;
+ move(8, 0);
+ clrtobot();
+ outs("請提出退回申請表原因,按 <enter> 取消\n");
+ for (n = 0; n < REJECT_REASONS; n++)
+ prints("%d) 請%s\n", n, reason[n]);
+ outs("\n"); // preserved for prompt
+ for (nf = 0; field[nf]; nf++)
+ prints("%s: %s\n", finfo[nf], fdata[nf]);
+ } else
+ buf[0] = ans[0];
+
+ if (ans[0] != 'n' ||
+ getdata(9 + n, 0, "退回原因: ", buf, 60, DOECHO))
+ if ((buf[0] - '0') >= 0 && (buf[0] - '0') < n) {
+ int i;
+ fileheader_t mhdr;
+ char title[128], buf1[80];
+ FILE *fp;
+
+ sethomepath(buf1, muser.userid);
+ stampfile(buf1, &mhdr);
+ strlcpy(mhdr.owner, cuser.userid, sizeof(mhdr.owner));
+ strlcpy(mhdr.title, "[註冊失敗]", TTLEN);
+ mhdr.filemode = 0;
+ sethomedir(title, muser.userid);
+ if (append_record(title, &mhdr, sizeof(mhdr)) != -1) {
+ char rejfn[PATHLEN];
+ fp = fopen(buf1, "w");
+
+ for(i = 0; buf[i] && i < sizeof(buf); i++){
+ if (buf[i] >= '0' && buf[i] < '0'+n)
+ {
+ fprintf(fp, "[退回原因] 請%s\n",
+ reason[buf[i] - '0']);
+ }
+ }
+
+ fclose(fp);
+
+ // build reject file
+ setuserfile(rejfn, "justify.reject");
+ Copy(buf1, rejfn);
+ }
+ if ((fout = fopen(logfile, "a"))) {
+ for (n = 0; field[n]; n++)
+ fprintf(fout, "%s: %s\n", field[n], fdata[n]);
+ fprintf(fout, "Date: %s\n", Cdate(&now));
+ fprintf(fout, "Rejected: %s [%s]\n----\n",
+ uid, buf);
+ fclose(fout);
+ }
+ break;
+ }
+ move(10, 0);
+ clrtobot();
+ outs("取消退回此註冊申請表");
+ /* no break? */
+
+ case 's':
+ if ((freg = fopen(regfile, "a"))) {
+ for (n = 0; field[n]; n++)
+ fprintf(freg, "%s: %s\n", field[n], fdata[n]);
+ fprintf(freg, "----\n");
+ fclose(freg);
+ }
+ break;
+
+ default:
+ outs("以下使用者資料已經更新:\n");
+ mail_muser(muser, "[註冊成功\囉]", "etc/registered");
+
+#if FOREIGN_REG_DAY > 0
+ if(muser.uflag2 & FOREIGN)
+ mail_muser(muser, "[出入境管理局]", "etc/foreign_welcome");
+#endif
+
+ muser.userlevel |= (PERM_LOGINOK | PERM_POST);
+ strlcpy(muser.realname, fdata[1], sizeof(muser.realname));
+ strlcpy(muser.address, fdata[3], sizeof(muser.address));
+ strlcpy(muser.email, fdata[5], sizeof(muser.email));
+ snprintf(genbuf, sizeof(genbuf), "%s:%s:%s",
+ fdata[4], fdata[2], uid);
+ strlcpy(muser.justify, genbuf, sizeof(muser.justify));
+
+ passwd_update(unum, &muser);
+ // XXX TODO notify users?
+ sendalert(muser.userid, ALERT_PWD_PERM); // force to reload perm
+
+ sethomefile(buf, muser.userid, "justify");
+ log_file(buf, LOG_CREAT, genbuf);
+
+ if ((fout = fopen(logfile, "a"))) {
+ for (n = 0; field[n]; n++)
+ fprintf(fout, "%s: %s\n", field[n], fdata[n]);
+ fprintf(fout, "Date: %s\n", Cdate(&now));
+ fprintf(fout, "Approved: %s\n", uid);
+ fprintf(fout, "----\n");
+ fclose(fout);
+ }
+ sethomefile(genbuf, muser.userid, "justify.wait");
+ unlink(genbuf);
+ break;
+ }
+ }
+ }
+
+ fclose(fn);
+ unlink(fname);
+
+ move(0, 0);
+ clrtobot();
+
+ move(5, 0);
+ prints("您審了 %d 份註冊單,AutoScan 審了 %d 份", nSelf, nAuto);
+
+ pressanykey();
+ return (0);
+}
+
+#ifdef EXP_ADMIN_REGFORM
+
+#define FORMS_IN_PAGE (10)
+#define REASON_LEN (60)
+static const char *reasonstr[REJECT_REASONS] = {
+ "輸入真實姓名",
+ "詳填(畢業)學校『系』『級』或服務單位(含所屬縣市及職稱)",
+ "填寫完整的住址資料 (含縣市名稱, 台北市請含行政區域)",
+ "詳填連絡電話 (含區碼, 中間不加 '-', '(', ')' 等符號)",
+ "精確並完整填寫註冊申請表",
+ "用中文填寫申請單",
+};
+
+#define REASON_FIRSTABBREV '0'
+#define REASON_IN_ABBREV(x) \
+ ((x) >= REASON_FIRSTABBREV && (x) - REASON_FIRSTABBREV < REJECT_REASONS)
+#define REASON_EXPANDABBREV(x) reasonstr[(x) - REASON_FIRSTABBREV]
+
+static void
+prompt_regform_ui()
+{
+ move(b_lines, 0);
+ outs(ANSI_COLOR(30;47) " "
+ ANSI_COLOR(31) "y" ANSI_COLOR(30) "接受 "
+ ANSI_COLOR(31) "n" ANSI_COLOR(30) "拒絕 "
+ ANSI_COLOR(31) "d" ANSI_COLOR(30) "刪除 "
+ ANSI_COLOR(31) "s" ANSI_COLOR(30) "跳過 "
+ ANSI_COLOR(31) "u" ANSI_COLOR(30) "復原 "
+ " "
+ ANSI_COLOR(31) "0-9jk↑↓" ANSI_COLOR(30) "移動 "
+ ANSI_COLOR(31) "空白/PgDn" ANSI_COLOR(30) "儲存+下頁 "
+ " "
+ ANSI_COLOR(31) "q/END" ANSI_COLOR(30) "結束 "
+ ANSI_RESET);
+}
+
+void
+resolve_reason(char *s, int y)
+{
+ // should start with REASON_FIRSTABBREV
+ const char *reason_prompt =
+ " (0)真實姓名 (1)詳填系級 (2)完整住址"
+ " (3)詳填電話 (4)確實填寫 (5)中文填寫";
+
+ s[0] = 0;
+ move(y, 0);
+ outs(reason_prompt); outs("\n");
+
+ do {
+ getdata(y+1, 0,
+ "退回原因: ", s, REASON_LEN, DOECHO);
+
+ // convert abbrev reasons (format: single digit, or multiple digites)
+ if (REASON_IN_ABBREV(s[0]))
+ {
+ if (s[1] == 0) // simple replace ment
+ {
+ strlcpy(s+2, REASON_EXPANDABBREV(s[0]),
+ REASON_LEN-2);
+ s[0] = 0xbd; // '請'[0];
+ s[1] = 0xd0; // '請'[1];
+ } else {
+ // strip until all digites
+ char *p = s;
+ while (*p)
+ {
+ if (!REASON_IN_ABBREV(*p))
+ *p = ' ';
+ p++;
+ }
+ strip_blank(s, s);
+ strlcat(s, " [多重原因]", REASON_LEN);
+ }
+ }
+
+ if (strlen(s) < 4)
+ {
+ if (vmsg("原因太短。 要取消退回嗎? (y/N): ") == 'y')
+ {
+ *s = 0;
+ return;
+ }
+ }
+ } while (strlen(s) < 4);
+}
+
+void
+regform_accept(const char *userid, const char *justify)
+{
+ char buf[PATHLEN];
+ int unum = 0;
+ userec_t muser;
+
+ unum = getuser(userid, &muser);
+ if (unum == 0)
+ return; // invalid user
+
+ muser.userlevel |= (PERM_LOGINOK | PERM_POST);
+ strlcpy(muser.justify, justify, sizeof(muser.justify));
+ // manual accept sets email to 'x'
+ strlcpy(muser.email, "x", sizeof(muser.email));
+
+ // handle files
+ sethomefile(buf, muser.userid, "justify.wait");
+ unlink(buf);
+ sethomefile(buf, muser.userid, "justify.reject");
+ unlink(buf);
+ sethomefile(buf, muser.userid, "justify");
+ log_filef(buf, LOG_CREAT, "%s\n", muser.justify);
+
+ // update password file
+ passwd_update(unum, &muser);
+
+ // alert online users?
+ sendalert(muser.userid, ALERT_PWD_PERM|ALERT_PWD_JUSTIFY); // force to reload perm
+
+#if FOREIGN_REG_DAY > 0
+ if(muser.uflag2 & FOREIGN)
+ mail_muser(muser, "[出入境管理局]", "etc/foreign_welcome");
+ else
+#endif
+ // last: send notification mail
+ mail_muser(muser, "[註冊成功\囉]", "etc/registered");
+}
+
+void
+regform_reject(const char *userid, char *reason)
+{
+ char buf[PATHLEN];
+ FILE *fp = NULL;
+ int unum = 0;
+ userec_t muser;
+
+ unum = getuser(userid, &muser);
+ if (unum == 0)
+ return; // invalid user
+
+ muser.userlevel &= ~(PERM_LOGINOK | PERM_POST);
+
+ // handle files
+ sethomefile(buf, muser.userid, "justify.wait");
+ unlink(buf);
+
+ // update password file
+ passwd_update(unum, &muser);
+
+ // alert notify users?
+ sendalert(muser.userid, ALERT_PWD_PERM); // force to reload perm
+
+ // last: send notification
+ mkuserdir(muser.userid);
+ sethomefile(buf, muser.userid, "justify.reject");
+ fp = fopen(buf, "wt");
+ assert(fp);
+ syncnow();
+ fprintf(fp, "%s 註冊失敗。\n", Cdate(&now));
+
+ // multiple abbrev loop
+ if (REASON_IN_ABBREV(reason[0]))
+ {
+ int i = 0;
+ for (i = 0; i < REASON_LEN && REASON_IN_ABBREV(reason[i]); i++)
+ fprintf(fp, "[退回原因] 請%s\n", REASON_EXPANDABBREV(reason[i]));
+ } else {
+ fprintf(fp, "[退回原因] %s\n", reason);
+ }
+ fclose(fp);
+ mail_muser(muser, "[註冊失敗]", buf);
+}
+
+// TODO define and use structure instead, even in reg request file.
+//
+typedef struct {
+ // current format:
+ // (optional) num: unum, date
+ // [0] uid: xxxxx (IDLEN=12)
+ // [1] name: RRRRRR (20)
+ // [2] career: YYYYYYYYYYYYYYYYYYYYYYYYYY (40)
+ // [3] addr: TTTTTTTTT (50)
+ // [4] phone: 02DDDDDDDD (20)
+ // [5] email: x (50) (deprecated)
+ // [6] mobile: (deprecated)
+ // [7] ----
+ // lasthost: 16
+ char userid[IDLEN+1];
+
+ char exist;
+ char online;
+ char pad [ 5]; // IDLEN(12)+1+1+1+5=20
+
+ char name [20];
+ char career[40];
+ char addr [50];
+ char phone [20];
+} RegformEntry;
+
+int
+load_regform_entry(RegformEntry *pre, FILE *fp)
+{
+ char buf[STRLEN];
+ char *v;
+
+ memset(pre, 0, sizeof(RegformEntry));
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ if (buf[0] == '-')
+ break;
+ buf[sizeof(buf)-1] = 0;
+ v = strchr(buf, ':');
+ if (v == NULL)
+ continue;
+ *v++ = 0;
+ if (*v == ' ') v++;
+ chomp(v);
+
+ if (strcmp(buf, "uid") == 0)
+ strlcpy(pre->userid, v, sizeof(pre->userid));
+ else if (strcmp(buf, "name") == 0)
+ strlcpy(pre->name, v, sizeof(pre->name));
+ else if (strcmp(buf, "career") == 0)
+ strlcpy(pre->career, v, sizeof(pre->career));
+ else if (strcmp(buf, "addr") == 0)
+ strlcpy(pre->addr, v, sizeof(pre->addr));
+ else if (strcmp(buf, "phone") == 0)
+ strlcpy(pre->phone, v, sizeof(pre->phone));
+ }
+ return pre->userid[0] ? 1 : 0;
+}
+
+int
+print_regform_entry(const RegformEntry *pre, FILE *fp, int close)
+{
+ fprintf(fp, "uid: %s\n", pre->userid);
+ fprintf(fp, "name: %s\n", pre->name);
+ fprintf(fp, "career: %s\n", pre->career);
+ fprintf(fp, "addr: %s\n", pre->addr);
+ fprintf(fp, "phone: %s\n", pre->phone);
+ fprintf(fp, "email: %s\n", "x");
+ if (close)
+ fprintf(fp, "----\n");
+ return 1;
+}
+
+int
+append_regform(const RegformEntry *pre, const char *logfn,
+ const char *varname, const char *varval1, const char *varval2)
+{
+ FILE *fout = fopen(logfn, "at");
+ if (!fout)
+ return 0;
+
+ print_regform_entry(pre, fout, 0);
+ if (varname && *varname)
+ {
+ syncnow();
+ fprintf(fout, "Date: %s\n", Cdate(&now));
+ if (!varval1) varval1 = "";
+ fprintf(fout, "%s: %s", varname, varval1);
+ if (varval2) fprintf(fout, " %s", varval2);
+ fprintf(fout, "\n");
+ }
+ // close it
+ fprintf(fout, "----\n");
+ fclose(fout);
+ return 1;
+}
+
+// #define REGFORM_DISABLE_ONLINE_USER
+
+int
+handle_register_form(const char *regfile, int dryrun)
+{
+ int unum = 0;
+ int yMsg = FORMS_IN_PAGE*2+1;
+ FILE *fp = NULL;
+ userec_t muser;
+ RegformEntry forms [FORMS_IN_PAGE];
+ char ans [FORMS_IN_PAGE];
+ char rejects[FORMS_IN_PAGE][REASON_LEN]; // reject reason length
+ char fname [PATHLEN] = "";
+ char justify[REGLEN+1];
+ char rsn [REASON_LEN];
+ int cforms = 0, // current loaded forms
+ parsed = 0, // total parsed forms
+ ci = 0, // cursor index
+ ch = 0, // input key
+ i, blanks;
+ long fsz = 0, fpos = 0;
+
+ // prepare reg tickets
+ if (dryrun)
+ {
+ // directly open regfile to try
+ fp = fopen(regfile, "rt");
+ } else {
+ fp = pull_regform(regfile, fname, -1);
+ }
+
+ if (!fp)
+ return 0;
+
+ // retreieve file info
+ fpos = ftell(fp);
+ fseek(fp, 0, SEEK_END);
+ fsz = ftell(fp);
+ fseek(fp, fpos, SEEK_SET);
+ if (!fsz) fsz = 1;
+
+ while (ch != 'q')
+ {
+ // initialize and prepare
+ memset(ans, 0, sizeof(ans));
+ memset(rejects, 0, sizeof(rejects));
+ memset(forms, 0, sizeof(forms));
+ cforms = 0;
+
+ // load forms
+ while (cforms < FORMS_IN_PAGE && load_regform_entry(&forms[cforms], fp))
+ cforms++, parsed ++;
+
+ // if no more forms then leave.
+ // TODO what if regform error?
+ if (cforms < 1)
+ break;
+
+ // adjust cursor if required
+ if (ci >= cforms)
+ ci = cforms-1;
+
+ // display them all.
+ clear();
+ for (i = 0; i < cforms; i++)
+ {
+ // fetch user information
+ memset(&muser, 0, sizeof(muser));
+ unum = getuser(forms[i].userid, &muser);
+ forms[i].exist = unum ? 1 : 0;
+ if (unum) forms[i].online = search_ulist(unum) ? 1 : 0;
+
+ // if already got login level, delete by default.
+ if (!unum)
+ ans[i] = 'd';
+ else {
+ if (muser.userlevel & PERM_LOGINOK)
+ ans[i] = 'd';
+#ifdef REGFORM_DISABLE_ONLINE_USER
+ else if (forms[i].online)
+ ans[i] = 's';
+#endif // REGFORM_DISABLE_ONLINE_USER
+ }
+
+ // print
+ move(i*2, 0);
+ prints(" %2d%s %s%-12s " ANSI_RESET,
+ i+1,
+ (unum == 0) ? ANSI_COLOR(1;31) "D" :
+ ( (muser.userlevel & PERM_LOGINOK) ?
+ ANSI_COLOR(1;33) "Y" :
+#ifdef REGFORM_DISABLE_ONLINE_USER
+ forms[i].online ? "s" :
+#endif
+ "."),
+ forms[i].online ? ANSI_COLOR(1;35) : ANSI_COLOR(1),
+ forms[i].userid);
+
+ prints( ANSI_COLOR(1;31) "%19s "
+ ANSI_COLOR(1;32) "%-40s" ANSI_RESET"\n",
+ forms[i].name, forms[i].career);
+
+ move(i*2+1, 0);
+ prints(" %s %-50s%20s\n",
+ (muser.userlevel & PERM_NOREGCODE) ?
+ ANSI_COLOR(1;31) "T" ANSI_RESET : " ",
+ forms[i].addr, forms[i].phone);
+ }
+
+ // display page info
+ {
+ char msg[STRLEN];
+ fpos = ftell(fp);
+ if (fpos > fsz) fsz = fpos*10;
+ snprintf(msg, sizeof(msg),
+ " 已顯示 %d 份註冊單 (%2d%%) ",
+ parsed, (int)(fpos*100/fsz));
+ prints(ANSI_COLOR(7) "\n%78s" ANSI_RESET "\n", msg);
+ }
+
+ // handle user input
+ prompt_regform_ui();
+ ch = 0;
+ while (ch != 'q' && ch != ' ') {
+ ch = cursor_key(ci*2, 0);
+ switch (ch)
+ {
+ // nav keys
+ case KEY_UP:
+ case 'k':
+ if (ci > 0) ci--;
+ break;
+
+ case KEY_DOWN:
+ case 'j':
+ ch = 'j'; // go next
+ break;
+
+ // quick nav (assuming to FORMS_IN_PAGE=10)
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ ci = ch - '1';
+ if (ci >= cforms) ci = cforms-1;
+ break;
+ case '0':
+ ci = 10-1;
+ if (ci >= cforms) ci = cforms-1;
+ break;
+
+ /*
+ case KEY_HOME: ci = 0; break;
+ case KEY_END: ci = cforms-1; break;
+ */
+
+ // abort
+ case KEY_END:
+ case 'q':
+ ch = 'q';
+ if (getans("確定要離開了嗎? (本頁變更將不會儲存) [y/N]: ") != 'y')
+ {
+ prompt_regform_ui();
+ ch = 0;
+ continue;
+ }
+ break;
+
+ // prepare to go next page
+ case KEY_PGDN:
+ case ' ':
+ ch = ' ';
+
+ // solving blank (undecided entries)
+ for (i = 0, blanks = 0; i < cforms; i++)
+ if (ans[i] == 0) blanks ++;
+
+ if (!blanks)
+ break;
+
+ // have more blanks
+ ch = getans("尚未指定的 %d 個項目要: (S跳過/y通過/n拒絕/e繼續編輯): ",
+ blanks);
+
+ if (ch == 'e')
+ {
+ prompt_regform_ui();
+ ch = 0;
+ continue;
+ }
+ if (ch == 'y') {
+ // do nothing.
+ } else if (ch == 'n') {
+ // query reject reason
+ resolve_reason(rsn, yMsg);
+ if (*rsn == 0)
+ ch = 's';
+ } else ch = 's';
+
+ // filling answers
+ for (i = 0; i < cforms; i++)
+ {
+ if (ans[i] != 0)
+ continue;
+ ans[i] = ch;
+ if (ch != 'n')
+ continue;
+ strlcpy(rejects[i], rsn, REASON_LEN);
+ }
+
+ ch = ' '; // go to page mode!
+ break;
+
+ // function keys
+ case 'y': // accept
+#ifdef REGFORM_DISABLE_ONLINE_USER
+ if (forms[ci].online)
+ {
+ vmsg("暫不開放審核在線上使用者。");
+ break;
+ }
+#endif
+ case 's': // skip
+ case 'd': // delete
+ case KEY_DEL: //delete
+ if (ch == KEY_DEL) ch = 'd';
+
+ grayout(ci*2, ci*2+1, GRAYOUT_DARK);
+ move_ansi(ci*2, 4); outc(ch);
+ ans[ci] = ch;
+ ch = 'j'; // go next
+ break;
+
+ case 'u': // undo
+#ifdef REGFORM_DISABLE_ONLINE_USER
+ if (forms[ci].online)
+ {
+ vmsg("暫不開放審核在線上使用者。");
+ break;
+ }
+#endif
+ grayout(ci*2, ci*2+1, GRAYOUT_NORM);
+ move_ansi(ci*2, 4); outc('.');
+ ans[ci] = 0;
+ ch = 'j'; // go next
+ break;
+
+ case 'n': // reject
+#ifdef REGFORM_DISABLE_ONLINE_USER
+ if (forms[ci].online)
+ {
+ vmsg("暫不開放審核在線上使用者。");
+ break;
+ }
+#endif
+ // query for reason
+ resolve_reason(rejects[ci], yMsg);
+ prompt_regform_ui();
+
+ if (!rejects[ci][0])
+ break;
+
+ move(yMsg, 0);
+ prints("退回 %s 註冊單原因:\n %s\n", forms[ci].userid, rejects[ci]);
+
+ // do reject
+ grayout(ci*2, ci*2+1, GRAYOUT_DARK);
+ move_ansi(ci*2, 4); outc(ch);
+ ans[ci] = ch;
+ ch = 'j'; // go next
+
+ break;
+ } // switch(ch)
+
+ // change cursor
+ if (ch == 'j' && ++ci >= cforms)
+ ci = cforms -1;
+ } // while(ch != QUIT/SAVE)
+
+ // if exit, we still need to skip all read forms
+ if (ch == 'q')
+ {
+ for (i = 0; i < cforms; i++)
+ ans[i] = 's';
+ }
+
+ // page complete (save).
+ assert(ch == ' ' || ch == 'q');
+
+ // save/commit if required.
+ if (dryrun)
+ {
+ // prmopt for debug
+ clear();
+ stand_title("測試模式");
+ outs("您正在執行測試模式,所以剛審的註冊單並不會生效。\n"
+ "下面列出的是剛才您審完的結果:\n\n");
+
+ for (i = 0; i < cforms; i++)
+ {
+ if (ans[i] == 'y')
+ snprintf(justify, sizeof(justify), // build justify string
+ "%s:%s:%s", forms[i].phone, forms[i].career, cuser.userid);
+
+ prints("%2d. %-12s - %c %s\n", i+1, forms[i].userid, ans[i],
+ ans[i] == 'n' ? rejects[i] :
+ ans[i] == 'y' ? justify : "");
+ }
+ if (ch != 'q')
+ pressanykey();
+ }
+ else
+ {
+ // real functionality
+ for (i = 0; i < cforms; i++)
+ {
+ if (ans[i] == 'y')
+ {
+ // build justify string
+ snprintf(justify, sizeof(justify),
+ "%s:%s:%s", forms[i].phone, forms[i].career, cuser.userid);
+
+ regform_accept(forms[i].userid, justify);
+ // log form to FN_REGISTER_LOG
+ append_regform(&forms[i], FN_REGISTER_LOG,
+ "Approved", cuser.userid, NULL);
+ }
+ else if (ans[i] == 'n')
+ {
+ regform_reject(forms[i].userid, rejects[i]);
+ // log form to FN_REGISTER_LOG
+ append_regform(&forms[i], FN_REGISTER_LOG,
+ "Rejected", cuser.userid, rejects[i]);
+ }
+ else if (ans[i] == 's')
+ {
+ // append form back to fn_register
+ append_regform(&forms[i], fn_register,
+ NULL, NULL, NULL);
+ }
+ }
+ } // !dryrun
+
+ } // while (ch != 'q')
+
+ // cleaning left regforms
+ if (!dryrun)
+ {
+ pump_regform(regfile, fp);
+ fclose(fp);
+ unlink(fname);
+ } else {
+ // directly close file should be OK.
+ fclose(fp);
+ }
+
+ return 0;
+}
+
+#endif // EXP_ADMIN_REGFORM
+
+int
+m_register(void)
+{
+ FILE *fn;
+ int x, y, wid, len;
+ char ans[4];
+ char genbuf[200];
+
+ if ((fn = fopen(fn_register, "r")) == NULL) {
+ outs("目前並無新註冊資料");
+ return XEASY;
+ }
+ stand_title("審核使用者註冊資料");
+ y = 2;
+ x = wid = 0;
+
+ while (fgets(genbuf, STRLEN, fn) && x < 65) {
+ if (strncmp(genbuf, "uid: ", 5) == 0) {
+ move(y++, x);
+ outs(genbuf + 5);
+ len = strlen(genbuf + 5);
+ if (len > wid)
+ wid = len;
+ if (y >= t_lines - 3) {
+ y = 2;
+ x += wid + 2;
+ }
+ }
+ }
+ fclose(fn);
+ getdata(b_lines - 1, 0,
+#ifdef EXP_ADMIN_REGFORM
+ "開始審核嗎(Auto自動/Yes手動/No不審/Exp新界面)?[N] ",
+#else
+ "開始審核嗎(Auto自動/Yes手動/No不審)?[N] ",
+#endif
+ ans, sizeof(ans), LCECHO);
+ if (ans[0] == 'a')
+ scan_register_form(fn_register, 1, NULL);
+ else if (ans[0] == 'y')
+ scan_register_form(fn_register, 0, NULL);
+
+#ifdef EXP_ADMIN_REGFORM
+ else if (ans[0] == 'e')
+ {
+#ifdef EXP_ADMIN_REGFORM_DRYRUN
+ int dryrun = 0;
+ if (getans("你要進行純測試(T)還是真的執行審核(y)?") == 'y')
+ {
+ vmsg("進入實際執行模式,所有審核動作都是真的。");
+ dryrun = 0;
+ } else {
+ vmsg("測試模式。");
+ dryrun = 1;
+ }
+ handle_register_form(fn_register, dryrun);
+#else
+ // run directly.
+ handle_register_form(fn_register, 0);
+#endif
+ }
+#endif
+
+ return 0;
+}
+
+int
+cat_register(void)
+{
+ if (system("cat register.new.tmp >> register.new") == 0 &&
+ unlink("register.new.tmp") == 0)
+ vmsg("OK 嚕~~ 繼續去奮鬥吧!!");
+ else
+ vmsg("沒辦法CAT過去呢 去檢查一下系統吧!!");
+ return 0;
+}
+
/* vim:sw=4
*/
diff --git a/mbbsd/user.c b/mbbsd/user.c
index a44e500e..9c686b24 100644
--- a/mbbsd/user.c
+++ b/mbbsd/user.c
@@ -15,8 +15,6 @@ static const char * const chess_type[3] = {
};
#endif
-#define REGCODE_INITIAL "v6" // always 2 characters
-
int
kill_user(int num, const char *userid)
{
@@ -525,146 +523,6 @@ void Customize(void)
vmsg("設定完成");
}
-static char *
-getregfile(char *buf)
-{
- // not in user's home because s/he could zip his/her home
- snprintf(buf, PATHLEN, "jobspool/.regcode.%s", cuser.userid);
- return buf;
-}
-
-static char *
-makeregcode(char *buf)
-{
- char fpath[PATHLEN];
- int fd, i;
- // prevent ambigious characters: oOlI
- const char *alphabet = "qwertyuipasdfghjkzxcvbnmoQWERTYUPASDFGHJKLZXCVBNM";
-
- /* generate a new regcode */
- buf[13] = 0;
- buf[0] = REGCODE_INITIAL[0];
- buf[1] = REGCODE_INITIAL[1];
- for( i = 2 ; i < 13 ; ++i )
- buf[i] = alphabet[random() % strlen(alphabet)];
-
- getregfile(fpath);
- if( (fd = open(fpath, O_WRONLY | O_CREAT, 0600)) == -1 ){
- perror("open");
- exit(1);
- }
- write(fd, buf, 13);
- close(fd);
-
- return buf;
-}
-
-static char *
-getregcode(char *buf)
-{
- int fd;
- char fpath[PATHLEN];
-
- getregfile(fpath);
- if( (fd = open(fpath, O_RDONLY)) == -1 ){
- buf[0] = 0;
- return buf;
- }
- read(fd, buf, 13);
- close(fd);
- buf[13] = 0;
- return buf;
-}
-
-static void
-delregcodefile(void)
-{
- char fpath[PATHLEN];
- getregfile(fpath);
- unlink(fpath);
-}
-
-#ifdef DEBUG
-int
-_debug_testregcode()
-{
- char buf[16], rcode[16];
- char myid[16];
- int i = 1;
-
- clear();
- strcpy(myid, cuser.userid);
- do {
- getdata(0, 0, "輸入 id (空白結束): ",
- buf, IDLEN+1, DOECHO);
- if(buf[0])
- {
- move(i++, 0);
- i %= t_lines;
- if(i == 0)
- i = 1;
- strcpy(cuser.userid, buf);
- prints("id: [%s], regcode: [%s]\n",
- cuser.userid, getregcode(rcode));
- move(i, 0);
- clrtoeol();
- }
- } while (buf[0]);
- strcpy(cuser.userid, myid);
-
- pressanykey();
- return 0;
-}
-#endif
-
-static void
-justify_wait(char *userid, char *phone, char *career,
- char *rname, char *addr, char *mobile)
-{
- char buf[PATHLEN];
- sethomefile(buf, userid, "justify.wait");
- if (phone[0] != 0) {
- FILE* fn = fopen(buf, "w");
- assert(fn);
- fprintf(fn, "%s\n%s\ndummy\n%s\n%s\n%s\n",
- phone, career, rname, addr, mobile);
- fclose(fn);
- }
-}
-
-static void email_justify(const userec_t *muser)
-{
- char tmp[IDLEN + 1], buf[256], genbuf[256];
- /*
- * It is intended to use BBSENAME instead of BBSNAME here.
- * Because recently many poor users with poor mail clients
- * (or evil mail servers) cannot handle/decode Chinese
- * subjects (BBSNAME) correctly, so we'd like to use
- * BBSENAME here to prevent subject being messed up.
- * And please keep BBSENAME short or it may be truncated
- * by evil mail servers.
- */
- snprintf(buf, sizeof(buf),
- " " BBSENAME " - [ %s ]", makeregcode(genbuf));
-
- strlcpy(tmp, cuser.userid, sizeof(tmp));
- // XXX dirty, set userid=SYSOP
- strlcpy(cuser.userid, str_sysop, sizeof(cuser.userid));
-#ifdef HAVEMOBILE
- if (strcmp(muser->email, "m") == 0 || strcmp(muser->email, "M") == 0)
- mobile_message(mobile, buf);
- else
-#endif
- bsmtp("etc/registermail", buf, muser->email);
- strlcpy(cuser.userid, tmp, sizeof(cuser.userid));
- move(20,0);
- clrtobot();
- outs("我們即將寄出認證信 (您應該會在 10 分鐘內收到)\n"
- "收到後您可以根據認證信標題的認證碼\n"
- "輸入到 (U)ser -> (R)egister 後就可以完成註冊");
- pressanykey();
- return;
-}
void
uinfo_query(userec_t *u, int adminmode, int unum)
@@ -696,7 +554,7 @@ uinfo_query(userec_t *u, int adminmode, int unum)
memcpy(&x, u, sizeof(userec_t));
ans = getans(adminmode ?
- "(1)改資料(2)密碼(3)權限(4)砍帳號(5)改ID(6)寵物(7)審判(M)信箱 [0]結束 " :
+ "(1)改資料(2)密碼(3)權限(4)砍帳號(5)改ID(7)審判(M)信箱 [0]結束 " :
"請選擇 (1)修改資料 (2)設定密碼 (M)修改信箱 (C) 個人化設定 ==> [0]結束 ");
if (ans > '2' && ans != 'm' && ans != 'c' && !adminmode)
@@ -1050,6 +908,9 @@ uinfo_query(userec_t *u, int adminmode, int unum)
}
strlcpy(genbuf, buf, PASSLEN);
+ move(y+1, 0);
+ outs("請注意設定密碼只有前八個字元有效,超過的將自動忽略。");
+
getdata(y++, 0, "請檢查新密碼:", buf, PASSLEN, NOECHO);
if (strncmp(buf, genbuf, PASSLEN)) {
outs("\n\n新密碼確認失敗, 無法設定新密碼\n");
@@ -1087,12 +948,6 @@ uinfo_query(userec_t *u, int adminmode, int unum)
strlcpy(x.userid, genbuf, sizeof(x.userid));
}
break;
- case '6':
- if (x.mychicken.name[0])
- x.mychicken.name[0] = 0;
- else
- strlcpy(x.mychicken.name, "[死]", sizeof(x.mychicken.name));
- break;
default:
return;
}
@@ -1118,22 +973,8 @@ uinfo_query(userec_t *u, int adminmode, int unum)
setuserid(unum, x.userid);
}
if (mail_changed && !adminmode) {
- char justify_tmp[REGLEN + 1];
- char *phone, *career;
- char *strtok_pos;
- strlcpy(justify_tmp, u->justify, sizeof(justify_tmp));
-
+ // wait registration.
x.userlevel &= ~(PERM_LOGINOK | PERM_POST);
-
- phone = strtok_r(justify_tmp, ":", &strtok_pos);
- career = strtok_r(NULL, ":", &strtok_pos);
-
- if (phone == NULL) phone = "";
- if (career == NULL) career = "";
-
- snprintf(buf, sizeof(buf), "%d", x.mobile);
-
- justify_wait(x.userid, phone, career, x.realname, x.address, buf);
}
memcpy(u, &x, sizeof(x));
if (tokill) {
@@ -1380,41 +1221,6 @@ u_editplan(void)
return 0;
}
-
-/* 使用者填寫註冊表格 */
-static void
-getfield(int line, const char *info, const char *desc, char *buf, int len)
-{
- char prompt[STRLEN];
- char genbuf[200];
-
- // clear first
- move(line+1, 0); clrtoeol();
- move(line, 0); clrtoeol();
- prints(" 原先設定:%-30.30s (%s)", buf, info);
- snprintf(prompt, sizeof(prompt), " %s:", desc);
- if (getdata_str(line + 1, 0, prompt, genbuf, len, DOECHO, buf))
- strcpy(buf, genbuf);
- move(line+1, 0); clrtoeol();
- move(line, 0); clrtoeol();
- prints(" %s:%s", desc, buf);
-}
-
-static int
-removespace(char *s)
-{
- int i, index;
-
- for (i = 0, index = 0; s[i]; i++) {
- if (s[i] != ' ')
- s[index++] = s[i];
- }
- s[index] = '\0';
- return index;
-}
-
-
-
int
isvalidemail(const char *email)
{
@@ -1443,553 +1249,6 @@ isvalidemail(const char *email)
return 1;
}
-static void
-toregister(char *email, char *phone, char *career,
- char *rname, char *addr, char *mobile)
-{
- FILE *fn = NULL;
-
- justify_wait(cuser.userid, phone, career, rname, addr, mobile);
-
- clear();
- stand_title("認證設定");
- if (cuser.userlevel & PERM_NOREGCODE){
- strcpy(email, "x");
- goto REGFORM2;
- }
- move(1, 0);
- outs("您好, 本站認證認證的方式有:\n"
- " 1.若您有 E-Mail (本站不接受 yahoo, kimo等免費的 E-Mail)\n"
- " 請輸入您的 E-Mail , 我們會寄發含有認證碼的信件給您\n"
- " 收到後請到 (U)ser => (R)egister 輸入認證碼, 即可通過認證\n"
- "\n"
- " 2.若您沒有 E-Mail 或是一直無法收到認證信, 請輸入 x \n"
- " 會有站長親自人工審核註冊資料," ANSI_COLOR(1;33)
- "但注意這可能會花上數週或更多時間。" ANSI_RESET "\n"
- "**********************************************************\n"
- "* 注意! *\n"
- "* 通常應該會在輸入完成後十分鐘內收到認證信, 若過久未收到 *\n"
- "* 請到郵件垃圾桶檢查是否被當作垃圾信(SPAM)了,另外若是 *\n"
- "* 輸入後發生認證碼錯誤請重填一次 E-Mail *\n"
- "**********************************************************\n");
-
-#ifdef HAVEMOBILE
- outs(" 3.若您有手機門號且想採取手機簡訊認證的方式 , 請輸入 m \n"
- " 我們將會寄發含有認證碼的簡訊給您 \n"
- " 收到後請到(U)ser => (R)egister 輸入認證碼, 即可通過認證\n");
-#endif
-
- while (1) {
- email[0] = 0;
- getfield(15, "身分認證用", "E-Mail Address", email, 50);
- if (strcmp(email, "x") == 0 || strcmp(email, "X") == 0)
- break;
-#ifdef HAVEMOBILE
- else if (strcmp(email, "m") == 0 || strcmp(email, "M") == 0) {
- if (isvalidmobile(mobile)) {
- char yn[3];
- getdata(16, 0, "請再次確認您輸入的手機號碼正確嘛? [y/N]",
- yn, sizeof(yn), LCECHO);
- if (yn[0] == 'Y' || yn[0] == 'y')
- break;
- } else {
- move(15, 0); clrtobot();
- move(17, 0);
- outs("指定的手機號碼不正確,"
- "若您無手機門號請選擇其他方式認證");
- }
-
- }
-#endif
- else if (isvalidemail(email)) {
- char yn[3];
-#ifdef USE_EMAILDB
- int email_count = emaildb_check_email(email, strlen(email));
-
- if (email_count < 0) {
- move(15, 0); clrtobot();
- move(17, 0);
- outs("暫時不允許\ email 認證註冊, 請稍後再試\n");
- pressanykey();
- return;
- } else if (email_count >= EMAILDB_LIMIT) {
- move(15, 0); clrtobot();
- move(17, 0);
- outs("指定的 E-Mail 已註冊過多帳號, 請使用其他 E-Mail, 或輸入 x 採手動認證\n");
- outs("但注意手動認證通常會花上數週以上的時間。\n");
- } else {
-#endif
- getdata(16, 0, "請再次確認您輸入的 E-Mail 位置正確嘛? [y/N]",
- yn, sizeof(yn), LCECHO);
- if (yn[0] == 'Y' || yn[0] == 'y')
- break;
-#ifdef USE_EMAILDB
- }
-#endif
- } else {
- move(15, 0); clrtobot();
- move(17, 0);
- outs("指定的 E-Mail 不正確, 若您無 E-Mail 請輸入 x 由站長手動認證\n");
- outs("但注意手動認證通常會花上數週以上的時間。\n");
- }
- }
-#ifdef USE_EMAILDB
- if (emaildb_update_email(cuser.userid, strlen(cuser.userid),
- email, strlen(email)) < 0) {
- move(15, 0); clrtobot();
- move(17, 0);
- outs("暫時不允許\ email 認證註冊, 請稍後再試\n");
- pressanykey();
- return;
- }
-#endif
- strlcpy(cuser.email, email, sizeof(cuser.email));
- REGFORM2:
- if (strcasecmp(email, "x") == 0) { /* 手動認證 */
- if ((fn = fopen(fn_register, "a"))) {
- fprintf(fn, "num: %d, %s", usernum, ctime4(&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, "mobile: %s\n", mobile);
- fprintf(fn, "email: %s\n", email);
- fprintf(fn, "----\n");
- fclose(fn);
- // save justify information
- snprintf(cuser.justify, sizeof(cuser.justify),
- "%s:%s:<Manual>", phone, career);
- }
- // XXX what if we cannot open register form?
- } else {
- // register by mail of phone
- snprintf(cuser.justify, sizeof(cuser.justify),
- "%s:%s:<Email>", phone, career);
-#ifdef HAVEMOBILE
- if (phone != NULL && email[1] == 0 && tolower(email[0]) == 'm')
- sprintf(cuser.justify, sizeof(cuser.justify),
- "%s:%s:<Mobile>", phone, career);
-#endif
- email_justify(&cuser);
- }
-}
-
-static int HaveRejectStr(const char *s, const char **rej)
-{
- int i;
- char *ptr, *rejectstr[] =
- {"幹", "阿", "不", "你媽", "某", "笨", "呆", "..", "xx",
- "你管", "管我", "猜", "天才", "超人",
- "ㄅ", "ㄆ", "ㄇ", "ㄈ", "ㄉ", "ㄊ", "ㄋ", "ㄌ", "ㄍ", "ㄎ", "ㄏ",
- "ㄐ", "ㄑ", "ㄒ", "ㄓ",/*"ㄔ",*/ "ㄕ", "ㄖ", "ㄗ", "ㄘ", "ㄙ",
- "ㄧ", "ㄨ", "ㄩ", "ㄚ", "ㄛ", "ㄜ", "ㄝ", "ㄞ", "ㄟ", "ㄠ", "ㄡ",
- "ㄢ", "ㄣ", "ㄤ", "ㄥ", "ㄦ", NULL};
-
- if( rej != NULL )
- for( i = 0 ; rej[i] != NULL ; ++i )
- if( strstr(s, rej[i]) )
- return 1;
-
- for( i = 0 ; rejectstr[i] != NULL ; ++i )
- if( strstr(s, rejectstr[i]) )
- return 1;
-
- if( (ptr = strstr(s, "ㄔ")) != NULL ){
- if( ptr != s && strncmp(ptr - 1, "都市", 4) == 0 )
- return 0;
- return 1;
- }
- return 0;
-}
-
-char *isvalidname(char *rname)
-{
-#ifdef FOREIGN_REG
- return NULL;
-#else
- const char *rejectstr[] =
- {"肥", "胖", "豬頭", "小白", "小明", "路人", "老王", "老李", "寶貝",
- "先生", "帥哥", "老頭", "小姊", "小姐", "美女", "小妹", "大頭",
- "公主", "同學", "寶寶", "公子", "大頭", "小小", "小弟", "小妹",
- "妹妹", "嘿", "嗯", "爺爺", "大哥", "無",
- NULL};
- if( removespace(rname) && rname[0] < 0 &&
- strlen(rname) >= 4 &&
- !HaveRejectStr(rname, rejectstr) &&
- strncmp(rname, "小", 2) != 0 && //起頭是「小」
- strncmp(rname, "我是", 4) != 0 && //起頭是「我是」
- !(strlen(rname) == 4 && strncmp(&rname[2], "兒", 2) == 0) &&
- !(strlen(rname) >= 4 && strncmp(&rname[0], &rname[2], 2) == 0))
- return NULL;
- return "您的輸入不正確";
-#endif
-
-}
-
-static char *isvalidcareer(char *career)
-{
-#ifndef FOREIGN_REG
- const char *rejectstr[] = {NULL};
- if (!(removespace(career) && career[0] < 0 && strlen(career) >= 6) ||
- strcmp(career, "家裡") == 0 || HaveRejectStr(career, rejectstr) )
- return "您的輸入不正確";
- if (strcmp(&career[strlen(career) - 2], "大") == 0 ||
- strcmp(&career[strlen(career) - 4], "大學") == 0 ||
- strcmp(career, "學生大學") == 0)
- return "麻煩請加學校系所";
- if (strcmp(career, "學生高中") == 0)
- return "麻煩輸入學校名稱";
-#else
- if( strlen(career) < 6 )
- return "您的輸入不正確";
-#endif
- return NULL;
-}
-
-char *isvalidaddr(char *addr)
-{
- const char *rejectstr[] =
- {"地球", "銀河", "火星", NULL};
-
- // addr[0] > 0: check if address is starting by Chinese.
- if (!removespace(addr) || strlen(addr) < 15)
- return "這個地址似乎並不完整";
- if (strstr(addr, "信箱") != NULL || strstr(addr, "郵政") != NULL)
- return "抱歉我們不接受郵政信箱";
- if ((strstr(addr, "市") == NULL && strstr(addr, "巿") == NULL &&
- strstr(addr, "縣") == NULL && strstr(addr, "室") == NULL) ||
- HaveRejectStr(addr, rejectstr) ||
- strcmp(&addr[strlen(addr) - 2], "段") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "路") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "巷") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "弄") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "區") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "市") == 0 ||
- strcmp(&addr[strlen(addr) - 2], "街") == 0 )
- return "這個地址似乎並不完整";
- return NULL;
-}
-
-static char *isvalidphone(char *phone)
-{
- int i;
- for( i = 0 ; phone[i] != 0 ; ++i )
- if( !isdigit((int)phone[i]) )
- return "請不要加分隔符號";
- if (!removespace(phone) ||
- strlen(phone) < 9 ||
- strstr(phone, "00000000") != NULL ||
- strstr(phone, "22222222") != NULL ) {
- return "這個電話號碼並不正確(請含區碼)" ;
- }
- return NULL;
-}
-
-int
-u_register(void)
-{
- char rname[20], addr[50], mobile[16];
-#ifdef FOREIGN_REG
- char fore[2];
-#endif
- char phone[20], career[40], email[50], birthday[11], sex_is[2];
- unsigned char year, mon, day;
- char inregcode[14], regcode[50];
- char ans[3], *ptr, *errcode;
- char genbuf[200];
- FILE *fn;
-
- if (cuser.userlevel & PERM_LOGINOK) {
- outs("您的身份確認已經完成,不需填寫申請表");
- return XEASY;
- }
- if ((fn = fopen(fn_register, "r"))) {
- int i =0;
- while (fgets(genbuf, STRLEN, fn)) {
- if ((ptr = strchr(genbuf, '\n')))
- *ptr = '\0';
- if (strncmp(genbuf, "uid: ", 5) != 0)
- continue;
- i++;
- if(strcmp(genbuf + 5, cuser.userid) != 0)
- continue;
- fclose(fn);
- /* idiots complain about this, so bug them */
- clear();
- move(3, 0);
- prints(" 您的註冊申請單尚在處理中(處理順位: %d),請耐心等候\n\n", i);
- outs(" 如果您已收到註冊碼卻看到這個畫面,那代表您在使用 Email 註冊後\n");
- outs(" " ANSI_COLOR(1;31) "又另外申請了站長直接人工審核的註冊申請單。"
- ANSI_RESET "\n\n");
- // outs("該死,都不看說明的...\n");
- outs(" 進入人工審核程序後 Email 註冊自動失效,有註冊碼也沒用,\n");
- outs(" 要等到審核完成 (會多花很多時間,通常起碼數天) ,所以請耐心等候。\n\n");
-
- /* 下面是國王的 code 所需要的 message */
-#if 0
- outs(" 另外請注意,若站長審註冊單時您正在站上則會無法審核、自動跳過。\n");
- outs(" 所以等候審核時請勿掛站。若超過兩三天仍未被審到,通常就是這個原因。\n");
-#endif
-
- vmsg("您的註冊申請單尚在處理中");
- return FULLUPDATE;
- }
- fclose(fn);
- }
- strlcpy(rname, cuser.realname, sizeof(rname));
- strlcpy(addr, cuser.address, sizeof(addr));
- strlcpy(email, cuser.email, sizeof(email));
- if (cuser.mobile)
- snprintf(mobile, sizeof(mobile), "0%09d", cuser.mobile);
- else
- mobile[0] = 0;
- if (cuser.month == 0 && cuser.day == 0 && cuser.year == 0)
- birthday[0] = 0;
- else
- snprintf(birthday, sizeof(birthday), "%04i/%02i/%02i",
- 1900 + cuser.year, cuser.month, cuser.day);
- sex_is[0] = (cuser.sex % 8) + '1';
- sex_is[1] = 0;
- career[0] = phone[0] = '\0';
- sethomefile(genbuf, cuser.userid, "justify.wait");
- if ((fn = fopen(genbuf, "r"))) {
- fgets(genbuf, sizeof(genbuf), fn);
- chomp(genbuf);
- strlcpy(phone, genbuf, sizeof(phone));
-
- fgets(genbuf, sizeof(genbuf), fn);
- chomp(genbuf);
- strlcpy(career, genbuf, sizeof(career));
-
- fgets(genbuf, sizeof(genbuf), fn); // old version compatible
-
- fgets(genbuf, sizeof(genbuf), fn);
- chomp(genbuf);
- strlcpy(rname, genbuf, sizeof(rname));
-
- fgets(genbuf, sizeof(genbuf), fn);
- chomp(genbuf);
- strlcpy(addr, genbuf, sizeof(addr));
-
- fgets(genbuf, sizeof(genbuf), fn);
- chomp(genbuf);
- strlcpy(mobile, genbuf, sizeof(mobile));
-
- fclose(fn);
- }
-
- if (cuser.userlevel & PERM_NOREGCODE) {
- vmsg("您不被允許\使用認證碼認證。請填寫註冊申請單");
- goto REGFORM;
- }
-
- // getregcode(regcode);
-
- // XXX why check by year?
- // birthday is moved to earlier, so let's check email instead.
- if (cuser.email[0] && // cuser.year != 0 && /* 已經第一次填過了~ ^^" */
- strcmp(cuser.email, "x") != 0 && /* 上次手動認證失敗 */
- strcmp(cuser.email, "X") != 0)
- {
- clear();
- stand_title("EMail認證");
- move(2, 0);
-
- prints("請輸入您的認證碼。(由 %s 開頭無空白的十三碼)\n"
- "或輸入 x 來重新填寫 E-Mail 或改由站長手動認證\n", REGCODE_INITIAL);
- inregcode[0] = 0;
-
- do{
- getdata(10, 0, "您的認證碼:",
- inregcode, sizeof(inregcode), DOECHO);
- if( strcmp(inregcode, "x") == 0 || strcmp(inregcode, "X") == 0 )
- break;
- if( strlen(inregcode) != 13 || inregcode[0] == ' ')
- vmsg("認證碼輸入不完整,總共應有十三碼,沒有空白字元。");
- else if( inregcode[0] != REGCODE_INITIAL[0] || inregcode[1] != REGCODE_INITIAL[1] ) {
- /* old regcode */
- vmsg("輸入的認證碼錯誤," // "或因系統昇級已失效,"
- "請輸入 x 重填一次 E-Mail");
- }
- else
- break;
- } while( 1 );
-
- // make it case insensitive.
- if (strcasecmp(inregcode, getregcode(regcode)) == 0) {
- int unum;
- delregcodefile();
- if ((unum = searchuser(cuser.userid, NULL)) == 0) {
- vmsg("系統錯誤,查無此人!");
- u_exit("getuser error");
- exit(0);
- }
- mail_muser(cuser, "[註冊成功\囉]", "etc/registeredmail");
-#if FOREIGN_REG_DAY > 0
- if(cuser.uflag2 & FOREIGN)
- mail_muser(cuser, "[出入境管理局]", "etc/foreign_welcome");
-#endif
- cuser.userlevel |= (PERM_LOGINOK | PERM_POST);
- outs("\n註冊成功\, 重新上站後將取得完整權限\n"
- "請按下任一鍵跳離後重新上站~ :)");
- sethomefile(genbuf, cuser.userid, "justify.wait");
- unlink(genbuf);
- snprintf(cuser.justify, sizeof(cuser.justify),
- "%s:%s:email", phone, career);
- sethomefile(genbuf, cuser.userid, "justify");
- log_file(genbuf, LOG_CREAT, cuser.justify);
- pressanykey();
- u_exit("registed");
- exit(0);
- return QUIT;
- } else if (strcasecmp(inregcode, "x") != 0) {
- if (regcode[0])
- {
- vmsg("認證碼錯誤!");
- return FULLUPDATE;
- }
- else
- {
- vmsg("認證碼已過期,請重新註冊。");
- toregister(email, phone, career, rname, addr, mobile);
- return FULLUPDATE;
- }
- } else {
- toregister(email, phone, career, rname, addr, mobile);
- return FULLUPDATE;
- }
- }
-
- REGFORM:
- getdata(b_lines - 1, 0, "您確定要填寫註冊單嗎(Y/N)?[N] ",
- ans, 3, LCECHO);
- if (ans[0] != 'y')
- return FULLUPDATE;
-
- move(2, 0);
- clrtobot();
- while (1) {
- clear();
- move(1, 0);
- prints("%s(%s) 您好,請據實填寫以下的資料:",
- cuser.userid, cuser.nickname);
-#ifdef FOREIGN_REG
- fore[0] = 'y';
- fore[1] = 0;
- getfield(2, "Y/n", "是否現在住在台灣", fore, 2);
- if (fore[0] == 'n')
- fore[0] |= FOREIGN;
- else
- fore[0] = 0;
-#endif
- while (1) {
- getfield(8,
-#ifdef FOREIGN_REG
- "請用本名",
-#else
- "請用中文",
-#endif
- "真實姓名", rname, 20);
- if( (errcode = isvalidname(rname)) == NULL )
- break;
- else
- vmsg(errcode);
- }
-
- move(11, 0);
- outs(" 請盡量詳細的填寫您的服務單位,大專院校請麻煩"
- "加" ANSI_COLOR(1;33) "系所" ANSI_RESET ",公司單位請加" ANSI_COLOR(1;33) "職稱" ANSI_RESET ",\n"
- " 暫無工作請麻煩填寫" ANSI_COLOR(1;33) "畢業學校" ANSI_RESET "。\n");
- while (1) {
- getfield(9, "(畢業)學校(含" ANSI_COLOR(1;33) "系所年級" ANSI_RESET ")或單位職稱",
- "服務單位", career, 40);
- if( (errcode = isvalidcareer(career)) == NULL )
- break;
- else
- vmsg(errcode);
- }
- move(10, 0); clrtobot();
- while (1) {
- getfield(10, "含" ANSI_COLOR(1;33) "縣市" ANSI_RESET "及門寢號碼"
- "(台北請加" ANSI_COLOR(1;33) "行政區" ANSI_RESET ")",
- "目前住址", addr, sizeof(addr));
- if( (errcode = isvalidaddr(addr)) == NULL
-#ifdef FOREIGN_REG
- || fore[0]
-#endif
- )
- break;
- else
- vmsg(errcode);
- }
- while (1) {
- getfield(11, "不加-(), 包括長途區號", "連絡電話", phone, 11);
- if( (errcode = isvalidphone(phone)) == NULL )
- break;
- else
- vmsg(errcode);
- }
- getfield(12, "只輸入數字 如:0912345678 (可不填)",
- "手機號碼", mobile, 20);
- while (1) {
- getfield(13, "西元/月月/日日 如:1984/02/29", "生日", birthday, sizeof(birthday));
- if (birthday[0] == 0) {
- snprintf(birthday, sizeof(birthday), "%04i/%02i/%02i",
- 1900 + cuser.year, cuser.month, cuser.day);
- mon = cuser.month;
- day = cuser.day;
- year = cuser.year;
- } else {
- int y, m, d;
- if (ParseDate(birthday, &y, &m, &d)) {
- vmsg("您的輸入不正確");
- continue;
- }
- mon = (unsigned char)m;
- day = (unsigned char)d;
- year = (unsigned char)(y - 1900);
- }
- if (year < 40) {
- vmsg("您的輸入不正確");
- continue;
- }
- break;
- }
- getfield(14, "1.葛格 2.姐接 ", "性別", sex_is, 2);
- getdata(20, 0, "以上資料是否正確(Y/N)?(Q)取消註冊 [N] ",
- ans, 3, LCECHO);
- if (ans[0] == 'q')
- return 0;
- if (ans[0] == 'y')
- break;
- }
- strlcpy(cuser.realname, rname, sizeof(cuser.realname));
- strlcpy(cuser.address, addr, sizeof(cuser.address));
- strlcpy(cuser.email, email, sizeof(cuser.email));
- cuser.mobile = atoi(mobile);
- cuser.sex = (sex_is[0] - '1') % 8;
- cuser.month = mon;
- cuser.day = day;
- cuser.year = year;
-#ifdef FOREIGN_REG
- if (fore[0])
- cuser.uflag2 |= FOREIGN;
- else
- cuser.uflag2 &= ~FOREIGN;
-#endif
- trim(career);
- trim(addr);
- trim(phone);
-
- toregister(email, phone, career, rname, addr, mobile);
-
- // update cuser
- passwd_update(usernum, &cuser);
-
- return FULLUPDATE;
-}
-
/* 列出所有註冊使用者 */
struct ListAllUsetCtx {
int usercounter;