diff options
Diffstat (limited to 'mbbsd/register.c')
-rw-r--r-- | mbbsd/register.c | 409 |
1 files changed, 398 insertions, 11 deletions
diff --git a/mbbsd/register.c b/mbbsd/register.c index 3eb9e8e3..c71ed66a 100644 --- a/mbbsd/register.c +++ b/mbbsd/register.c @@ -1,11 +1,16 @@ /* $Id$ */ #include "bbs.h" -#define FN_REGISTER_LOG "register.log" +#define FN_REGISTER_LOG "register.log" // global registration history #define FN_JUSTIFY "justify" #define FN_JUSTIFY_WAIT "justify.wait" #define FN_REJECT_NOTIFY "justify.reject" +// New style (Regform2) file names: +#define FN_REGFORM "regform" // registration form in user home +#define FN_REGFORM_LOG "regform.log" // regform history in user home +#define FN_REQLIST "reg.wait" // request list file, in global directory (replacing fn_register) + //////////////////////////////////////////////////////////////////////////// // Password Hash //////////////////////////////////////////////////////////////////////////// @@ -13,7 +18,7 @@ // prototype of crypt() char *crypt(const char *key, const char *salt); -char * +char * genpasswd(char *pw) { if (pw[0]) { @@ -1245,7 +1250,7 @@ regform_accept(const char *userid, const char *justify) } void -regform_reject(const char *userid, char *reason) +regform_reject(const char *userid, const char *reason) { char buf[PATHLEN]; FILE *fp = NULL; @@ -1270,7 +1275,7 @@ regform_reject(const char *userid, char *reason) // last: send notification mkuserdir(muser.userid); - sethomefile(buf, muser.userid, "justify.reject"); + sethomefile(buf, muser.userid, FN_REJECT_NOTIFY); fp = fopen(buf, "wt"); assert(fp); syncnow(); @@ -1289,6 +1294,7 @@ regform_reject(const char *userid, char *reason) mail_muser(muser, "[註冊失敗]", buf); } +// Regform v1 API // read count entries from regsrc to a temp buffer FILE * pull_regform(const char *regfile, char *workfn, int count) @@ -1325,6 +1331,7 @@ pump_regform(const char *regfn, FILE *remains) fclose(fout); } +// New Regform UI static void prompt_regform_ui() { @@ -1393,6 +1400,10 @@ resolve_reason(char *s, int y) } while (strlen(s) < 4); } +//////////////////////////////////////////////////////////////////////////// +// Regform Utilities +//////////////////////////////////////////////////////////////////////////// + // TODO define and use structure instead, even in reg request file. typedef struct { // current format: @@ -1418,6 +1429,7 @@ typedef struct { char phone [20]; } RegformEntry; +// regform format utilities int load_regform_entry(RegformEntry *pre, FILE *fp) { @@ -1459,7 +1471,6 @@ print_regform_entry(const RegformEntry *pre, FILE *fp, int close) 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; @@ -1489,6 +1500,386 @@ append_regform(const RegformEntry *pre, const char *logfn, return 1; } +//////////////////////////////////////////////////////////////////////////// +// Regform2 API +//////////////////////////////////////////////////////////////////////////// + +// registration queue +int +regq_append(const char *userid) +{ + if (file_append_record(FN_REQLIST, userid) < 0) + return 0; + return 1; +} + +int +regq_find(const char *userid) +{ + return file_find_record(FN_REQLIST, userid); +} + +int +regq_delete(const char *userid) +{ + return file_delete_record(FN_REQLIST, userid, 0); +} + +// user home regform operation +int +regfrm_exist(const char *userid) +{ + char fn[PATHLEN]; + sethomefile(fn, userid, FN_REGFORM); + return dashf(fn) ? 1 : 0; +} + +int +regfrm_load(const char *userid, RegformEntry *pre) +{ + FILE *fp = NULL; + char fn[PATHLEN]; + int ret = 0; + sethomefile(fn, userid, FN_REGFORM); + if (!dashf(fn)) + return 0; + + fp = fopen(fn, "rt"); + if (!fp) + return 0; + ret = load_regform_entry(pre, fp); + fclose(fp); + return ret; +} + +int +regfrm_save(const char *userid, const RegformEntry *pre) +{ + FILE *fp = NULL; + char fn[PATHLEN]; + int ret = 0; + sethomefile(fn, userid, FN_REGFORM); + + fp = fopen(fn, "wt"); + if (!fp) + return 0; + ret = print_regform_entry(pre, fp, 1); + fclose(fp); + return ret; +} + +int +regfrm_trylock(const char *userid) +{ + int fd = 0; + char fn[PATHLEN]; + sethomefile(fn, userid, FN_REGFORM); + if (!dashf(fn)) return 0; + fd = open(fn, O_RDONLY); + if (fd < 0) return 0; + if (flock(fd, LOCK_EX|LOCK_NB) == 0) + return fd; + close(fd); + return 0; +} + +int +regfrm_unlock(int lockfd) +{ + int fd = lockfd; + if (lockfd <= 0) + return 0; + lockfd = flock(fd, LOCK_UN) == 0 ? 1 : 0; + close(fd); + return lockfd; +} + +// regform processors +int +regfrm_accept(RegformEntry *pre) +{ + char justify[REGLEN+1], buf[STRLEN*2]; + char fn[PATHLEN], fnlog[PATHLEN]; + + // dry run! + vmsg("regfrm_accept"); + return 1; + + sethomefile(fn, pre->userid, FN_REGFORM); + + // build justify string + removespace(pre->phone); + removespace(pre->career); + snprintf(justify, sizeof(justify), + "%s:%s:%s", pre->phone, pre->career, cuser.userid); + + // call handler + regform_accept(pre->userid, justify); + + // append current form to history. + sethomefile(fnlog, pre->userid, FN_REGFORM_LOG); + AppendTail(fn, fnlog, 0); + // global history + snprintf(buf, sizeof(buf), "Approved: %s -> %s\nDate: %s\n", + cuser.userid, pre->userid, Cdate(&now)); + file_append_line(FN_REGISTER_LOG, buf); + AppendTail(fn, FN_REGISTER_LOG, 0); + + // remove from queue + unlink(fn); + regq_delete(pre->userid); + return 1; +} + +int +regfrm_reject(RegformEntry *pre, const char *reason) +{ + char buf[STRLEN*2]; + char fn[PATHLEN]; + + // dry run! + vmsg("regfrm_reject"); + return 1; + + sethomefile(fn, pre->userid, FN_REGFORM); + + // call handler + regform_reject(pre->userid, reason); + + // log it + snprintf(buf, sizeof(buf), "Rejected: %s -> %s [%s]\nDate: %s\n", + cuser.userid, pre->userid, reason, Cdate(&now)); + file_append_line(FN_REGISTER_LOG, buf); + AppendTail(fn, FN_REGISTER_LOG, 0); + + // remove from queue + unlink(fn); + regq_delete(pre->userid); + return 1; +} + +int +regfrm_delete(const char *userid) +{ + char fn[PATHLEN]; + sethomefile(fn, userid, FN_REGFORM); + + // dry run! + vmsgf("regfrm_delete (%s)", userid); + return 1; + + // directly delete. + unlink(fn); + + // remove from queue + regq_delete(userid); + return 1; +} + +// working queue +FILE * +regq_init_pull() +{ + FILE *fp = tmpfile(), *src =NULL; + char buf[STRLEN]; + if (!fp) return NULL; + src = fopen(FN_REQLIST, "rt"); + if (!src) { fclose(fp); return NULL; } + while (fgets(buf, sizeof(buf), src)) + fputs(buf, fp); + fclose(src); + rewind(fp); + return fp; +} + +int +regq_pull(FILE *fp, char *uid) +{ + char buf[STRLEN]; + size_t idlen = 0; + uid[0] = 0; + if (fgets(buf, sizeof(buf), fp) == NULL) + return 0; + idlen = strcspn(buf, str_space); + if (idlen < 1) return 0; + if (idlen > IDLEN) idlen = IDLEN; + strlcpy(uid, buf, idlen+1); + return 1; +} + +int +regq_end_pull(FILE *fp) +{ + // no need to unlink because fp is a tmpfile. + if (!fp) return 0; + fclose(fp); + return 1; +} + +// UI part +int +ui_display_regform_single( + const userec_t *xuser, + const RegformEntry *pre, + int tid, char *reason) +{ + int c; + + while (1) + { + move(1, 0); + user_display(xuser, 1); + move(14, 0); + prints(ANSI_COLOR(1;32) + "--------------- 這是第 %2d 份註冊單 ------------------" + ANSI_RESET "\n", tid); + prints(" %-12s: %s\n", "帳號", pre->userid); + prints("0.%-12s: %s%s\n", "真實姓名", pre->name, + xuser->uflag2 & FOREIGN ? " (外籍)" : + ""); + prints("1.%-12s: %s\n", "服務單位", pre->career); + prints("2.%-12s: %s\n", "目前住址", pre->addr); + prints("3.%-12s: %s\n", "連絡電話", pre->phone); + + move(b_lines, 0); + outs("是否接受此資料(Y/N/Q/Del/Skip)?[S] "); + + c = tolower(igetch() & 0xFF); // round to ASCII + if (c == 'y' || c == 'q' || c == 'd' || c == 's') + return c; + if (c == 'n') + { + int n = 0; + move(3, 0); + outs("\n" ANSI_COLOR(1;31) + "請提出退回申請表原因,按 <Enter> 取消:\n" ANSI_RESET); + for (n = 0; n < REJECT_REASONS; n++) + prints("%d) 請%s\n", n, reasonstr[n]); + outs("\n\n\n"); // preserved for prompt + + getdata(3+2+REJECT_REASONS+1, 0,"退回原因: ", + reason, REASON_LEN, DOECHO); + if (reason[0] == 0) + continue; + // interprete reason + return 'n'; + } + else if (REASON_IN_ABBREV(c)) + { + // quick set + sprintf(reason, "%c", c); + return 'n'; + } + return 's'; + } + // shall never reach here + return 's'; +} + +// sample iterator +void +register_sample() +{ + int lfd = 0; + int tid = 0; + char uid[IDLEN+1]; + char rsn[REASON_LEN]; + FILE *fpregq = regq_init_pull(); + RegformEntry re; + + if (!fpregq) + return; + + while (regq_pull(fpregq, uid)) + { + userec_t muser; + int unum = 0; + int abort = 0; + + // check if user exists. + memset(&muser, 0, sizeof(muser)); + unum = getuser(uid, &muser); + + if (unum < 1) + { + regq_delete(uid); + continue; + } + + // check if regform exists. + if (!regfrm_exist(uid)) + { + // TODO delete here? + regq_delete(uid); + continue; + } + + // TODO check if user is already registered +#if 0 + if (muser.userlevel & PERM_LOGINOK) + { + regfrm_delete(uid); + continue; + } +#endif + + // try to lock + lfd = regfrm_trylock(uid); + if (lfd <= 0) + continue; + + // load it + if (!regfrm_load(uid, &re)) + { + regfrm_delete(uid); + regfrm_unlock(lfd); + // regq_delete(uid); // done in regfrm_delete + continue; + } + + tid ++; + // display regform and process + switch(ui_display_regform_single(&muser, &re, tid, rsn)) + { + case 'a': // accept + regfrm_accept(&re); + break; + + case 'd': // delete + regfrm_delete(uid); + break; + + case 'q': // quit + abort = 1; + break; + + case 'n': // reject + regfrm_reject(&re, rsn); + break; + + case 's': // skip + // do nothing. + break; + + default: // shall never reach here + assert(0); + break; + } + + // final processing + regfrm_unlock(lfd); + + if (abort) + break; + } + regq_end_pull(fpregq); + + // finishing + clear(); move(5, 0); + prints("您審了 %d 份註冊單份。", tid); + pressanykey(); +} + ///////////////////////////////////////////////////////////////////////////// // Regform UI // 處理 Register Form @@ -1759,7 +2150,7 @@ scan_register_form(const char *regfile, int automode, const char *target_uid) fclose(fp); // build reject file - setuserfile(rejfn, "justify.reject"); + sethomefile(rejfn, muser.userid, FN_REJECT_NOTIFY); Copy(buf1, rejfn); } if ((fout = fopen(FN_REGISTER_LOG, "a"))) { @@ -1828,12 +2219,8 @@ scan_register_form(const char *regfile, int automode, const char *target_uid) fclose(fn); unlink(fname); - move(0, 0); - clrtobot(); - - move(5, 0); + clear(); move(5, 0); prints("您審了 %d 份註冊單,AutoScan 審了 %d 份", nSelf, nAuto); - pressanykey(); return (0); } |