diff options
Diffstat (limited to 'mbbsd/passwd.c')
-rw-r--r-- | mbbsd/passwd.c | 639 |
1 files changed, 581 insertions, 58 deletions
diff --git a/mbbsd/passwd.c b/mbbsd/passwd.c index 405e5d7c..658e7dce 100644 --- a/mbbsd/passwd.c +++ b/mbbsd/passwd.c @@ -1,97 +1,620 @@ /* $Id$ */ +#define PWCU_IMPL #include "bbs.h" +#include "time.h" #ifdef _BBS_UTIL_C_ #error sorry, mbbsd/passwd.c does not support utility mode anymore. please use libcmbbs instead. #endif -static uint32_t latest_numposts; - -void -passwd_force_update(int flag) -{ - if(!currutmp || (currutmp->alerts & ALERT_PWD) == 0) - return; - currutmp->alerts &= ~flag; -} +#ifndef NO_CONST_CUSER + #undef cuser + #define cuser pwcuser +#endif int initcuser(const char *userid) { usernum = passwd_load_user(userid, &cuser); - latest_numposts = cuser.numposts; return usernum; } -// XXX I don't like the stupid synchronization here, -// but simply following previous work here... int passwd_sync_update(int num, userec_t * buf) { - int alerts; - if (num < 1 || num > MAX_USERS) return -1; // money update should be done before everything. buf->money = moneyof(num); + if (passwd_update(num, buf) != 0) + return -1; - if(usernum == num && currutmp && ((alerts = currutmp->alerts) & ALERT_PWD)) - { - userec_t u; - if (passwd_sync_query(num, &u) != 0) - return -1; + return 0; +} - if(alerts & ALERT_PWD_BADPOST) - cuser.badpost = buf->badpost = u.badpost; - if(alerts & ALERT_PWD_GOODPOST) - cuser.goodpost = buf->goodpost = u.goodpost; - if(alerts & ALERT_PWD_PERM) - cuser.userlevel = buf->userlevel = u.userlevel; - if(alerts & ALERT_PWD_JUSTIFY) - { - memcpy(buf->justify, u.justify, sizeof(u.justify)); - memcpy(cuser.justify, u.justify, sizeof(u.justify)); - memcpy(buf->email, u.email, sizeof(u.email)); - memcpy(cuser.email, u.email, sizeof(u.email)); - } - cuser.numposts += u.numposts - latest_numposts; - // XXX bad workaround - but.... let's use it until we've solved the sync issue - if ((int)cuser.numposts < 0) - cuser.numposts = 0; - currutmp->alerts &= ~ALERT_PWD; - - // ALERT_PWD_RELOAD: reload all! No need to write. - if (alerts & ALERT_PWD_RELOAD) - { - memcpy(&cuser, &u, sizeof(u)); - return 0; - } - } +int +passwd_sync_query(int num, userec_t * buf) +{ + if (passwd_query(num, buf) < 0) + return -1; - if (passwd_update(num, buf) != 0) + buf->money = moneyof(num); + return 0; +} + +// pwcu*: current user password helpers + +static int +pwcuInitCUser(userec_t *u) +{ + assert(usernum > 0 && usernum <= MAX_USERS); + if (passwd_query(usernum, u) != 0) + return -1; + assert(strncmp(u->userid, cuser.userid, IDLEN) == 0); + if (strncmp(u->userid, cuser.userid, IDLEN) != 0) + return -1; + return 0; +} + +static int +pwcuFinalCUser(userec_t *u) +{ + assert(usernum > 0 && usernum <= MAX_USERS); + assert(strcmp(u->userid, cuser.userid) == 0); + if (passwd_update(usernum, u) != 0) + return -1; + return 0; +} + +#define PWCU_START() userec_t u; if(pwcuInitCUser (&u) != 0) return -1 +#define PWCU_END() if (pwcuFinalCUser(&u) != 0) return -1; return 0 + +#define _ENABLE_BIT( var,mask) var |= (mask) +#define _DISABLE_BIT(var,mask) var &= ~(mask) +#define _SETBY_BIT(var,mask,val) if (val) { _ENABLE_BIT(var, (mask)); } else { _DISABLE_BIT(var, (mask)); } + +int pwcuBitEnableLevel (unsigned int mask) +{ + PWCU_START(); + _ENABLE_BIT( u.userlevel, mask); + _ENABLE_BIT(cuser.userlevel, mask); + PWCU_END(); +} + +int pwcuBitDisableLevel (unsigned int mask) +{ + PWCU_START(); + _DISABLE_BIT( u.userlevel, mask); + _DISABLE_BIT(cuser.userlevel, mask); + PWCU_END(); +} + +int +pwcuIncNumPost() +{ + PWCU_START(); + cuser.numposts = ++u.numposts; + PWCU_END(); +} + +int +pwcuDecNumPost() +{ + PWCU_START(); + if (u.numposts > 0) + u.numposts--; + cuser.numposts = u.numposts; + PWCU_END(); +} + +int +pwcuViolateLaw () +{ + PWCU_START(); + _ENABLE_BIT( u.userlevel, PERM_VIOLATELAW); + _ENABLE_BIT(cuser.userlevel, PERM_VIOLATELAW); + u.timeviolatelaw = now; + cuser.timeviolatelaw = u.timeviolatelaw; + u.vl_count++; + cuser.vl_count = u.vl_count; + PWCU_END(); +} + +int +pwcuSaveViolateLaw() +{ + PWCU_START(); + _DISABLE_BIT( u.userlevel, PERM_VIOLATELAW); + _DISABLE_BIT(cuser.userlevel, PERM_VIOLATELAW); + PWCU_END(); +} + +int +pwcuCancelBadpost() +{ + int day; + PWCU_START(); + + // check timebomb again + day = (now - u.timeremovebadpost ) / DAY_SECONDS; + if (day <= 180) + return -1; + if (u.badpost < 1) return -1; - if (currutmp && usernum > 0 && - latest_numposts != cuser.numposts) + cuser.badpost = --u.badpost; + cuser.timeremovebadpost = u.timeremovebadpost = now; + + PWCU_END(); +} + +int +pwcuAddExMailBox(int m) +{ + PWCU_START(); + u.exmailbox += m; + cuser.exmailbox = u.exmailbox; + PWCU_END(); +} + +int pwcuSetLastSongTime (time4_t clk) +{ + PWCU_START(); + u.lastsong = clk; + cuser.lastsong = clk; + PWCU_END(); +} + +int pwcuSetMyAngel (const char *angel_uid) +{ + PWCU_START(); + strlcpy( u.myangel, angel_uid, sizeof( u.myangel)); + strlcpy(cuser.myangel, angel_uid, sizeof(cuser.myangel)); + PWCU_END(); +} + +int pwcuSetNickname (const char *nickname) +{ + PWCU_START(); + strlcpy( u.nickname, nickname, sizeof( u.nickname)); + strlcpy(cuser.nickname, nickname, sizeof(cuser.nickname)); + PWCU_END(); +} + +int +pwcuToggleOutMail() +{ + PWCU_START(); + u.uflag2 ^= REJ_OUTTAMAIL; + _SETBY_BIT(cuser.uflag2, REJ_OUTTAMAIL, + u.uflag2 & REJ_OUTTAMAIL); + PWCU_END(); +} + +int +pwcuSetLoginView(unsigned int bits) +{ + PWCU_START(); + u.loginview = bits; + cuser.loginview = u.loginview; + PWCU_END(); +} + +int +pwcuRegCompleteJustify(const char *justify) +{ + PWCU_START(); + strlcpy( u.justify, justify, sizeof(u.justify)); + strlcpy(cuser.justify, justify, sizeof(cuser.justify)); + _ENABLE_BIT( u.userlevel, (PERM_POST | PERM_LOGINOK)); + _ENABLE_BIT(cuser.userlevel, (PERM_POST | PERM_LOGINOK)); + PWCU_END(); +} + +int +pwcuRegSetTemporaryJustify(const char *justify, const char *email) +{ + PWCU_START(); + strlcpy( u.email, email, sizeof(u.email)); + strlcpy(cuser.email, email, sizeof(cuser.email)); + strlcpy( u.justify, justify, sizeof(u.justify)); + strlcpy(cuser.justify, justify, sizeof(cuser.justify)); + _DISABLE_BIT( u.userlevel, (PERM_POST | PERM_LOGINOK)); + _DISABLE_BIT(cuser.userlevel, (PERM_POST | PERM_LOGINOK)); + PWCU_END(); +} + +int pwcuRegisterSetInfo (const char *rname, + const char *addr, + const char *career, + const char *phone, + const char *email, + int mobile, + uint8_t sex, + uint8_t year, + uint8_t month, + uint8_t day, + uint8_t is_foreign) +{ + PWCU_START(); + strlcpy(u.realname, rname, sizeof(u.realname)); + strlcpy(u.address, addr, sizeof(u.address)); + strlcpy(u.career, career, sizeof(u.career)); + strlcpy(u.phone, phone, sizeof(u.phone)); + strlcpy(u.email, email, sizeof(u.email)); + u.mobile = mobile; + u.sex = sex; + u.year = year; + u.month = month; + u.day = day; + _SETBY_BIT(u.uflag2, FOREIGN, is_foreign); + + // duplicate to cuser + + strlcpy(cuser.realname, rname, sizeof(cuser.realname)); + strlcpy(cuser.address, addr, sizeof(cuser.address)); + strlcpy(cuser.career, career, sizeof(cuser.career)); + strlcpy(cuser.phone, phone, sizeof(cuser.phone)); + strlcpy(cuser.email, email, sizeof(cuser.email)); + cuser.mobile = mobile; + cuser.sex = sex; + cuser.year = year; + cuser.month = month; + cuser.day = day; + _SETBY_BIT(cuser.uflag2, FOREIGN, is_foreign); + + PWCU_END(); +} + +#include "chess.h" +int +pwcuChessResult(int sigType, ChessGameResult r) +{ + uint16_t *utmp_win = NULL, *cuser_win = NULL, *u_win = NULL, + *utmp_lose= NULL, *cuser_lose= NULL, *u_lose= NULL, + *utmp_tie = NULL, *cuser_tie = NULL, *u_tie = NULL; + + PWCU_START(); + + // verify variable size + assert(sizeof(* utmp_win) == sizeof(currutmp->chc_win)); + assert(sizeof(*cuser_lose)== sizeof( cuser.five_lose)); + assert(sizeof(* u_tie) == sizeof( u.go_tie)); + + // determine variables + switch(sigType) { - sendalert_uid(usernum, ALERT_PWD_POSTS); - latest_numposts = cuser.numposts; + case SIG_CHC: + utmp_win = &(currutmp->chc_win); + utmp_lose = &(currutmp->chc_lose); + utmp_tie = &(currutmp->chc_tie); + cuser_win = &( cuser.chc_win); + cuser_lose= &( cuser.chc_lose); + cuser_tie = &( cuser.chc_tie); + u_win = &( u.chc_win); + u_lose = &( u.chc_lose); + u_tie = &( u.chc_tie); + break; + + case SIG_GO: + utmp_win = &(currutmp->go_win); + utmp_lose = &(currutmp->go_lose); + utmp_tie = &(currutmp->go_tie); + cuser_win = &( cuser.go_win); + cuser_lose= &( cuser.go_lose); + cuser_tie = &( cuser.go_tie); + u_win = &( u.go_win); + u_lose = &( u.go_lose); + u_tie = &( u.go_tie); + break; + + case SIG_GOMO: + utmp_win = &(currutmp->five_win); + utmp_lose = &(currutmp->five_lose); + utmp_tie = &(currutmp->five_tie); + cuser_win = &( cuser.five_win); + cuser_lose= &( cuser.five_lose); + cuser_tie = &( cuser.five_tie); + u_win = &( u.five_win); + u_lose = &( u.five_lose); + u_tie = &( u.five_tie); + break; + + default: + assert(!"unknown sigtype"); + break; } - return 0; + // perform action + switch(r) + { + case CHESS_RESULT_WIN: + *utmp_win = *cuser_win = + ++(*u_win); + // recover init lose + if (*u_lose > 0) + *utmp_lose = *cuser_lose = + --(*u_lose); + break; + + case CHESS_RESULT_TIE: + *utmp_tie = *cuser_tie = + ++*u_tie; + // recover init lose + if (*u_lose > 0) + *utmp_lose = *cuser_lose = + --(*u_lose); + break; + + case CHESS_RESULT_LOST: + *utmp_lose = *cuser_lose = + ++(*u_lose); + break; + + default: + assert(!"unknown result"); + return -1; + } + + PWCU_END(); +} + +int +pwcuSetChessEloRating(uint16_t elo_rating) +{ + PWCU_START(); + cuser.chess_elo_rating = u.chess_elo_rating = elo_rating; + PWCU_END(); } -// XXX I don't like the stupid synchronization here, -// but simply following previous work here... +int +pwcuSaveUserFlags() +{ + PWCU_START(); + u.uflag = cuser.uflag; + u.uflag2 = cuser.uflag2; + PWCU_END(); +} + +// non-important variables (only save on exit) + int -passwd_sync_query(int num, userec_t * buf) +pwcuSetSignature(unsigned char newsig) { - if (passwd_query(num, buf) < 0) - return -1; + // XXX you MUST save this variable in pwcuExitSave(); + cuser.signature = newsig; + return 0; +} + +int +pwcuSetWaterballMode(unsigned int bm) +{ + // XXX you MUST save this variable in pwcuExitSave(); + bm &= WATER_MASK; + cuser.uflag2 &= ~WATER_MASK; + cuser.uflag2 |= bm; + return 0; +} + +int +pwcuToggleSortBoard () +{ + // XXX you MUST save this variable in pwcuExitSave(); + cuser.uflag ^= BRDSORT_FLAG; + return 0; +} + +int +pwcuToggleFriendList() +{ + // XXX you MUST save this variable in pwcuExitSave(); + cuser.uflag ^= FRIEND_FLAG; + return 0; +} - if (buf == &cuser) - latest_numposts = cuser.numposts; +int +pwcuToggleUserFlag (unsigned int mask) +{ + // XXX you MUST save this variable in pwcuExitSave(); + cuser.uflag ^= mask; + return 0; +} +int +pwcuToggleUserFlag2 (unsigned int mask) +{ + // XXX you MUST save this variable in pwcuExitSave(); + cuser.uflag2 ^= mask; return 0; } + +// session save + +// XXX this is a little different - only invoked at login, +// which we should update/calculate every variables to log. +int pwcuLoginSave () +{ + // XXX because LoginSave was called very long after + // login_start_time, so we must reload passwd again + // here to prevent race condition. + // If you want to remove this reload, make sure + // pwcuLoginSave is called AFTER login_start_time + // was decided. + int regdays = 0, prev_regdays = 0; + int reftime = login_start_time; + time4_t baseref = 0; + struct tm baseref_tm = {0}; + + PWCU_START(); + + // new host from 'fromhost' + strlcpy( u.lasthost, fromhost, sizeof( u.lasthost)); + strlcpy(cuser.lasthost, fromhost, sizeof(cuser.lasthost)); + + // this must be valid. + assert(login_start_time > 0); + + // adjust base reference by rounding to beginning of each day (0:00am) + baseref = u.firstlogin; + if (localtime4_r(&baseref, &baseref_tm)) + { + baseref_tm.tm_sec = baseref_tm.tm_min = baseref_tm.tm_hour = 0; + baseref = mktime(&baseref_tm); + } + + // invalid session? + if (reftime < u.lastlogin) + reftime = u.lastlogin; + + regdays = ( reftime - baseref) / DAY_SECONDS; + prev_regdays = (u.lastlogin - baseref) / DAY_SECONDS; + // assert(regdays >= prev_regdays); + + if (u.numlogindays > prev_regdays) + u.numlogindays = prev_regdays; + + // calculate numlogindays (only increase one per each key) + if (regdays > prev_regdays) + { + ++u.numlogindays; + is_first_login_of_today = 1; + } + cuser.numlogindays = u.numlogindays; + + // update last login time + cuser.lastlogin = u.lastlogin = reftime; + + if (!PERM_HIDE(currutmp)) + cuser.lastseen = u.lastseen = reftime; + + PWCU_END(); +} + +// XXX this is a little different - only invoked at exist, +// so no need to sync back to cuser. +int +pwcuExitSave () +{ + int dirty = 0; + uint32_t uflag, uflag2, withme; + uint8_t invisible, pager; + int32_t money; + + PWCU_START(); + + // save variables for dirty check + uflag = u.uflag; + uflag2= u.uflag2; + withme= u.withme; + pager = u.pager; + invisible = u.invisible; + money = u.money; + + // uflag and uflag2: always trust cuser except REJ_OUTTAMAIL + _SETBY_BIT(cuser.uflag2, REJ_OUTTAMAIL, (u.uflag2 & REJ_OUTTAMAIL)); + u.uflag = cuser.uflag; + u.uflag2= cuser.uflag2; + + _DISABLE_BIT(u.uflag, (PAGER_FLAG | CLOAK_FLAG)); + if (currutmp->pager != PAGER_ON) + _ENABLE_BIT(u.uflag, PAGER_FLAG); + if (currutmp->invisible) + _ENABLE_BIT(u.uflag, CLOAK_FLAG); + + u.invisible = currutmp->invisible; + u.withme = currutmp->withme; + u.pager = currutmp->pager; + u.money = moneyof(usernum); + + // XXX 當初設計的人把 mind 設計成非 NULL terminated 的... + // assert(sizeof(u.mind) == sizeof(currutmp->mind)); + if (memcmp(u.mind, currutmp->mind, sizeof(u.mind)) != 0) + { + memcpy(u.mind,currutmp->mind, sizeof(u.mind)); + dirty = 1; + } + + // check dirty + if (!dirty && ( + uflag != u.uflag || + uflag2 != u.uflag2|| + withme != u.withme|| + pager != u.pager || + money != u.money || + invisible != u.invisible)) + { + dirty = 1; + } + +#ifdef DEBUG + log_filef("log/pwcu_exitsave.log", LOG_CREAT, + "%s exit %s at %s\n", u.userid, + dirty ? "DIRTY" : "CLEAN", + Cdatelite(&now)); +#endif + + // no need to save data. + if (!dirty) + return 0; + + PWCU_END(); +} + +int +pwcuReload () +{ + int r = passwd_sync_query(usernum, &cuser); + // XXX TODO verify cuser structure? + return r; +} + +// Initialization + +void pwcuInitZero () +{ + bzero(&cuser, sizeof(cuser)); +} + +int pwcuInitAdminPerm () +{ + PWCU_START(); + cuser.userlevel = PERM_BASIC | PERM_CHAT | PERM_PAGE | + PERM_POST | PERM_LOGINOK | PERM_MAILLIMIT | + PERM_CLOAK | PERM_SEECLOAK | PERM_XEMPT | + PERM_SYSOPHIDE | PERM_BM | PERM_ACCOUNTS | + PERM_CHATROOM | PERM_BOARD | PERM_SYSOP | PERM_BBSADM; + PWCU_END(); +} + +void pwcuInitGuestPerm () +{ + cuser.userlevel = 0; + cuser.uflag = PAGER_FLAG | BRDSORT_FLAG | MOVIE_FLAG; + cuser.uflag2= 0; // we don't need FAVNEW_FLAG or anything else. +# ifdef GUEST_DEFAULT_DBCS_NOINTRESC + _ENABLE_BIT(cuser.uflag, DBCS_NOINTRESC); +# endif +} + +#undef DIM +#define DIM(x) (sizeof(x)/sizeof(x[0])) + +void pwcuInitGuestInfo () +{ + int i; + char *nick[] = { + "椰子", "貝殼", "內衣", "寶特瓶", "翻車魚", + "樹葉", "浮萍", "鞋子", "潛水艇", "魔王", + "鐵罐", "考卷", "大美女" + }; + + i = random() % DIM(nick); + snprintf(cuser.nickname, sizeof(cuser.nickname), + "海邊漂來的%s", nick[i]); + strlcpy(currutmp->nickname, cuser.nickname, + sizeof(currutmp->nickname)); + strlcpy(cuser.realname, "guest", sizeof(cuser.realname)); + memset (cuser.mind, 0, sizeof(cuser.mind)); + cuser.sex = i % 8; +} |