/*-------------------------------------------------------*/
/* more.c ( NTHU CS MapleBBS Ver 2.36 ) */
/*-------------------------------------------------------*/
/* target : simple & beautiful ANSI/Chinese browser */
/* create : 95/03/29 */
/* update : 95/12/15 */
/*-------------------------------------------------------*/
#include "bbs.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define MAXPATHLEN 256
static char *more_help[] = {
"\0閱\讀文章功\能鍵使用說明",
"\01游標移動功\能鍵",
"(↑) 上捲一行",
"(↓)(Enter) 下捲一行",
"(^B)(PgUp)(BackSpace) 上捲一頁",
"(→)(PgDn)(Space) 下捲一頁",
"(0)(g)(Home) 檔案開頭",
"($)(G) (End) 檔案結尾",
"\01其他功\能鍵",
"(/) 搜尋字串",
"(n/N) 重複正/反向搜尋",
"(TAB) URL連結",
"(Ctrl-T) 存到暫存檔",
"(:/f/b) 跳至某頁/下/上篇",
"(F/B) 跳至同一搜尋主題下/上篇",
"(a/A) 跳至同一作者下/上篇",
"([/]) 主題式閱\讀 上/下",
"(t) 主題式循序閱\讀",
"(Ctrl-C) 小計算機",
"(q)(←) 結束",
"(h)(H)(?) 輔助說明畫面",
NULL};
int beep = 0;
static int
readln(fp, buf)
FILE *fp;
char *buf;
{
register int ch, i, len, bytes, in_ansi;
len = bytes = in_ansi = i = 0;
while (len < 80 && i < ANSILINELEN && (ch = getc(fp)) != EOF)
{
bytes++;
if (ch == '\n')
{
break;
}
else if (ch == '\t')
{
do
{
buf[i++] = ' ';
} while ((++len & 7) && len < 80);
}
else if (ch == '\a')
{
beep = 1;
}
else if (ch == '\033')
{
if (showansi)
buf[i++] = ch;
in_ansi = 1;
}
else if (in_ansi)
{
if (showansi)
buf[i++] = ch;
if (!strchr("[0123456789;,", ch))
in_ansi = 0;
}
else if (isprint2(ch))
{
len++;
buf[i++] = ch;
}
}
buf[i] = '\0';
return bytes;
}
int
more(fpath, promptend)
char *fpath;
int promptend;
{
extern char* strcasestr();
static char *head[4] = {"作者", "標題", "時間" ,"轉信"};
char *ptr, *word, buf[256],*ch1;
struct stat st;
FILE *fp;
usint pagebreak[MAXPAGES], pageno, lino;
int line, ch, viewed, pos, numbytes;
int header = 0;
int local = 0;
char search_char0=0;
static char search_str[81]="";
typedef char* (*FPTR)();
static FPTR fptr;
int searching = 0;
int scrollup = 0;
char *printcolor[3]= {"44","33;45","0;34;46"}, color =0;
char *http[80]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
/* Ptt */
char pagemode = 0;
char pagecount = 0;
memset(pagebreak, 0, sizeof(pagebreak));
if (*search_str)
search_char0 = *search_str;
*search_str = 0;
if (!(fp = fopen(fpath, "r")))
return -1;
if (fstat(fileno(fp), &st))
return -1;
pagebreak[0] = pageno = viewed = line = pos = 0;
clear();
while ((numbytes = readln(fp, buf)) || (line == t_lines))
{
if (scrollup) {
rscroll();
move(0, 0);
}
if (numbytes) /* 一般資料處理 */
{
if (!viewed) /* begin of file */
{
if (showansi) /* header processing */
{
if (!strncmp(buf, str_author1, LEN_AUTHOR1))
{
line = 3;
word = buf + LEN_AUTHOR1;
local = 1;
}
else if (!strncmp(buf, str_author2, LEN_AUTHOR2))
{
line = 4;
word = buf + LEN_AUTHOR2;
}
while (pos < line)
{
if (!pos && ((ptr = strstr(word, str_post1)) ||
(ptr = strstr(word, str_post2))))
{
ptr[-1] = '\0';
prints(" %s %-53.53s %.4s %-13s\n", head[0], word, ptr, ptr + 5);
}
else if (pos < 4)
prints(" %s %-72.72s\n", head[pos], word);
viewed += numbytes;
numbytes = readln(fp, buf);
if(!pos && viewed >= 79) /* 第一行太長了 */
{
if (memcmp( buf, head[1], 2)) /* 第二行不是 [標....] */
{
viewed += numbytes; /* 讀下一行進來處理 */
numbytes = readln(fp, buf);
}
}
pos++;
}
if (pos)
{
header = 1;
prints("%s\n", msg_seperator);
line = pos = 4;
}
}
lino = pos;
word = NULL;
}
/* ※處理引用者 & 引言 */
if ((buf[1] == ' ') && (buf[0] == ':' || buf[0] == '>'))
word = "";
else if ((buf[0] == 'ꄧ && buf[1] == '뀧) || !strncmp(buf, "==>", 3))
word = "";
ch1 = buf ;
while(1) /* Ptt */
{
int i;
char e,*ch2;
if(ch2 = strstr(ch1,"http://"));
else if(ch2 = strstr(ch1,"gopher://"));
else if(ch2 = strstr(ch1,"mailto:"));
else break;
for(e=0; ch2[e] != ' ' && ch2[e] != '\n' && ch2[e] != '\0'
&& ch2[e] != '"' && ch2[e] != ';' && ch2[e] != ']'; e++);
for(i=0;http[i] && i<80;i++)
if(!strncmp(http[i],ch2,e) && http[e]==0) break;
if(!http[i])
{
http[i] = (char *) malloc( e+1 );
strncpy(http[i],ch2,e);
http[i][e]=0;
pagecount++;
}
ch1 = &ch2[7];
}
if (word)
outs(word);
{
/*
woju
*/
char msg[500], *pos;
if (*search_str && (pos = fptr(buf, search_str))) {
char SearchStr[81];
char buf1[100], *pos1;
strncpy(SearchStr, pos, strlen(search_str));
SearchStr[strlen(search_str)] = 0;
searching = 0;
sprintf(msg, "%.*s%s", pos - buf, buf,
SearchStr);
while (pos = fptr(pos1 = pos + strlen(search_str), search_str)) {
sprintf(buf1, "%.*s%s", pos - pos1, pos1, SearchStr);
strcat(msg, buf1);
}
strcat(msg, pos1);
outs(Ptt_prints(msg));
}
else {
outs(Ptt_prints(buf));
}
}
if (word) {
outs("");
word = NULL;
}
outch('\n');
if (beep)
{
bell();
beep = 0;
}
if (line < b_lines) /* 一般資料讀取 */
line++;
if (line == b_lines && searching == -1) {
if (pageno > 0)
fseek(fp, viewed = pagebreak[--pageno], SEEK_SET);
else
searching = 0;
lino = pos = line = 0;
clear();
continue;
}
if (scrollup) {
move(line = b_lines, 0);
clrtoeol();
for (pos = 1; pos < b_lines; pos++)
viewed += readln(fp, buf);
}
else if (pos == b_lines) /* 捲動螢幕 */
scroll();
else
pos++;
if (!scrollup && ++lino >= b_lines && pageno < MAXPAGES - 1)
{
pagebreak[++pageno] = viewed;
lino = 1;
}
if (scrollup) {
lino = scrollup;
scrollup = 0;
}
viewed += numbytes; /* 累計讀過資料 */
}
else
line = b_lines; /* end of END */
if (promptend && (!searching && line == b_lines || viewed == st.st_size))
{
/* Kaede 剛好 100% 時不停 */
/*
if (viewed == st.st_size && viewed - numbytes == pagebreak[1])
continue;
*/
move(b_lines, 0);
if (viewed == st.st_size) {
if (searching == 1)
searching = 0;
color = 0;
}
else if (pageno == 1 && lino == 1) {
if (searching == -1)
searching = 0;
color = 1;
}
else color = 2;
prints("m 瀏覽 P.%d(%d%%) m %-30.30s%s",
printcolor[color],pageno,(viewed * 100) / st.st_size,
pagemode ? "30;47": "31;47",
pagemode ? http[pagemode-1]
: "(h)求助 →↓[PgUp][",
pagemode ?
"[TAB]切換 [Enter]選定 ←放棄"
:"PgDn][Home][End]游標移動 ←[q]結束 ");
while (line == b_lines || (line > 0 && viewed == st.st_size))
{
switch (ch = egetch())
{
case ':': {
char buf[10];
int i = 0;
getdata(b_lines - 1, 0, "Goto Page: ", buf, 5, DOECHO);
sscanf(buf, "%d", &i);
if (0 < i && i < MAXPAGES && (i == 1 || pagebreak[i - 1]))
pageno = i - 1;
else if (pageno)
pageno--;
lino = line = 0;
break;
}
case '/': {
char ans[4] = "n";
*search_str = search_char0;
getdata_buf(b_lines - 1, 0,"[搜尋]關鍵字:", search_str, 40, DOECHO);
if (*search_str) {
searching = 1;
if (getdata(b_lines - 1, 0, "區分大小寫(Y/N/Q)? [N] ", ans, 4, LCECHO) && *ans == 'y')
fptr = strstr;
else
fptr = strcasestr;
}
if (*ans == 'q')
searching = 0;
if (pageno)
pageno--;
lino = line = 0;
break;
}
case 'n':
if (*search_str) {
searching = 1;
if (pageno)
pageno--;
lino = line = 0;
}
break;
case 'N':
if (*search_str) {
searching = -1;
if (pageno)
pageno--;
lino = line = 0;
}
break;
case 'r':
case 'R':
case 'Y':
fclose(fp);
return 7;
case 'y':
fclose(fp);
return 8;
case 'A':
fclose(fp);
return 9;
case 'a':
fclose(fp);
return 10;
case 'F':
fclose(fp);
return 11;
case 'B':
fclose(fp);
return 12;
case KEY_LEFT:
if(pagemode)
{
pagemode = 0;
*search_str = 0;
if (pageno)
pageno--;
lino = line = 0;
break;
}
fclose(fp);
return 6;
case 'q':
fclose(fp);
return 0;
case 'b':
fclose(fp);
return 1;
case 'f':
fclose(fp);
return 3;
case ']': /* Kaede 為了主題閱讀方便 */
fclose(fp);
return 4;
case '[': /* Kaede 為了主題閱讀方便 */
fclose(fp);
return 2;
case '=': /* Kaede 為了主題閱讀方便 */
fclose(fp);
return 5;
case Ctrl('F'):
case KEY_PGDN:
line = 1;
break;
case 't':
if (viewed == st.st_size) {
fclose(fp);
return 4;
}
line = 1;
break;
case ' ':
if (viewed == st.st_size) {
fclose(fp);
return 3;
}
line = 1;
break;
case KEY_RIGHT:
if (viewed == st.st_size) {
fclose(fp);
return 0;
}
line = 1;
break;
case '\r':
case '\n':
if (pagemode){
more_web(http[pagemode-1],YEA);
/*pagebreak[0] = pageno = viewed = line = pos = 0;*/
pagemode = 0;
*search_str = 0;
if (pageno)
pageno--;
lino = line = 0;
break;
}
case KEY_DOWN:
if (viewed == st.st_size ||
promptend == 2 && (ch == '\r' || ch == '\n')) {
fclose(fp);
return 3;
}
line = t_lines - 2;
break;
case '$':
case 'G':
case KEY_END:
line = t_lines;
break;
case '0':
case 'g':
case KEY_HOME:
pageno = line = 0;
break;
case 'h':
case 'H':
case '?':
/* Kaede Buggy ... */
show_help(more_help);
if (pageno)
pageno--;
lino = line = 0;
break;
case 'E':
if (strcmp(fpath, "etc/ve.hlp")) {
fclose(fp);
vedit(fpath, HAS_PERM(PERM_SYSOP) ? 0 : 2);
return 0;
}
break;
case Ctrl('R'): if (currutmp->msgs[0].last_pid) {
show_last_call_in();
my_write(currutmp->msgs[0].last_pid, "水球丟回去:");
if (pageno)
pageno--;
lino = line = 0;
}
break;
case KEY_ESC:
if (KEY_ESC_arg == 'n') {
edit_note();
if (pageno)
pageno--;
lino = line = 0;
}
else if (KEY_ESC_arg == 'c')
capture_screen();
break;
case Ctrl('U'):
t_users();
if (pageno)
pageno--;
lino = line = 0;
break;
case Ctrl('C'):
cal();
if (pageno)
pageno--;
lino = line = 0;
break;
case Ctrl('T'):
getdata(b_lines - 2, 0, "把這篇文章收入到暫存檔?[y/N] ",
buf, 4, LCECHO);
if(buf[0] == 'y' )
{
char tmpbuf[128];
setuserfile(tmpbuf, ask_tmpbuf(b_lines - 1));
sprintf(buf,"cp -f %s %s",fpath, tmpbuf);
system(buf);
}
if (pageno)
pageno--;
lino = line = 0;
break;
/* case Ctrl('T'):
x_cdict();
if (pageno)
pageno--;
lino = line = 0;
break;*/
case Ctrl('I'):
/*
t_idle();
if (pageno)
pageno--;
lino = line = 0;
*/
if(!pagecount) break;
pagemode = (pagemode % pagecount) + 1;
/* if(pagemode!=1) searching =1;
else searching =-1;*/
strncpy(search_str,http[pagemode-1],80);
search_str[80] =0;
fptr = strstr;
if (pageno)
pageno--;
lino = line = 0;
break;
case KEY_UP:
line = -1;
break;
case Ctrl('B'):
case KEY_PGUP:
if (pageno > 1)
{
if (lino < 2)
pageno -= 2;
else
pageno--;
lino = line = 0;
}
else if (pageno && lino > 1)
pageno = line = 0;
break;
case Ctrl('H'):
if (pageno > 1)
{
if (lino < 2)
pageno -= 2;
else
pageno--;
lino = line = 0;
}
else if (pageno && lino > 1)
pageno = line = 0;
/*
woju
*/
else {
fclose(fp);
return 1;
}
}
}
if (line > 0)
{
move(b_lines, 0);
clrtoeol();
refresh();
}
else if (line < 0) { /* Line scroll up */
if (pageno <= 1) {
if (lino == 1 || !pageno) {
fclose(fp);
return 1;
}
if (header && lino <= 5) {
fseek(fp, viewed = pagebreak[scrollup = lino = pageno = 0] = 0, SEEK_SET);
clear();
}
}
if (pageno && lino > 1 + local) {
line = (lino - 2) - local;
if (pageno > 1 && viewed == st.st_size)
line += local;
scrollup = lino - 1;
fseek(fp, viewed = pagebreak[pageno - 1], SEEK_SET);
while (line--)
viewed += readln(fp, buf);
}
else if (pageno > 1) {
scrollup = b_lines - 1;
line = (b_lines - 2) - local;
fseek(fp, viewed = pagebreak[--pageno - 1], SEEK_SET);
while (line--)
viewed += readln(fp, buf);
}
line = pos = 0;
}
else
{
pos = 0;
fseek(fp, viewed = pagebreak[pageno], SEEK_SET);
move(0,0);
clear();
}
}
}
fclose(fp);
if (promptend)
{
pressanykey();
clear();
}
else
outs(reset_color);
return 0;
}
int
more_web(fpath, promptend)
char *fpath;
int promptend;
{
int a;
FILE *fp;
struct hostent *h;
char *ch,*ch1;
char *hostname = fpath,userfile[MAXPATHLEN],file[MAXPATHLEN]="/";
struct sockaddr_in sin;
char genbuf[200];
time_t dtime;
int i;
if(ch=strstr(fpath,"mailto:"))
{
if(!HAS_PERM(PERM_LOGINOK))
{
move(b_lines - 1,0);
outs(" 您的權限不足無法使用internet mail... ");
refresh();
sleep(1);
return 0;
}
if(!invalidaddr(&ch[7]) &&
getdata(b_lines - 1, 0, "[寄信]主題:", genbuf, 40, DOECHO))
{
do_send(&ch[7], genbuf);
}
else
{
move(b_lines - 1,0);
outs(" 收信人email 或 標題 有誤... ");
refresh();
sleep(1);
}
return 0;
}
if(ch=strstr(fpath,"gopher://"))
{
ITEM item;
strcpy(item.X.G.server, &ch[9]);
strcpy(item.X.G.path, "1/");
item.X.G.port = 70;
gem(fpath , &item, 0);
return 0;
}
if(ch=strstr(fpath,"http://"))
{
hostname=&ch[7];
}
if(ch=strchr(hostname,'/'))
{
*ch=0;
if(&ch1[1]) strcat(file,&ch[1]);
}
if(file[strlen(file)-1] == '/')
{
strcat(file,"index.html");
}
move(b_lines-1,0);
clrtoeol();
#ifdef USE_PROXY
sprintf(genbuf," 正在連往%s.(proxy:%s).....請稍候...."
,hostname,PROXYSERVER);
#else
sprintf(genbuf," 正在連往%s......請稍候....",hostname);
#endif
outs(genbuf);
refresh();
#ifdef LOCAL_PROXY
/* 先找 local disk 的 proxy */
time(&dtime);
sprintf(userfile,"hproxy/%s%s",hostname,file);
if(dashf(userfile) && (dtime - dasht(userfile)) < HPROXYDAY * 24 * 60
&& more(userfile,promptend))
{
return 1;
}
ch=userfile - 1;
while(ch1 = strchr(ch + 1,'/'))
{
*ch1 = 0;
if(!dashd(ch)) mkdir(ch+1,0755);
chdir(ch+1);
*ch1 = '/';
ch = ch1;
}
chdir(BBSHOME);
#endif
#ifndef USE_LYNX
#ifdef USE_PROXY
if (!(h = gethostbyname(PROXYSERVER)))
{
outs(" 找不到這個proxy server!..");
refresh();
sleep(1);
return;
}
(void) memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if (h == NULL)
sin.sin_addr.s_addr = inet_addr(PROXYSERVER);
else
(void) memcpy(&sin.sin_addr.s_addr, h->h_addr, h->h_length);
sin.sin_port = htons((ushort)PROXYPORT); /* HTTP port */
a = socket(AF_INET, SOCK_STREAM, 0);
if ((connect(a, (struct sockaddr *) & sin, sizeof sin)) < 0)
{
outs(" 連接到proxy受到拒絕 ! ");
refresh();
sleep(1);
return;
}
sprintf(genbuf,"GET http://%s/%s HTTP/1.1\n",hostname,file);
#else
if (!(h = gethostbyname(hostname)))
{
outs(" 找不到這個server!..");
refresh();
sleep(1);
return;
}
(void) memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if (h == NULL)
sin.sin_addr.s_addr = inet_addr(hostname);
else
(void) memcpy(&sin.sin_addr.s_addr, h->h_addr, h->h_length);
sin.sin_port = htons((ushort)80);
a = socket(AF_INET, SOCK_STREAM, 0);
if ((connect(a, (struct sockaddr *) & sin, sizeof sin)) < 0)
{
outs(" 連接受到拒絕 ! ");
refresh();
sleep(1);
return;
}
sprintf(genbuf,"GET %s\n",file);
#endif
for(i=strlen(file); file[i-1] != '/' && i>0 ; i-- );
file[i] = 0;
i=strlen(genbuf);
(void) write(a,genbuf,i);
#define BLANK 001
#define ISPRINT 002
#define PRE 004
#define CENTER 010
if(fp = fopen(userfile,"w"));
{
int flag=2,c;
char path[256];
unsigned char j,k;
while(i =read(a,genbuf,200))
{
if (i<0) return;
genbuf[i]=0;
for(j=0,k=0;genbuf[j] && j<i;j++)
{
if((flag & ISPRINT) && genbuf[j] == '<' )
{
flag |= BLANK;
}
else if((flag & ISPRINT) && genbuf[j] == '>' )
flag &= ~BLANK;
else
{
if(!(flag & BLANK))
{
if(j!=k &&
(genbuf[j] != '\n' || flag & PRE)) genbuf[k++] = genbuf[j];
}
else
{
switch(char_lower(genbuf[j]))
{
case 'a':
/*
strstr(&genbuf[j],"http
*/
break;
case 'b':
if(genbuf[j+1]=='r' && genbuf[j+2]=='>')
genbuf[k++] = '\n';
break;
case 'h':
if(genbuf[j+1]=='r' &&
(genbuf[j+2]=='>' || genbuf[j+2]=='s'))
{
strncpy(&genbuf[k],"\n--\n",4);
k+=4;
}
break;
case 'l':
if(genbuf[j+1]=='i' && genbuf[j+2]=='>')
{
strncpy(&genbuf[k],"\n◎ ",4);
k+=4;
}
break;
case 'p':
if(genbuf[j+1]=='>')
{
genbuf[k++] = '\n';
genbuf[k++] = '\n';
}
else if(genbuf[j+1]=='r' && genbuf[j+2]=='e')
{
flag ^= PRE;
}
break;
case 't':
if(genbuf[j+1]=='d' && genbuf[j+2]=='>')
{
strncpy(&genbuf[k],"\n-\n",3);
k+=3;
}
break;
}
}
if( (genbuf[j] & 0x80) && (flag & ISPRINT))
flag &= ~ISPRINT;
else flag |= ISPRINT;
}
}
genbuf[k]=0;
fputs(genbuf,fp);
}
fclose(fp);
close(a);
return more(userfile,promptend);
}
return 0;
#else /* use lynx dump */
sprintf(genbuf,"lynx -dump http://%s%s > %s",hostname,file,userfile);
system(genbuf);
return more(userfile,promptend);
#endif
}