Beispiel #1
0
static int
common_pager_exit_handler(int r, const char *fpath)
{
    // post processing
    switch(r)
    {
	case RET_DOSYSOPEDIT:
	    r = FULLUPDATE;
	    if (!check_sysop_edit_perm(fpath))
		break;
	    log_filef("log/security", LOG_CREAT,
		    "%u %s %d %s admin edit file=%s\n", 
		    (int)now, Cdate(&now), getpid(), cuser.userid, fpath);
	    veditfile(fpath);
	    break;

	case RET_COPY2TMP:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
	    {
		char buf[PATHLEN];
		getdata(b_lines - 1, 0, "把這篇文章收入到暫存檔?[y/N] ",
			buf, 4, LCECHO);
		if (buf[0] != 'y')
		    break;
		setuserfile(buf, ask_tmpbuf(b_lines - 1));
		Copy(fpath, buf);
	    }
	    break;

	case RET_SELECTBRD:
	    r = FULLUPDATE;
	    if (currstat == READING)
		r = Select();
	    break;

	case RET_DOCHESSREPLAY:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
		ChessReplayGame(fpath);
	    break;

#if defined(USE_BBSLUA) && !defined(DISABLE_BBSLUA_IN_PAGER)
	case RET_DOBBSLUA:
	    r = FULLUPDATE;
	    // check permission again
	    if (HasUserPerm(PERM_BASIC)) 
		bbslua(fpath);
	    break;
#endif
    }
    return r;
}
Beispiel #2
0
/* 使用者管理 */
int
m_user(void)
{
    userec_t        xuser;
    int             id;
    char            genbuf[200];

    vs_hdr("使用者設定");
    usercomplete(msg_uid, genbuf);
    if (*genbuf) {
	move(2, 0);
	if ((id = getuser(genbuf, &xuser))) {
	    user_display(&xuser, 1);
	    if( HasUserPerm(PERM_ACCOUNTS) )
		uinfo_query(xuser.userid, 1, id);
	    else
		pressanykey();
	} else {
	    outs(err_uid);
	    clrtoeol();
	    pressanykey();
	}
    }
    return 0;
}
Beispiel #3
0
static int
check_sysop_edit_perm(const char *fpath)
{
    if (!HasUserPerm(PERM_SYSOP) ||
	strcmp(fpath, "etc/ve.hlp") == 0)
	return 0;

    if (fpath && *fpath) {
        if (strstr(fpath, BBSHOME) == fpath)
            fpath += (strlen(BBSHOME) + 1);

        // allow only files in board, man or home.
        if (!(strstr(fpath, "boards/") == fpath ||
              strstr(fpath, "home/") == fpath ||
              strstr(fpath, "man/") == fpath))
            return 0;
    }

#ifdef BN_SECURITY
    if (strcmp(currboard, BN_SECURITY) == 0)
	return 0;
#endif // BN_SECURITY

    return 1;
}
Beispiel #4
0
int
Announce(void)
{
    setutmpmode(ANNOUNCE);
    a_menu(BBSNAME "佈告欄", "man",
	   ((HasUserPerm(PERM_SYSOP) ) ? SYSOP : NOBODY),
	   0,
	   NULL, NULL);
    return 0;
}
Beispiel #5
0
static int 
check_sysop_edit_perm(const char *fpath)
{
    if (!HasUserPerm(PERM_SYSOP) ||
	strcmp(fpath, "etc/ve.hlp") == 0)
	return 0;

#ifdef BN_SECURITY
    if (strcmp(currboard, BN_SECURITY) == 0)
	return 0;
#endif // BN_SECURITY

    return 1;
}
Beispiel #6
0
static void
a_showname(const menu_t * pm)
{
    char            buf[PATHLEN];
    int             len;
    int             i;
    int             sym;

    move(b_lines - 1, 0);
    snprintf(buf, sizeof(buf),
	     "%s/%s", pm->path, pm->header[pm->now - pm->page].filename);
    if (dashl(buf)) {
	prints("此 symbolic link 名稱為 %s\n",
	       pm->header[pm->now - pm->page].filename);
	if ((len = readlink(buf, buf, PATHLEN - 1)) >= 0) {
	    buf[len] = '\0';
	    for (i = 0; BBSHOME[i] && buf[i] == BBSHOME[i]; i++);
	    if (!BBSHOME[i] && buf[i] == '/') {
		if (HasUserPerm(PERM_BBSADM))
		    sym = 1;
		else {
		    sym = 0;
		    for (i++; BBSHOME "/man"[i] && buf[i] == BBSHOME "/man"[i];
			 i++);
		    if (!BBSHOME "/man"[i] && buf[i] == '/')
			sym = 1;
		}
		if (sym) {
		    vmsgf("此 symbolic link 指向 %s", &buf[i + 1]);
		}
	    }
	}
    } else if (dashf(buf))
	prints("此文章名稱為 %s", pm->header[pm->now - pm->page].filename);
    else if (dashd(buf))
	prints("此目錄名稱為 %s", pm->header[pm->now - pm->page].filename);
    else
	outs("此項目已損毀, 建議將其刪除!");
    pressanykey();
}
Beispiel #7
0
static void
a_delete(menu_t * pm, const char *backup_dir)
{
    char            fpath[PATHLEN], buf[PATHLEN], cmd[PATHLEN];
    char            ans[4];
    fileheader_t    backup, *fhdr = &(pm->header[pm->now - pm->page]);
    const char *msg_errsync = "刪除檔案失敗,請退回上層目錄後再重試一次",
               *msg_errsync2 = "檔案可能已被它人刪除,請退回上層目錄再重進確認",
               *msg_errbackup = "檔案已刪除但無法備份。請至 " BN_BUGREPORT
                                "報告您試圖刪除檔案的位置。";

    snprintf(fpath, sizeof(fpath),
	     "%s/%s", pm->path, fhdr->filename);
    setadir(buf, pm->path);

    if (fhdr->filename[0] == 'H' && fhdr->filename[1] == '.') {
	getdata(b_lines - 1, 1, "您確定要刪除此精華區連線嗎(Y/N)?[N] ",
		ans, sizeof(ans), LCECHO);
	if (ans[0] != 'y')
	    return;
	if (delete_fileheader(buf, fhdr, pm->now + 1) == -1) {
            vmsg(msg_errsync);
	    return;
        }
    } else if (dashl(fpath)) {
	getdata(b_lines - 1, 1, "您確定要刪除此 symbolic link 嗎(Y/N)?[N] ",
		ans, sizeof(ans), LCECHO);
	if (ans[0] != 'y')
	    return;
	if (delete_fileheader(buf, fhdr, pm->now + 1) == -1) {
            vmsg(msg_errsync);
	    return;
        }
	unlink(fpath);
    } else if (dashf(fpath)) {

	getdata(b_lines - 1, 1, "您確定要刪除此檔案嗎(Y/N)?[N] ", ans,
		sizeof(ans), LCECHO);
	if (ans[0] != 'y')
	    return;

        if (delete_fileheader(buf, fhdr, pm->now + 1) == -1) {
            vmsg(msg_errsync);
            return;
        }

        switch(delete_file_content(buf, fhdr, backup_dir, NULL, 0)) {
            case DELETE_FILE_CONTENT_BACKUP_FAILED:
                vmsg(msg_errbackup);
                break;
            case DELETE_FILE_CONTENT_FAILED:
                vmsg(msg_errsync2);
                break;
            default:
#ifndef USE_TIME_CAPSULE
                // When not using time capsule, .DIR content may be changed in
                // board (BN_DELETE/BN_JUNK) and need to be changed. However
                // since that's going to be deprecated in future, let's have a
                // simple workaround here.
                if (backup_dir) {
                    const char *bn = NULL;
                    if (strstr(backup_dir, "/" BN_JUNK "/"))
                        bn = BN_JUNK;
                    else if (strstr(backup_dir, "/" BN_DELETED "/"))
                        bn = BN_DELETED;
                    if (bn)
                        setbtotal(getbnum(bn));
                }
#endif
                break;
        }

    } else if (dashd(fpath)) {

        // TODO(hungte) We should create a top level folder and move everything
        // inside.

	// XXX we also check PERM_MAILLIMIT here because RMAIL
	// may be not trusted...
	const char *save_bn = ( HasUserPerm(PERM_MAILLIMIT) && (currstat & RMAIL) ) ?
		BN_JUNK : BN_DELETED;

	getdata(b_lines - 1, 1, "您確定要刪除整個目錄嗎(Y/N)?[N] ", ans,
		sizeof(ans), LCECHO);
	if (ans[0] != 'y')
	    return;
	if (delete_fileheader(buf, fhdr, pm->now + 1) == -1) {
            vmsg(msg_errsync);
	    return;
        }

	setapath(buf, save_bn);
	// XXX because this directory will hold folders from entire site,
	// let's allow it to use a large set of file names.
	if (stampadir(buf, &backup, 1) != 0)
	{
	    vmsg("抱歉,系統目前無法刪除資料,請通知站務人員");
	    return;
	}

	snprintf(cmd, sizeof(cmd),
		"rm -rf %s;/bin/mv -f %s %s", buf, fpath, buf);
	system(cmd);

	strlcpy(backup.owner, cuser.userid, sizeof(backup.owner));
	strcpy(backup.title, "◆");
	strlcpy(backup.title + 2, fhdr->title + 2, sizeof(backup.title) - 3);

        // restrict access if source is hidden
        if ((fhdr->filemode & FILE_BM) || (fhdr->filemode & FILE_HIDE))
            backup.filemode |= FILE_BM;

	/* merge setapath(buf, save_bn); setadir(buf, buf); */
	snprintf(buf, sizeof(buf), "man/boards/%c/%s/" FN_DIR,
		*save_bn, save_bn);
	append_record(buf, &backup, sizeof(backup));

    } else {			/* Ptt 損毀的項目 */
	getdata(b_lines - 1, 1, "您確定要刪除此損毀的項目嗎(Y/N)?[N] ",
		ans, sizeof(ans), LCECHO);
	if (ans[0] != 'y')
	    return;
	if (delete_fileheader(buf, fhdr, pm->now + 1) == -1)
	    return;
    }
    pm->num--;
}
Beispiel #8
0
int
a_menu_rec(const char *maintitle, const char *path,
	int lastlevel, int lastbid,
	char *trans_buffer,
	a_menu_session_t *sess,
	const int *preselect,
	// we don't change root's value (but may change root pointer)
	// we may   change parent's value (but never change parent pointer)
	const menu_t *root, menu_t* const parent)
{
    menu_t          me = {0};
    char            fname[PATHLEN];
    int             ch, returnvalue = FULLUPDATE;

    assert(sess);

    // prevent deep resursive directories
    if (strlen(path) + FNLEN >= PATHLEN)
    {
	// it is not save to enter such directory.
	return returnvalue;
    }

    if(trans_buffer)
	trans_buffer[0] = '\0';

    if (parent)
    {
	parent->next = &me;
    } else {
	assert(root == NULL);
	root = &me;
    }

    me.header_size = p_lines;
    me.header = (fileheader_t *) calloc(me.header_size, FHSZ);
    me.path = path;
    strlcpy(me.mtitle, maintitle, sizeof(me.mtitle));
    setadir(fname, me.path);
    me.num = get_num_records(fname, FHSZ);
    me.bid = lastbid;

    /* 精華區-tree 中部份結構屬於 cuser ==> BM */

    if (!(me.level = lastlevel)) {
	char           *ptr;

	// warning: this is only valid for me.level.
	// is_uBM should not do anything except returning test result:
	// for ex, setting user BM permission automatically.
	// such extra behavior will result in any sub-op to have PERM_BM
	// ability, which leads to entering BM board without authority.
	// Thanks to mtdas@ptt for reporting this exploit.
	if (HasBasicUserPerm(PERM_LOGINOK) &&
            !HasUserPerm(PERM_NOCITIZEN) &&
            (ptr = strrchr(me.mtitle, '[')))
	    me.level = is_uBM(ptr + 1, cuser.userid);
    }
    me.page = A_INVALID_PAGE;

    if (preselect && !*preselect)
	preselect = NULL;

    me.now = preselect ? (*preselect -1) : 0;

    for (;;) {
	if (me.now >= me.num)
	    me.now = me.num - 1;
	if (me.now < 0)
	    me.now = 0;

	if (me.now < me.page || me.now >= me.page + me.header_size) {
	    me.page = me.now - ((me.page == 10000 && me.now > p_lines / 2) ?
				(p_lines / 2) : (me.now % p_lines));
	    if (!a_showmenu(&me))
	    {
		// some directories are invalid, restart!
		sess->bReturnToRoot = 1;
		break;
	    }
	}

	if (preselect && *preselect && preselect[1])
	{
	    // if this is not the last preselect entry, enter it
	    ch = KEY_ENTER;
	} else {
	    ch = cursor_key(2 + me.now - me.page, 0);
	}

	if (ch == 'q' || ch == 'Q' || ch == KEY_LEFT)
	    break;

	// TODO maybe we should let 1-9=simple search and z=tree-search
	// TODO or let 'z' prefix means 'back to root'
	if ((ch >= '1' && ch <= '9') || (ch == 'z' || ch == 'Z')) {
	    int n = a_multi_search_num(ch, sess);
	    me.page = A_INVALID_PAGE;
	    if (n > 0)
	    {
		// simple (single) selection
		me.now = n-1;
		me.page = 10000; // I don't know what's the magic value 10000...
	    }
	    else if (n == 0 && sess->z_indexes[0] == 0)
	    {
		// empty/invalid input
	    }
	    else
	    {
		// n == 0 with multiple selects
		preselect = sess->z_indexes;
		if (*preselect < 0)
		{
		    // return to root first?
		    if (parent)
		    {
			sess->bReturnToRoot = 1;
			return DONOTHING;
		    }

		    // already in root
		    preselect ++;
		}

		// handle first preselect (maybe zero due to previous 'already in root')
		if (*preselect > 0)
		    me.now = *preselect - 1;
		else
		    preselect = NULL;
	    }
	    continue;
	}
	switch (ch) {
	case KEY_UP:
	case 'k':
	    if (--me.now < 0)
		me.now = me.num - 1;
	    break;

	case KEY_DOWN:
	case 'j':
	    if (++me.now >= me.num)
		me.now = 0;
	    break;

	case KEY_PGUP:
	case Ctrl('B'):
	    if (me.now >= p_lines)
		me.now -= p_lines;
	    else if (me.now > 0)
		me.now = 0;
	    else
		me.now = me.num - 1;
	    break;

	case ' ':
	case KEY_PGDN:
	case Ctrl('F'):
	    if (me.now < me.num - p_lines)
		me.now += p_lines;
	    else if (me.now < me.num - 1)
		me.now = me.num - 1;
	    else
		me.now = 0;
	    break;

	case KEY_HOME:
	case '0':
	    me.now = 0;
	    break;
	case KEY_END:
	case '$':
	    me.now = me.num - 1;
	    break;

	case '?':
	case '/':
	    if(me.num) {
		me.now = a_searchtitle(&me, ch == '?');
		me.page = A_INVALID_PAGE;
	    }
	    break;
	case 'h':
	    a_showhelp(me.level);
	    me.page = A_INVALID_PAGE;
	    break;

	case Ctrl('W'):
	    a_where_am_i(root, me.now, me.header[me.now - me.page].title);
	    vmsg(NULL);
	    me.page = A_INVALID_PAGE;
	    break;

	case 'e':
	case 'E':
	    snprintf(fname, sizeof(fname),
		     "%s/%s", path, me.header[me.now - me.page].filename);
	    if (dashf(fname) && me.level >= MANAGER) {
		int edflags = 0;
		*quote_file = 0;

# ifdef BN_BBSMOVIE
		if (me.bid && strcmp(getbcache(me.bid)->brdname,
			    BN_BBSMOVIE) == 0)
		{
		    edflags |= EDITFLAG_UPLOAD;
		    edflags |= EDITFLAG_ALLOWLARGE;
		}
# endif // BN_BBSMOVIE

		if (vedit2(fname, NA, NULL, edflags) != -1) {
		    char            fpath[PATHLEN];
		    fileheader_t    fhdr;
		    strlcpy(fpath, path, sizeof(fpath));
		    stampfile(fpath, &fhdr);
		    unlink(fpath);
		    strlcpy(fhdr.filename,
			    me.header[me.now - me.page].filename,
			    sizeof(fhdr.filename));
		    strlcpy(me.header[me.now - me.page].owner,
			    cuser.userid,
			    sizeof(me.header[me.now - me.page].owner));
		    setadir(fpath, path);
		    substitute_record(fpath, me.header + me.now - me.page,
				      sizeof(fhdr), me.now + 1);

		}
		me.page = A_INVALID_PAGE;
	    }
	    break;

	case 't':
	case 'c':
	    if (me.now < me.num) {
		if (!isvisible_man(&me))
		    break;

		snprintf(fname, sizeof(fname), "%s/%s", path,
			 me.header[me.now - me.page].filename);

		/* XXX: dirty fix
		   應該要改成如果發現該目錄裡面有隱形目錄的話才拒絕.
		   不過這樣的話須要整個搜一遍, 而且目前判斷該資料是目錄
		   還是檔案竟然是用 fstat(2) 而不是直接存在 .DIR 內 |||b
		   須等該資料寫入 .DIR 內再 implement才有效率.
		 */
		if( !me.level && !HasUserPerm(PERM_SYSOP) &&
		    (me.bid==0 || !is_BM_cache(me.bid)) && dashd(fname) )
		    vmsg("只有板主才可以拷貝目錄唷!");
		else
		    a_copyitem(fname, me.header[me.now - me.page].title, 0, 1);
		me.page = A_INVALID_PAGE;
		/* move down */
		if (++me.now >= me.num)
		    me.now = 0;
		break;
	    }
	case KEY_ENTER:
	case KEY_RIGHT:
	case 'r':
	    if (me.now >= me.num || me.now < 0)
	    {
		preselect = NULL;
		continue;
	    }
	    else
	    {
		fileheader_t   *fhdr = &me.header[me.now - me.page];
		const int *newselect = preselect ? preselect+1 : NULL;
		preselect = NULL;

		if (!isvisible_man(&me))
		    break;
#ifdef DEBUG
		vmsgf("%s/%s", &path[11], fhdr->filename);;
#endif
		snprintf(fname, sizeof(fname), "%s/%s", path, fhdr->filename);
		if (dashf(fname)) {
		    int             more_result;

		    while ((more_result = more(fname, YEA))) {
			/* Ptt 範本精靈 plugin */
			if (trans_buffer &&
				(currstat == EDITEXP || currstat == OSONG)) {
			    char            ans[4];

			    move(22, 0);
			    clrtoeol();
			    getdata(22, 1,
				    currstat == EDITEXP ?
				    "要把範例加入到文章內嗎?[y/N]" :
				    "確定要選這篇嗎?[y/N]",
				    ans, sizeof(ans), LCECHO);
			    if (ans[0] == 'y') {
				strlcpy(trans_buffer, fname, PATHLEN);
				sess->bReturnToRoot = 1;
				if (currstat == OSONG) {
				    log_filef(FN_USSONG, LOG_CREAT, "%s\n", fhdr->title);
				}
				free(me.header);
				return FULLUPDATE;
			    }
			}
			if (more_result == READ_PREV) {
			    if (--me.now < 0) {
				me.now = 0;
				break;
			    }
			} else if (more_result == READ_NEXT) {
			    if (++me.now >= me.num) {
				me.now = me.num - 1;
				break;
			    }
			    /* we only load me.header_size pages */
			    if (me.now - me.page >= me.header_size)
				break;
			} else
			    break;
			if (!isvisible_man(&me))
			    break;
			snprintf(fname, sizeof(fname), "%s/%s", path,
				 me.header[me.now - me.page].filename);
			if (!dashf(fname))
			    break;
		    }
		} else if (dashd(fname)) {
		    returnvalue = a_menu_rec(me.header[me.now - me.page].title, fname,
			    me.level, me.bid, trans_buffer,
			    sess, newselect, root, &me);

		    if (returnvalue == DONOTHING)
		    {
			// DONOTHING will only be caused by previous a_multi_search_num + preselect.
			assert(sess->bReturnToRoot);

			if (!parent)
			{
			    // we've reached root menu!
			    assert(sess->z_indexes[0] == -1);
			    sess->bReturnToRoot = 0;
			    returnvalue = FULLUPDATE;
			    preselect = sess->z_indexes+1;  // skip first 'return to root'
			    if (*preselect > 0)
				me.now = *preselect-1;
			}
		    } else  {
			returnvalue = FULLUPDATE;
		    }

		    me.next = NULL;
		    /* Ptt  強力跳出recursive */
		    if (sess->bReturnToRoot) {
			free(me.header);
			return returnvalue;
		    }
		}
		me.page = A_INVALID_PAGE;
	    }
	    break;

	case 'F':
	case 'U':
	    if (me.now < me.num) {
                fileheader_t   *fhdr = &me.header[me.now - me.page];
                if (!isvisible_man(&me))
                    break;
		snprintf(fname, sizeof(fname),
			 "%s/%s", path, fhdr->filename);
		if (HasBasicUserPerm(PERM_LOGINOK) && dashf(fname)) {
		    a_forward(path, fhdr, ch /* == 'U' */ );
		    /* By CharlieL */
		} else
		    vmsg("無法轉寄此項目");
		me.page = A_INVALID_PAGE;
	    }

	    break;

	}

	if (me.level >= MANAGER) {
	    switch (ch) {
	    case 'n':
		a_newitem(&me, ADDITEM);
		me.page = A_INVALID_PAGE;
		break;
	    case 'g':
		a_newitem(&me, ADDGROUP);
		me.page = A_INVALID_PAGE;
		break;
	    case 'p':
		a_pasteitem(&me, 1);
		me.page = A_INVALID_PAGE;
		break;
	    case 'f':
		a_editsign(&me);
		me.page = A_INVALID_PAGE;
		break;
	    case Ctrl('P'):
		a_pastetagpost(&me, -1);
		returnvalue = DIRCHANGED;
		me.page = A_INVALID_PAGE;
		break;
	    case Ctrl('A'):
		a_pastetagpost(&me, 1);
		returnvalue = DIRCHANGED;
		me.page = A_INVALID_PAGE;
		break;
	    case 'a':
		a_appenditem(&me, 1);
		me.page = A_INVALID_PAGE;
		break;
	    }

	    if (me.num)
		switch (ch) {
		case 'm':
		    a_moveitem(&me);
		    me.page = A_INVALID_PAGE;
		    break;

		case 'D':
		    /* Ptt me.page = -1; */
		    a_delrange(&me, sess->backup_dir);
		    me.page = A_INVALID_PAGE;
		    break;
		case 'd':
		    a_delete(&me, sess->backup_dir);
		    me.page = A_INVALID_PAGE;
		    break;
		case 'H':
		    a_hideitem(&me);
		    me.page = A_INVALID_PAGE;
		    break;
		case 'T':
		    a_newtitle(&me);
		    me.page = A_INVALID_PAGE;
		    break;
#ifdef CHESSCOUNTRY
		case 'L':
		    a_setchesslist(&me);
		    break;
#endif
		}
	}
	if (me.level >= SYSOP) {
	    switch (ch) {
	    case 'N':
		a_showname(&me);
		me.page = A_INVALID_PAGE;
		break;
	    }
	}
    }
    free(me.header);
    return returnvalue;
}
Beispiel #9
0
static int
search_key_user(const char *passwdfile, int mode)
{
    userec_t        user;
    int             ch;
    int             unum = 0;
    FILE            *fp1 = fopen(passwdfile, "r");
    char            friendfile[PATHLEN]="", key[22], *keymatch;
    int		    keytype = 0;
    int	            isCurrentPwd;

    assert(fp1);

    isCurrentPwd = (strcmp(passwdfile, FN_PASSWD) == 0);
    clear();
    if (!mode)
    {
	getdata(0, 0, "請輸入id :", key, sizeof(key), DOECHO);
    } else {
	// improved search
	vs_hdr("關鍵字搜尋");
	outs("搜尋欄位: [0]全部 1.ID 2.姓名 3.暱稱 4.地址 5.Mail 6.IP 7.職業 8.認證\n");
	getdata(2, 0, "要搜尋哪種資料?", key, 2, NUMECHO);

	if (isascii(key[0]) && isdigit(key[0]))
	    keytype = key[0] - '0';
	if (keytype < 0 || keytype > 8)
	    keytype = 0;
	getdata(3, 0, "請輸入關鍵字: ", key, sizeof(key), DOECHO);
    }

    if(!key[0]) {
	fclose(fp1);
	return 0;
    }
    vs_hdr(key);

    // <= or < ? I'm not sure...
    while ((fread(&user, sizeof(user), 1, fp1)) > 0 && unum++ < MAX_USERS) {

	// skip empty records
	if (!user.userid[0])
	    continue;

	if (!(unum & 0xFF)) {
	    vs_hdr(key);
	    prints("第 [%d] 筆資料\n", unum);
	    refresh();
	}

	// XXX 這裡會取舊資料,要小心 PWD 的 upgrade
	if (!upgrade_passwd(&user))
	    continue;

        keymatch = NULL;

	if (!mode)
	{
	    // only verify id
	    if (!strcasecmp(user.userid, key))
		keymatch = user.userid;
	} else {
	    // search by keytype
	    if ((!keytype || keytype == 1) &&
		DBCS_strcasestr(user.userid, key))
		keymatch = user.userid;
	    else if ((!keytype || keytype == 2) &&
		DBCS_strcasestr(user.realname, key))
		keymatch = user.realname;
	    else if ((!keytype || keytype == 3) &&
		DBCS_strcasestr(user.nickname, key))
		keymatch = user.nickname;
	    else if ((!keytype || keytype == 4) &&
		DBCS_strcasestr(user.address, key))
		keymatch = user.address;
	    else if ((!keytype || keytype == 5) &&
		strcasestr(user.email, key)) // not DBCS.
		keymatch = user.email;
	    else if ((!keytype || keytype == 6) &&
		strcasestr(user.lasthost, key)) // not DBCS.
		keymatch = user.lasthost;
	    else if ((!keytype || keytype == 7) &&
		DBCS_strcasestr(user.career, key))
		keymatch = user.career;
	    else if ((!keytype || keytype == 8) &&
		DBCS_strcasestr(user.justify, key))
		keymatch = user.justify;
	}

        if(keymatch) {
	    vs_hdr(key);
	    prints("第 [%d] 筆資料\n", unum);
	    refresh();

	    user_display(&user, 1);
	    // user_display does not have linefeed in tail.

	    if (isCurrentPwd && HasUserPerm(PERM_ACCOUNTS))
		uinfo_query(user.userid, 1, unum);
	    else
		outs("\n");

	    // XXX don't trust 'user' variable after here
	    // because uinfo_query may have changed it.

	    outs(ANSI_COLOR(44) "               空白鍵" \
		 ANSI_COLOR(37) ":搜尋下一個          " \
		 ANSI_COLOR(33)" Q" ANSI_COLOR(37)": 離開");
	    outs(mode ?
                 "      A: add to namelist " ANSI_RESET " " :
		 "      S: 取用備份資料    " ANSI_RESET " ");
	    while (1) {
		while ((ch = vkey()) == 0)
		    ;
                if (ch == 'a' || ch=='A' )
                  {
                   if(!friendfile[0])
                    {
                     friend_special();
                     setfriendfile(friendfile, FRIEND_SPECIAL);
                    }
                   friend_add(user.userid, FRIEND_SPECIAL, keymatch);
                   break;
                  }
		if (ch == ' ')
		    break;
		if (ch == 'q' || ch == 'Q') {
		    fclose(fp1);
		    return 0;
		}
		if (ch == 's' && !mode) {
		    if (retrieve_backup(&user) >= 0) {
			fclose(fp1);
                        vmsg("已成功\取用備份資料。");
			return 0;
		    } else {
                        vmsg("錯誤: 取用備份資料失敗。");
                    }
		}
	    }
	}
Beispiel #10
0
static int 
common_pager_key_handler(int ch, void *ctx)
{
    switch(ch)
    {
	// Special service keys
	case 'z':
	    if (!HasUserPerm(PERM_BASIC))
		break;
	    return RET_DOCHESSREPLAY;

#if defined(USE_BBSLUA) && !defined(DISABLE_BBSLUA_IN_PAGER)
	case 'L':
	case 'l':
	    if (!HasUserPerm(PERM_BASIC))
		break;
	    return RET_DOBBSLUA;
#endif
	
	// Query information and file touch
	case 'Q':
	    return RET_DOQUERYINFO;

	case Ctrl('T'):
	    if (!HasUserPerm(PERM_BASIC))
		break;
	    return RET_COPY2TMP;

	case 'E':
	    // for early check, skip file name (must check again later)
	    if (!check_sysop_edit_perm("")) 
		break;
	    return RET_DOSYSOPEDIT;

	// Making Response
	case '%':
	case 'X':
	    return RET_DORECOMMEND;

	case 'r': case 'R':
	    return RET_DOREPLY;

	case 'Y': case 'y':
	    return RET_DOREPLYALL;

	// Special Navigation
	case 's':
	    if (!HasUserPerm(PERM_BASIC) ||
		currstat != READING)
		break;
	    return RET_SELECTBRD;

	case '#':
	    if (!HasUserPerm(PERM_BASIC) ||
		currstat != READING)
		break;
	    return RET_SELECTAID;
	
	/* ------- SOB THREADED NAVIGATION EXITING KEYS ------- */
	// I'm not sure if these keys are all invented by SOB,
	// but let's honor their names.
	// Kaede, Raw, Izero, woju - you are all TWBBS heroes  
	//                                  -- by piaip, 2008.
	case 'A':
	    return AUTHOR_PREV;
	case 'a':
	    return AUTHOR_NEXT;
	case 'F': case 'f':
	    return READ_NEXT;
	case 'B': case 'b':
	    return READ_PREV;

	/* from Kaede, thread reading */
	case ']':
	case '+':
	    return RELATE_NEXT;
	case '[':
	case '-':
	    return RELATE_PREV;
	case '=':
	    return RELATE_FIRST;
    }

    return DONOTHING;
}