/* $Id$ */
#define _UTIL_C_
#include "bbs.h"

time4_t now;

#undef MAX_GUEST_LIFE
#undef MAX_LIFE

// override max life
#define MAX_GUEST_LIFE     (365L * 24 * 60 * 60)
#define MAX_LIFE           (365L *10 * 24 * 60 * 60)

static int free_accs = 0;
int check_free(void *data, int n, userec_t *u)
{
    if (u->userid[0] == 0)
	free_accs++;
    return 0;
}

int check(void *data, int n, userec_t *u) {
    time4_t d;
    char buf[256];
    (void)data;

    if (u->userid[0] == 0 && u->userid[1])
    {
	// expired user, clean record!
	syslog(LOG_ERR, "reset record (%d)", n+1);
	memset(u, 0, sizeof(userec_t));
	passwd_update(n+1, u);
	return 0;
    }

    if(u->userid[0] != '\0') {
	if(!is_validuserid(u->userid)) {
	    syslog(LOG_ERR, "bad userid(%d): %s", n, u->userid);
	    u->userid[0] = '\0';
	} else {
	    // test PASSWD synchronization
	    /*
	    int unum = searchuser(u->userid, u->userid);
	    if (unum == 0)
	    {
		strcpy(buf, ctime4(&u->lastlogin));
		syslog(LOG_NOTICE, "invalid user record (%d): %s (%s) %s", n+1, 
			u->userid, (u->userlevel & PERM_LOGINOK) ? "regok" : "unreg",
			buf
			);
		u->userid[0] = '\0';
		passwd_update(n+1, u);
	    }
	    return 0;
	    */

	    d = now - u->lastlogin;

	    // ignore regged accounts now.
	    if (u->userlevel & PERM_LOGINOK)
		return 0;
            // ignore violate-law accounts
	    if (u->userlevel & PERM_VIOLATELAW)
		return 0;
	    if (u->userlevel & PERM_SYSOP)
		return 0;
	    if (u->userlevel & PERM_XEMPT)
		return 0;

	    // if((d > MAX_GUEST_LIFE && (u->userlevel & PERM_LOGINOK) == 0) 
	    // || (d > MAX_LIFE && (u->userlevel & PERM_XEMPT) == 0)) {
	    if(d > MAX_GUEST_LIFE) {
		/* expired */
		int unum;
		
		unum = searchuser(u->userid, u->userid);
		strcpy(buf, ctime4(&u->lastlogin));
		if (unum != n+1)
		{
		    syslog(LOG_NOTICE, "out-of-sync user(%d/%d): %s %s", unum, n, 
			    u->userid, buf);
		} 
		else if (unum != 0)
		{
		    syslog(LOG_NOTICE, "kill user(%d): %s %s", unum, 
			    // (u->userlevel & PERM_LOGINOK) ? "regok" : "guest",
			    u->userid, buf);

		    log_filef(FN_USIES, LOG_CREAT,
			    "%s %s %-12s %s",
			    Cdate(&now), "CLEAN(EXPIRE)", u->userid, buf);

		    sprintf(buf, "mv home/%c/%s tmp/", u->userid[0], u->userid);
		    if(system(buf))
			syslog(LOG_ERR, "can't move user home: %s", u->userid);
		    u->userid[0] = '\0';
		    setuserid(unum, u->userid);

		    // flush into passwd
		    memset(u, 0, sizeof(userec_t));
		    passwd_update(unum, u);
		} else {
		    /*
		    static int changed = 0;

		    if (changed ++ > 10)
			exit(0);
			*/
    
		    syslog(LOG_NOTICE, "clean user(%d): %s %s", n+1, 
			    u->userid, buf);

		    log_filef(FN_USIES, LOG_CREAT,
			    "%s %s %-12s %s",
			    Cdate(&now), "CLEAN(CLEAR)", u->userid, buf);
		    u->userid[0] = '\0';
		    memset(u, 0, sizeof(userec_t));
		    passwd_update(n+1, u);
		}
	    }
	}
    }
    return 0;
}

int check_last_login(void *data, int n, userec_t *u) {
    char buf[256];

    if (u->userid[0] == 0)
        return 0;

    // ignore all XEMPTY users
    if (u->userlevel & PERM_XEMPT)
        return 0;

    strcpy(buf, Cdate(&u->firstlogin));

    if (u->lastlogin > now + 86400 || u->lastlogin < 0) // should not be newer than now plus one day.
    {
        // invalid record
        printf("使用者 %-*s (登入%3d 次, %s%s, %s [%04X])\n 最後登入日期異常 [%04X]: %s",
                IDLEN, u->userid, u->numlogindays,
                (u->userlevel & PERM_LOGINOK) ? "已過認證" : "未過認證",
                (u->userlevel & PERM_SYSOP) ? "[SYSOP]" : "",
                buf,
                (unsigned)u->firstlogin,
                (unsigned)u->lastlogin,
                ctime4(&u->lastlogin));
        // fix it
        u->lastlogin = u->firstlogin;

        if (u->lastlogin > now)
        {
            printf(" (首次登入日期也異常)");
            u->lastlogin = u->firstlogin = 0x362CFC7E;
        }

        printf(" 已修正登入日期為: %s\n", ctime4(&u->lastlogin));

        // flush
        passwd_update(n+1, u);
    }

    return 0;
}


int main(int argc, char **argv)
{
    now = time(NULL);
    openlog("reaper", LOG_PID | LOG_PERROR, SYSLOG_FACILITY);
    chdir(BBSHOME);

    attach_SHM();
    if(passwd_init())
	exit(1);
    passwd_apply(NULL, check);
    // passwd_apply(NULL, check_free);
    // printf("free accounts=%d\n", free_accs);
    
    return 0;
}
