summaryrefslogtreecommitdiffstats
path: root/mbbsd/read.c
diff options
context:
space:
mode:
authorin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2002-03-07 23:13:44 +0800
committerin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2002-03-07 23:13:44 +0800
commitae31e19f92e717919ac8e3db9039eb38d2b89aae (patch)
treec70164d6a1852344f44b04a653ae2815043512af /mbbsd/read.c
downloadpttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.gz
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.bz2
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.lz
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.xz
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.zst
pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.zip
Initial revision
git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@1 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/read.c')
-rw-r--r--mbbsd/read.c998
1 files changed, 998 insertions, 0 deletions
diff --git a/mbbsd/read.c b/mbbsd/read.c
new file mode 100644
index 00000000..b92f95e7
--- /dev/null
+++ b/mbbsd/read.c
@@ -0,0 +1,998 @@
+/* $Id: read.c,v 1.1 2002/03/07 15:13:48 in2 Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "perm.h"
+#include "proto.h"
+
+#define MAXPATHLEN 256
+
+extern int p_lines; /* a Page of Screen line numbers: tlines-4 */
+extern int b_lines; /* Screen bottom line number: t_lines-1 */
+extern char currowner[IDLEN + 2];
+extern char currtitle[44];
+extern char currauthor[IDLEN + 2];
+extern char *str_reply;
+extern char *msg_fwd_ok;
+extern char *msg_fwd_err1;
+extern char *msg_fwd_err2;
+extern int currmode;
+extern unsigned int currstat;
+extern char currboard[]; /* name of currently selected board */
+extern int KEY_ESC_arg;
+extern int curredit;
+extern char *msg_mailer;
+extern int currbid;
+extern bcache_t *brdshm;
+
+char currdirect[64];
+static fileheader_t *headers = NULL;
+static int last_line;
+static int hit_thread;
+
+/* rocker.011018: add new tag */
+
+extern int rget();
+extern char getans();
+extern void touchdircache();
+extern int get_fileheader_cache();
+
+/* rocker.011018: 新的tag方式 */
+
+#define MAXTAGS 256
+
+#include <sys/mman.h>
+
+typedef struct
+{
+ time_t chrono;
+ int recno;
+} TagItem;
+
+
+/* ----------------------------------------------------- */
+/* Tag List 標籤 */
+/* ----------------------------------------------------- */
+
+
+int TagNum; /* tag's number */
+TagItem TagList[MAXTAGS]; /* ascending list */
+
+void
+UnTagger (int locus)
+{
+ if (locus > TagNum) return;
+
+ TagNum--;
+
+ if (TagNum > locus)
+ memcpy(&TagList[locus], &TagList[locus + 1],
+ (TagNum - locus) * sizeof(TagItem));
+}
+
+int
+Tagger(time_t chrono, int recno, int mode)
+{
+ int head, tail, posi = 0, comp;
+
+ for (head = 0, tail = TagNum - 1, comp = 1; head <= tail;)
+ {
+ posi = (head + tail) >> 1;
+ comp = TagList[posi].chrono - chrono;
+ if (!comp)
+ {
+ break;
+ }
+ else if (comp < 0)
+ {
+ head = posi + 1;
+ }
+ else
+ {
+ tail = posi - 1;
+ }
+ }
+
+ if (mode == TAG_NIN)
+ {
+ if (!comp && recno) /* 絕對嚴謹:連 recno 一起比對 */
+ comp = recno - TagList[posi].recno;
+ return comp;
+
+ }
+
+ if (!comp)
+ {
+ if (mode != TAG_TOGGLE)
+ return NA;
+
+ TagNum--;
+ memcpy(&TagList[posi], &TagList[posi + 1],
+ (TagNum - posi) * sizeof(TagItem));
+ }
+ else if (TagNum < MAXTAGS)
+ {
+ TagItem *tagp, buf[MAXTAGS];
+
+ tail = (TagNum - head) * sizeof(TagItem);
+ tagp = &TagList[head];
+ memcpy(buf, tagp, tail);
+ tagp->chrono = chrono;
+ tagp->recno = recno;
+ memcpy(++tagp, buf, tail);
+ TagNum++;
+ }
+ else
+ {
+ bell();
+ return 0; /* full */
+ }
+ return YEA;
+}
+
+
+void
+EnumTagName( char *fname, int locus)
+{
+ sprintf(fname, "M.%d.A", (int) TagList[locus].chrono);
+}
+
+void
+EnumTagFhdr(fileheader_t *fhdr, char *direct, int locus)
+{
+ get_record(direct, fhdr, sizeof(fileheader_t), TagList[locus].recno);
+}
+
+/* -1 : 取消 */
+/* 0 : single article */
+/* ow: whole tag list */
+
+int
+AskTag(char *msg)
+{
+ char buf[80];
+ int num;
+
+ num = TagNum;
+ sprintf(buf, "◆ %s A)文章 T)標記 Q)uit?", msg);
+ switch (rget(b_lines-1, buf))
+ {
+ case 'q':
+ num = -1;
+ break;
+ case 'a':
+ num = 0;
+ }
+ return num;
+}
+
+
+#include <sys/mman.h>
+
+#define BATCH_SIZE 65536
+
+char *
+f_map (char *fpath, int *fsize)
+{
+ int fd, size;
+ struct stat st;
+
+ if ((fd = open(fpath, O_RDONLY)) < 0)
+ return (char *) -1;
+
+ if (fstat(fd, &st) || !S_ISREG(st.st_mode) || (size = st.st_size) <= 0)
+ {
+ close(fd);
+ return (char *) -1;
+ }
+
+ fpath = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+ *fsize = size;
+ return fpath;
+}
+
+
+static int
+TagThread(char *direct)
+{
+ int fsize, count;
+ char *title, *fimage;
+ fileheader_t *head, *tail;
+
+ fimage = f_map(direct, &fsize);
+ if ( fimage == (char *) -1)
+ return DONOTHING;
+
+ head = (fileheader_t *) fimage;
+ tail = (fileheader_t *) (fimage + fsize);
+ count = 0;
+ do
+ {
+ count++;
+ title = subject(head->title);
+ if (!strncmp( currtitle, title,TTLEN))
+ {
+ if (!Tagger(atoi (head->filename + 2), count, TAG_INSERT))
+ break;
+ }
+ } while (++head < tail);
+
+ munmap(fimage, fsize);
+ return FULLUPDATE;
+}
+
+
+int
+TagPruner(int bid)
+{
+ if (TagNum && ((currstat != READING) || (currmode & MODE_BOARD)))
+ {
+ if(getans("刪除所有標記[N]?") != 'y')
+ return FULLUPDATE;
+ delete_range(currdirect, 0, 0);
+ TagNum = 0;
+ if(bid>0);
+ setbtotal(bid);
+ return NEWDIRECT;
+ }
+ return DONOTHING;
+}
+
+
+/* ----------------------------------------------------- */
+/* cursor & reading record position control */
+/* ----------------------------------------------------- */
+keeploc_t *getkeep(char *s, int def_topline, int def_cursline) {
+ static struct keeploc_t *keeplist = NULL;
+ struct keeploc_t *p;
+ void *malloc();
+
+ if(def_cursline >= 0)
+ for(p = keeplist; p; p = p->next) {
+ if(!strcmp(s, p->key)) {
+ if(p->crs_ln < 1)
+ p->crs_ln = 1;
+ return p;
+ }
+ }
+ else
+ def_cursline = -def_cursline;
+ p = (keeploc_t *)malloc(sizeof(keeploc_t));
+ p->key = (char *)malloc(strlen(s) + 1);
+ strcpy(p->key, s);
+ p->top_ln = def_topline;
+ p->crs_ln = def_cursline;
+ p->next = keeplist;
+ return (keeplist = p);
+}
+
+void fixkeep(char *s, int first) {
+ keeploc_t *k;
+
+ k = getkeep(s, 1, 1);
+ if(k->crs_ln >= first) {
+ k->crs_ln = (first == 1 ? 1 : first - 1);
+ k->top_ln = (first < 11 ? 1 : first - 10);
+ }
+}
+
+/* calc cursor pos and show cursor correctly */
+static int cursor_pos(keeploc_t *locmem, int val, int from_top) {
+ int top;
+
+ if(val > last_line) {
+ bell();
+ val = last_line;
+ }
+ if(val <= 0) {
+ bell();
+ val = 1;
+ }
+
+ top = locmem->top_ln;
+ if(val >= top && val < top + p_lines) {
+ cursor_clear(3 + locmem->crs_ln - top, 0);
+ locmem->crs_ln = val;
+ cursor_show(3 + val - top, 0);
+ return DONOTHING;
+ }
+ locmem->top_ln = val - from_top;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = val;
+ return PARTUPDATE;
+}
+
+static int move_cursor_line(keeploc_t *locmem, int mode) {
+ int top, crs;
+ int reload = 0;
+
+ top = locmem->top_ln;
+ crs = locmem->crs_ln;
+ if(mode == READ_PREV) {
+ if(crs <= top) {
+ top -= p_lines - 1;
+ if(top < 1)
+ top = 1;
+ reload = 1;
+ }
+ if(--crs < 1) {
+ crs = 1;
+ reload = -1;
+ }
+ } else if(mode == READ_NEXT) {
+ if(crs >= top + p_lines - 1) {
+ top += p_lines - 1;
+ reload = 1;
+ }
+ if(++crs > last_line) {
+ crs = last_line;
+ reload = -1;
+ }
+ }
+ locmem->top_ln = top;
+ locmem->crs_ln = crs;
+ return reload;
+}
+
+static int thread(keeploc_t *locmem, int stype) {
+ static char a_ans[32], t_ans[32];
+ char ans[32], s_pmt[64];
+ register char *tag, *query = NULL;
+ register int now, pos, match, near = 0;
+ fileheader_t fh;
+ int circulate_flag = 1; /* circulate at end or begin */
+
+ match = hit_thread = 0;
+ now = pos = locmem->crs_ln;
+ if(stype == 'A') {
+ if(!*currowner)
+ return DONOTHING;
+ str_lower(a_ans, currowner);
+ query = a_ans;
+ circulate_flag = 0;
+ stype = 0;
+ } else if(stype == 'a') {
+ if(!*currowner)
+ return DONOTHING;
+ str_lower(a_ans, currowner);
+ query = a_ans;
+ circulate_flag = 0;
+ stype = RS_FORWARD;
+ } else if(stype == '/') {
+ if(!*t_ans)
+ return DONOTHING;
+ query = t_ans;
+ circulate_flag = 0;
+ stype = RS_TITLE | RS_FORWARD;
+ } else if(stype == '?') {
+ if(!*t_ans)
+ return DONOTHING;
+ circulate_flag = 0;
+ query = t_ans;
+ stype = RS_TITLE;
+ } else if(stype & RS_RELATED) {
+ tag = headers[pos - locmem->top_ln].title;
+ if(stype & RS_CURRENT) {
+ if(stype & RS_FIRST) {
+ if(!strncmp(currtitle, tag, 40))
+ return DONOTHING;
+ near = 0;
+ }
+ query = currtitle;
+ } else {
+ query = subject(tag);
+ if(stype & RS_FIRST) {
+ if(query == tag)
+ return DONOTHING;
+ near = 0;
+ }
+ }
+ } else if(!(stype & RS_THREAD)) {
+ query = (stype & RS_TITLE) ? t_ans : a_ans;
+ if(!*query && query == a_ans) {
+ if(*currowner)
+ strcpy(a_ans, currowner);
+ else if (*currauthor)
+ strcpy(a_ans, currauthor);
+ }
+ sprintf(s_pmt, "%s搜尋%s [%s] ",(stype & RS_FORWARD) ? "往後":"往前",
+ (stype & RS_TITLE) ? "標題" : "作者", query);
+ getdata(b_lines - 1, 0, s_pmt, ans, 30, DOECHO);
+ if(*ans)
+ strcpy(query, ans);
+ else if(*query == '\0')
+ return DONOTHING;
+ }
+
+ tag = fh.owner;
+
+ do {
+ if(!circulate_flag || stype & RS_RELATED) {
+ if(stype & RS_FORWARD) {
+ if(++now > last_line)
+ return DONOTHING;
+ } else {
+ if(--now <= 0) {
+ if((stype & RS_FIRST) && (near)) {
+ hit_thread = 1;
+ return cursor_pos(locmem, near, 10);
+ }
+ return DONOTHING;
+ }
+ }
+ } else {
+ if(stype & RS_FORWARD) {
+ if(++now > last_line)
+ now = 1;
+ } else if(--now <= 0)
+ now = last_line;
+ }
+
+ get_record(currdirect, &fh, sizeof(fileheader_t), now);
+
+ if(fh.owner[0] == '-')
+ continue;
+
+ if(stype & RS_THREAD) {
+ if(strncasecmp(fh.title, str_reply, 3)) {
+ hit_thread = 1;
+ return cursor_pos(locmem, now, 10);
+ }
+ continue;
+ }
+
+ if(stype & RS_TITLE)
+ tag = subject(fh.title);
+
+ if(((stype & RS_RELATED) && !strncmp(tag, query, 40)) ||
+ (!(stype & RS_RELATED) && ((query == currowner) ?
+ !strcmp(tag, query) :
+ strstr_lower(tag, query)))) {
+ if((stype & RS_FIRST) && tag != fh.title) {
+ near = now;
+ continue;
+ }
+
+ hit_thread = 1;
+ match = cursor_pos(locmem, now, 10);
+ if((!(stype & RS_CURRENT)) &&
+ (stype & RS_RELATED) &&
+ strncmp(currtitle, query, 40)) {
+ strncpy(currtitle, query, 40);
+ match = PARTUPDATE;
+ }
+ break;
+ }
+ } while(now != pos);
+
+ return match;
+}
+
+
+#ifdef INTERNET_EMAIL
+static void mail_forward(fileheader_t *fhdr, char *direct, int mode) {
+ int i;
+ char buf[STRLEN];
+ char *p;
+
+ strncpy(buf, direct, sizeof(buf));
+ if((p = strrchr(buf, '/')))
+ *p = '\0';
+ switch(i = doforward(buf, fhdr, mode)) {
+ case 0:
+ outmsg(msg_fwd_ok);
+ break;
+ case -1:
+ outmsg(msg_fwd_err1);
+ break;
+ case -2:
+ outmsg(msg_fwd_err2);
+ break;
+ default:
+ break;
+ }
+ refresh();
+ sleep(1);
+}
+#endif
+
+extern userec_t cuser;
+
+static int select_read(keeploc_t *locmem, int sr_mode) {
+ register char *tag,*query,*temp;
+ fileheader_t fh;
+ char fpath[80], genbuf[MAXPATHLEN], buf3[5];
+ char static t_ans[TTLEN+1]="";
+ char static a_ans[IDLEN+1]="";
+ int fd, fr, size = sizeof(fileheader_t);
+ struct stat st;
+/* rocker.011018: make a reference number for process article */
+ int reference = 0;
+
+ if((currmode & MODE_SELECT))
+ return -1;
+ if(sr_mode == RS_TITLE)
+ query = subject(headers[locmem->crs_ln - locmem->top_ln].title);
+ else if(sr_mode == RS_NEWPOST)
+ {
+ strcpy(buf3, "Re: ");
+ query = buf3;
+ }
+ else
+ {
+ char buff[80];
+
+ query = (sr_mode == RS_RELATED) ? t_ans : a_ans;
+ sprintf(buff, "搜尋%s [%s] ",
+ (sr_mode == RS_RELATED) ? "標題" : "作者", query);
+ getdata(b_lines, 0,buff, query, 30, DOECHO);
+ if(!(*query))
+ return DONOTHING;
+ }
+
+ if((fd = open(currdirect, O_RDONLY, 0)) != -1) {
+ sprintf(genbuf,"SR.%s",cuser.userid);
+ if(currstat==RMAIL)
+ sethomefile(fpath,cuser.userid,genbuf);
+ else
+ setbfile(fpath,currboard,genbuf);
+ if(((fr = open(fpath,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1)) {
+ switch(sr_mode) {
+ case RS_TITLE:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = subject(fh.title);
+ if(!strncmp(tag, query, 40))
+ {
+ fh.money = reference | FHR_REFERENCE;
+ write(fr,&fh,size);
+ }
+ }
+ break;
+ case RS_RELATED:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = fh.title;
+ if(strcasestr(tag,query))
+ {
+ fh.money = reference | FHR_REFERENCE;
+ write(fr,&fh,size);
+ }
+ }
+ break;
+ case RS_NEWPOST:
+ while(read(fd, &fh, size) == size) {
+ ++reference;
+ tag = fh.title;
+ temp = strstr(tag, query);
+ if(temp == NULL || temp != tag)
+ {
+ write(fr, &fh, size);
+ fh.money = reference | FHR_REFERENCE;
+ }
+ }
+ case RS_AUTHOR:
+ while(read(fd,&fh,size) == size) {
+ ++reference;
+ tag = fh.owner;
+ if(strcasestr(tag,query))
+ {
+ write(fr,&fh,size);
+ fh.money = reference | FHR_REFERENCE;
+ }
+ }
+ break;
+ }
+ fstat(fr,&st);
+ close(fr);
+ }
+ close(fd);
+ if(st.st_size) {
+ currmode |= MODE_SELECT;
+ strcpy(currdirect,fpath);
+ }
+ }
+ return st.st_size;
+}
+
+extern userec_t xuser;
+
+static int i_read_key(onekey_t *rcmdlist, keeploc_t *locmem, int ch, int bid) {
+ int i, mode = DONOTHING;
+
+ switch(ch) {
+ case 'q':
+ case 'e':
+ case KEY_LEFT:
+ return (currmode & MODE_SELECT) ? board_select() :
+ (currmode & MODE_ETC) ? board_etc() :
+ (currmode & MODE_DIGEST) ? board_digest() : DOQUIT;
+ case Ctrl('L'):
+ redoscr();
+ break;
+/*
+ case Ctrl('C'):
+ cal();
+ return FULLUPDATE;
+ break;
+*/
+ case KEY_ESC:
+ if(KEY_ESC_arg == 'i') {
+ t_idle();
+ return FULLUPDATE;
+ }
+ break;
+ case Ctrl('H'):
+ if(select_read(locmem, RS_NEWPOST))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case 'a':
+ case 'A':
+ if(select_read(locmem,RS_AUTHOR))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case '/':
+ case '?':
+ if(select_read(locmem,RS_RELATED))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ case 'S':
+ if(select_read(locmem,RS_TITLE))
+ return NEWDIRECT;
+ else
+ return READ_REDRAW;
+ /* quick search title first */
+ case '=':
+ return thread(locmem, RELATE_FIRST);
+ case '\\':
+ return thread(locmem, CURSOR_FIRST);
+ /* quick search title forword */
+ case ']':
+ return thread(locmem, RELATE_NEXT);
+ case '+':
+ return thread(locmem, CURSOR_NEXT);
+ /* quick search title backword */
+ case '[':
+ return thread(locmem, RELATE_PREV);
+ case '-':
+ return thread(locmem, CURSOR_PREV);
+ case '<':
+ case ',':
+ return thread(locmem, THREAD_PREV);
+ case '.':
+ case '>':
+ return thread(locmem, THREAD_NEXT);
+ case 'p':
+ case 'k':
+ case KEY_UP:
+ return cursor_pos(locmem, locmem->crs_ln - 1, p_lines - 2);
+ case 'n':
+ case 'j':
+ case KEY_DOWN:
+ return cursor_pos(locmem, locmem->crs_ln + 1, 1);
+ case ' ':
+ case KEY_PGDN:
+ case 'N':
+ case Ctrl('F'):
+ if(last_line >= locmem->top_ln + p_lines) {
+ if(last_line > locmem->top_ln + p_lines)
+ locmem->top_ln += p_lines;
+ else
+ locmem->top_ln += p_lines - 1;
+ locmem->crs_ln = locmem->top_ln;
+ return PARTUPDATE;
+ }
+ cursor_clear(3 + locmem->crs_ln - locmem->top_ln, 0);
+ locmem->crs_ln = last_line;
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ break;
+ case KEY_PGUP:
+ case Ctrl('B'):
+ case 'P':
+ if(locmem->top_ln > 1) {
+ locmem->top_ln -= p_lines;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = locmem->top_ln;
+ return PARTUPDATE;
+ }
+ break;
+ case KEY_END:
+ case '$':
+ if(last_line >= locmem->top_ln + p_lines) {
+ locmem->top_ln = last_line - p_lines + 1;
+ if(locmem->top_ln <= 0)
+ locmem->top_ln = 1;
+ locmem->crs_ln = last_line;
+ return PARTUPDATE;
+ }
+ cursor_clear(3 + locmem->crs_ln - locmem->top_ln, 0);
+ locmem->crs_ln = last_line;
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ break;
+ case 'F':
+ case 'U':
+ if(HAS_PERM(PERM_FORWARD)) {
+ mail_forward(&headers[locmem->crs_ln - locmem->top_ln],
+ currdirect, ch /*== 'U'*/);
+ /*by CharlieL*/
+ return FULLUPDATE;
+ }
+ break;
+ case Ctrl('Q'):
+ return my_query(headers[locmem->crs_ln - locmem->top_ln].owner);
+ case Ctrl('S'):
+ if(HAS_PERM(PERM_ACCOUNTS)) {
+ int id;
+ userec_t muser;
+
+ strcpy(currauthor, headers[locmem->crs_ln - locmem->top_ln].owner);
+ stand_title("使用者設定");
+ move(1, 0);
+ if((id = getuser(headers[locmem->crs_ln - locmem->top_ln].owner))){
+ memcpy(&muser, &xuser, sizeof(muser));
+ user_display(&muser, 1);
+ uinfo_query(&muser, 1, id);
+ }
+ return FULLUPDATE;
+ }
+ break;
+
+/* rocker.011018: 採用新的tag模式 */
+ case 't':
+/* rocker.011112: 解決再select mode標記文章的問題 */
+ if (Tagger(atoi(headers[locmem->crs_ln - locmem->top_ln].filename + 2),
+ (currmode & MODE_SELECT) ?
+ (headers[locmem->crs_ln - locmem->top_ln].money & ~FHR_REFERENCE) :
+ locmem->crs_ln, TAG_TOGGLE))
+ return POS_NEXT;
+ return DONOTHING;
+
+ case Ctrl('C'):
+ if (TagNum)
+ {
+ TagNum = 0;
+ return FULLUPDATE;
+ }
+ return DONOTHING;
+
+ case Ctrl('T'):
+ return TagThread(currdirect);
+ case Ctrl('D'):
+ return TagPruner(bid);
+ case '\n':
+ case '\r':
+ case 'l':
+ case KEY_RIGHT:
+ ch = 'r';
+ default:
+ for(i = 0; rcmdlist[i].fptr; i++) {
+ if(rcmdlist[i].key == ch) {
+ mode = (*(rcmdlist[i].fptr))(locmem->crs_ln,
+ &headers[locmem->crs_ln -
+ locmem->top_ln], currdirect);
+ break;
+ }
+ if(rcmdlist[i].key == 'h')
+ if(currmode & (MODE_ETC | MODE_DIGEST))
+ return DONOTHING;
+ }
+ }
+ return mode;
+}
+
+void i_read(int cmdmode, char *direct, void (*dotitle)(), void (*doentry)(), onekey_t *rcmdlist, int bidcache) {
+ keeploc_t *locmem = NULL;
+ int recbase = 0, mode, ch;
+ int num = 0, entries = 0;
+ int i;
+ int jump = 0;
+ char genbuf[4];
+ char currdirect0[64];
+ int last_line0 = last_line;
+ int hit_thread0 = hit_thread;
+ fileheader_t *headers0 = headers;
+
+ strcpy(currdirect0 ,currdirect);
+#define FHSZ sizeof(fileheader_t)
+// Ptt:這邊headers 可以針對看板的最後60篇做cache
+ headers = (fileheader_t *)calloc(p_lines, FHSZ);
+ strcpy(currdirect, direct);
+ mode = NEWDIRECT;
+
+/* rocker.011018: 加入新的tag機制 */
+ TagNum = 0;
+
+ do {
+ /* 依據 mode 顯示 fileheader */
+ setutmpmode(cmdmode);
+ switch(mode) {
+ case NEWDIRECT: /* 第一次載入此目錄 */
+ case DIRCHANGED:
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST)) )
+ last_line=getbtotal(currbid);
+ else
+ last_line= get_num_records(currdirect, FHSZ);
+
+ if(mode == NEWDIRECT) {
+ if(last_line == 0) {
+ if(curredit & EDIT_ITEM) {
+ outs("沒有物品");
+ refresh();
+ goto return_i_read;
+ } else if(curredit & EDIT_MAIL) {
+ outs("沒有來信");
+ refresh();
+ goto return_i_read;
+ } else if(currmode & MODE_ETC) {
+ board_etc(); /* Kaede */
+ outmsg("尚未收錄其它文章");
+ refresh();
+ } else if(currmode & MODE_DIGEST) {
+ board_digest(); /* Kaede */
+ outmsg("尚未收錄文摘");
+ refresh();
+ } else if(currmode & MODE_SELECT) {
+ board_select(); /* Leeym */
+ outmsg("沒有此系列的文章");
+ refresh();
+ } else {
+ getdata(b_lines - 1, 0,
+ "看板新成立 (P)發表文章 (Q)離開?[Q] ",
+ genbuf, 4, LCECHO);
+ if(genbuf[0] == 'p')
+ do_post();
+ goto return_i_read;
+ }
+ }
+ num = last_line - p_lines + 1;
+ locmem = getkeep(currdirect, num < 1 ? 1 : num, last_line);
+ }
+ recbase = -1;
+
+ case FULLUPDATE:
+ (*dotitle)();
+
+ case PARTUPDATE:
+ if(last_line < locmem->top_ln + p_lines) {
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST)))
+ num=getbtotal(currbid);
+ else
+ num = get_num_records(currdirect, FHSZ);
+
+ if(last_line != num) {
+ last_line = num;
+ recbase = -1;
+ }
+ }
+
+ if(last_line == 0)
+ goto return_i_read;
+ else if(recbase != locmem->top_ln) {
+ recbase = locmem->top_ln;
+ if(recbase > last_line) {
+ recbase = (last_line - p_lines) >> 1;
+ if(recbase < 1)
+ recbase = 1;
+ locmem->top_ln = recbase;
+ }
+ if(bidcache>0 && !(currmode & (MODE_SELECT| MODE_DIGEST))
+ && (last_line - recbase) < DIRCACHESIZE )
+ entries = get_fileheader_cache(currbid, currdirect, headers,
+ recbase, p_lines);
+ else
+ entries = get_records(currdirect, headers, FHSZ, recbase,
+ p_lines);
+ }
+ if(locmem->crs_ln > last_line)
+ locmem->crs_ln = last_line;
+ move(3, 0);
+ clrtobot();
+ case PART_REDRAW:
+ move(3, 0);
+ for (i = 0; i < entries; i++)
+ (*doentry) (locmem->top_ln + i, &headers[i]);
+ case READ_REDRAW:
+ outmsg(curredit & EDIT_ITEM ?
+ "\033[44m 私人收藏 \033[30;47m 繼續? \033[m" :
+ curredit & EDIT_MAIL ? msg_mailer : MSG_POSTER);
+ break;
+ case READ_PREV:
+ case READ_NEXT:
+ case RELATE_PREV:
+ case RELATE_NEXT:
+ case RELATE_FIRST:
+ case POS_NEXT:
+ case 'A':
+ case 'a':
+ case '/':
+ case '?':
+ jump = 1;
+ break;
+ }
+
+ /* 讀取鍵盤,加以處理,設定 mode */
+ if(!jump) {
+ cursor_show(3 + locmem->crs_ln - locmem->top_ln, 0);
+ ch = egetch();
+ mode = DONOTHING;
+ } else
+ ch = ' ';
+
+ if(mode == POS_NEXT) {
+ mode = cursor_pos(locmem, locmem->crs_ln + 1, 1);
+ if(mode == DONOTHING)
+ mode = PART_REDRAW;
+ jump = 0;
+ } else if(ch >= '0' && ch <= '9') {
+ if((i = search_num(ch, last_line)) != -1)
+ mode = cursor_pos(locmem, i + 1, 10);
+ } else {
+ if(!jump)
+ mode = i_read_key(rcmdlist, locmem, ch, currbid);
+ while(mode == READ_NEXT || mode == READ_PREV ||
+ mode == RELATE_FIRST || mode == RELATE_NEXT ||
+ mode == RELATE_PREV || mode == THREAD_NEXT ||
+ mode == THREAD_PREV || mode == 'A' || mode == 'a' ||
+ mode == '/' || mode == '?') {
+ int reload;
+
+ if(mode == READ_NEXT || mode == READ_PREV)
+ reload = move_cursor_line(locmem, mode);
+ else {
+ reload = thread(locmem, mode);
+ if(!hit_thread) {
+ mode = FULLUPDATE;
+ break;
+ }
+ }
+
+ if(reload == -1) {
+ mode = FULLUPDATE;
+ break;
+ } else if(reload) {
+ recbase = locmem->top_ln;
+
+ if(bidcache>0 && !(currmode &(MODE_SELECT| MODE_DIGEST))
+ && last_line-recbase<DIRCACHESIZE )
+ entries = get_fileheader_cache(currbid, currdirect,
+ headers, recbase, p_lines);
+ else
+ entries = get_records(currdirect, headers, FHSZ, recbase,
+ p_lines);
+
+ if(entries <= 0) {
+ last_line = -1;
+ break;
+ }
+ }
+ num = locmem->crs_ln - locmem->top_ln;
+ if(headers[num].owner[0] != '-')
+ mode = i_read_key(rcmdlist, locmem, ch, bidcache);
+ }
+ }
+ } while(mode != DOQUIT);
+#undef FHSZ
+
+ return_i_read:
+ free(headers);
+ last_line = last_line0;
+ hit_thread = hit_thread0;
+ headers = headers0;
+ strcpy(currdirect ,currdirect0);
+ return;
+}