w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

commit 9de18e5e8f4e64a5fc2c788d266479c4e6d5fe94
parent dbcee390c1c9343869f046cc67c2a7ea2fe457d0
Author: ukai <ukai>
Date:   Fri, 27 Dec 2002 16:07:44 +0000

[w3m-dev 03608] news:<newsgroup>
* XMakefile (LSRCS): add news.c
	(LOBJS): add news.o
* file.c (loadSOmething): don't UFclose() for nntp/news
	(readHeader): remove . at beginning of line for news
		img link to file:
	(loadGeneralFile): add SCM_NEWS_GROUP
		don't UFclose() for nntp/news
	(loadHTMLstream): . line check for news
	(loadBuffer): . line check for news
* fm.h (NNTP_server): added
	(NNTP_mode): added
	(MaxNewsMessage): added
* html.h (SCM_NEWS_GROUP): added
* main.c (main): NNTP_server or NNTPSERVER
		NNTP_mode or NNTPMODE
		add SCM_NEWS_GROUP
	(followA): remove news:..@.. check
	(cmd_loadURL): remove news:...@.. check
	(w3m_exit): disconnectNews
* proto.h (openNewsStream): added
	(readNewsgroup): added
	(disconnectNews): added
* rc.c (CMT_NNTP_SERVER): added
	(CMT_NNTP_MODE): added
	(CMT_MAX_NEWS): added
	(params9): add nntpserver, nntpmode, max_news
* url.c (DefaultPort): add 119 for news group
	(parseURL2): news:..@... is SCM_NEWS_GROUP
	(_parsedURL2Str): add news for SCM_NEWS_GROUP
	(openURL): cleanup SCM_NEWS
		add SCM_NEWS_GROUP
* news.c: added
From: Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp>

Diffstat:
MChangeLog | 36++++++++++++++++++++++++++++++++++++
MXMakefile | 4++--
Mfile.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mfm.h | 5+++++
Mhtml.h | 5+++--
Mmain.c | 14++++++++++++--
Anews.c | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mproto.h | 5+++++
Mrc.c | 16++++++++++++++++
Murl.c | 97++++++++++++++++---------------------------------------------------------------
10 files changed, 603 insertions(+), 113 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,5 +1,41 @@ 2002-12-28 Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp> + * [w3m-dev 03608] news:<newsgroup> + * XMakefile (LSRCS): add news.c + (LOBJS): add news.o + * file.c (loadSOmething): don't UFclose() for nntp/news + (readHeader): remove . at beginning of line for news + img link to file: + (loadGeneralFile): add SCM_NEWS_GROUP + don't UFclose() for nntp/news + (loadHTMLstream): . line check for news + (loadBuffer): . line check for news + * fm.h (NNTP_server): added + (NNTP_mode): added + (MaxNewsMessage): added + * html.h (SCM_NEWS_GROUP): added + * main.c (main): NNTP_server or NNTPSERVER + NNTP_mode or NNTPMODE + add SCM_NEWS_GROUP + (followA): remove news:..@.. check + (cmd_loadURL): remove news:...@.. check + (w3m_exit): disconnectNews + * proto.h (openNewsStream): added + (readNewsgroup): added + (disconnectNews): added + * rc.c (CMT_NNTP_SERVER): added + (CMT_NNTP_MODE): added + (CMT_MAX_NEWS): added + (params9): add nntpserver, nntpmode, max_news + * url.c (DefaultPort): add 119 for news group + (parseURL2): news:..@... is SCM_NEWS_GROUP + (_parsedURL2Str): add news for SCM_NEWS_GROUP + (openURL): cleanup SCM_NEWS + add SCM_NEWS_GROUP + * news.c: added + +2002-12-28 Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp> + * [w3m-dev 03607] mymktime: time zone support * etc.c (get_zone): added (mymktime): parse timezone diff --git a/XMakefile b/XMakefile @@ -6,9 +6,9 @@ OBJS=main.o file.o buffer.o display.o etc.o search.o linein.o table.o local.o\ form.o map.o frame.o rc.o menu.o mailcap.o image.o\ func.o cookie.o history.o backend.o $(KEYBIND_OBJ) LSRCS=terms.c conv.c url.c ftp.c anchor.c mimehead.c parsetagx.c\ - tagtable.c istream.c + tagtable.c istream.c news.c LOBJS=terms.o conv.o url.o ftp.o anchor.o mimehead.o parsetagx.o\ - tagtable.o istream.o + tagtable.o istream.o news.o LLOBJS=version.o ALIBOBJS=Str.o indep.o regex.o textlist.o parsetag.o myctype.o entity.o hash.o ALIB=libindep.a diff --git a/file.c b/file.c @@ -222,7 +222,8 @@ loadSomething(URLFile *f, buf->real_scheme = f->scheme; if (f->scheme == SCM_LOCAL && buf->sourcefile == NULL) buf->sourcefile = path; - UFclose(f); + if (f->scheme != SCM_NNTP && f->scheme != SCM_NEWS) + UFclose(f); return buf; } @@ -577,6 +578,10 @@ readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu) newBuf->header_source = tmpf->ptr; } while ((tmp = StrmyUFgets(uf))->length) { +#ifdef USE_NNTP + if (uf->scheme == SCM_NEWS && tmp->ptr[0] == '.') + Strshrinkfirst(tmp, 1); +#endif #ifdef HTTP_DEBUG { FILE *ff; @@ -588,13 +593,7 @@ readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu) if (src) Strfputs(tmp, src); cleanup_line(tmp, HEADER_MODE); - if ((tmp->ptr[0] == '\n' || tmp->ptr[0] == '\r' || tmp->ptr[0] == '\0') -#ifdef USE_NNTP - || - (uf->scheme == SCM_NEWS && - Str_news_endline(tmp) && (iseos(uf->stream) = TRUE)) -#endif /* USE_NNTP */ - ) { + if (tmp->ptr[0] == '\n' || tmp->ptr[0] == '\r' || tmp->ptr[0] == '\0') { if (!lineBuf2) /* there is no header */ break; @@ -651,7 +650,7 @@ readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu) if (tmpf) { src = Sprintf - ("<img src=\"%s\" alt=\"X-Face\" width=48 height=48>", + ("<img src=\"file:%s\" alt=\"X-Face\" width=48 height=48>", html_quote(tmpf)); init_stream(&f, SCM_LOCAL, newStrStream(src)); loadHTMLstream(&f, newBuf, NULL, TRUE); @@ -1580,6 +1579,34 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, } } break; +#ifdef USE_NNTP + case SCM_NEWS_GROUP: + { + Str group = readNewsgroup(&pu); + if (group && group->length > 0) { + FILE *src; + tmp = tmpfname(TMPF_SRC, ".html"); + pushText(fileToDelete, tmp->ptr); + src = fopen(tmp->ptr, "w"); + if (src) { + Strfputs(group, src); + fclose(src); + } + b = loadHTMLString(group); + if (b) { + b->real_type = "news:group"; + if (b->currentURL.host == NULL + && b->currentURL.file == NULL) + copyParsedURL(&b->currentURL, &pu); + b->real_scheme = pu.scheme; + if (src) + b->sourcefile = tmp->ptr; + } + return b; + } + } + break; +#endif case SCM_UNKNOWN: #ifdef USE_EXTERNAL_URI_LOADER tmp = searchURIMethods(&pu); @@ -1905,7 +1932,7 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, doFileSave(f, file); if (f.scheme == SCM_FTP) FTPhalfclose(f.stream); - else + else if (f.scheme != SCM_NNTP && f.scheme != SCM_NEWS) UFclose(&f); return NO_BUFFER; } @@ -1965,7 +1992,8 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, if (b->currentURL.host == NULL && b->currentURL.file == NULL) copyParsedURL(&b->currentURL, &pu); } - UFclose(&f); + if (f.scheme != SCM_NNTP && f.scheme != SCM_NEWS) + UFclose(&f); if (fmInitialized) term_raw(); signal(SIGINT, prevtrap); @@ -1987,7 +2015,7 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, doFileSave(f, guess_save_name(t_buf, pu.file)); if (f.scheme == SCM_FTP) FTPhalfclose(f.stream); - else + else if (f.scheme != SCM_NNTP && f.scheme != SCM_NEWS) UFclose(&f); } return NO_BUFFER; @@ -2005,7 +2033,8 @@ loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, frame_source = flag & RG_FRAME_SRC; b = loadSomething(&f, pu.real_file ? pu.real_file : pu.file, proc, t_buf); frame_source = 0; - UFclose(&f); + if (f.scheme != SCM_NNTP && f.scheme != SCM_NEWS) + UFclose(&f); if (b) { b->real_scheme = f.scheme; b->real_type = real_type; @@ -6343,6 +6372,7 @@ loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal) clen_t linelen = 0; clen_t trbyte = 0; Str lineBuf2 = Strnew(); + char *p; char code; struct html_feed_environ htmlenv1; struct readbuffer obuf; @@ -6424,6 +6454,18 @@ loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal) if (IStype(f->stream) != IST_ENCODED) f->stream = newEncodedStream(f->stream, f->encoding); while ((lineBuf2 = StrmyUFgets(f))->length) { +#ifdef USE_NNTP + if (f->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') { + Strshrinkfirst(lineBuf2, 1); + if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' || + lineBuf2->ptr[0] == '\0') { +/* + iseos(f->stream) = TRUE; +*/ + break; + } + } +#endif /* USE_NNTP */ if (src) Strfputs(lineBuf2, src); linelen += lineBuf2->length; @@ -6453,14 +6495,6 @@ loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal) #endif #endif } -#ifdef USE_NNTP - if (f->scheme == SCM_NEWS) { - if (Str_news_endline(lineBuf2)) { - iseos(f->stream) = TRUE; - break; - } - } -#endif /* USE_NNTP */ HTMLlineproc0(lineBuf2->ptr, &htmlenv1, internal); } if (obuf.status != R_ST_NORMAL) { @@ -6725,6 +6759,18 @@ loadBuffer(URLFile *uf, Buffer *volatile newBuf) if (IStype(uf->stream) != IST_ENCODED) uf->stream = newEncodedStream(uf->stream, uf->encoding); while ((lineBuf2 = StrmyISgets(uf->stream))->length) { +#ifdef USE_NNTP + if (uf->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') { + Strshrinkfirst(lineBuf2, 1); + if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' || + lineBuf2->ptr[0] == '\0') { +/* + iseos(uf->stream) = TRUE; +*/ + break; + } + } +#endif /* USE_NNTP */ if (src) Strfputs(lineBuf2, src); linelen += lineBuf2->length; @@ -6742,14 +6788,6 @@ loadBuffer(URLFile *uf, Buffer *volatile newBuf) pre_lbuf = lineBuf2->ptr[0]; } ++nlines; -#ifdef USE_NNTP - if (uf->scheme == SCM_NEWS) { - if (Str_news_endline(lineBuf2)) { - iseos(uf->stream) = TRUE; - break; - } - } -#endif /* USE_NNTP */ Strchop(lineBuf2); lineBuf2 = checkType(lineBuf2, propBuffer, #ifdef USE_ANSI_COLOR diff --git a/fm.h b/fm.h @@ -816,6 +816,11 @@ global char NoCache init(FALSE); global char use_proxy init(TRUE); #define Do_not_use_proxy (!use_proxy) global int Do_not_use_ti_te init(FALSE); +#ifdef USE_NNTP +global char *NNTP_server init(NULL); +global char *NNTP_mode init(NULL); +global int MaxNewsMessage init(50); +#endif global char *document_root init(NULL); global char *personal_document_root init(NULL); diff --git a/html.h b/html.h @@ -362,9 +362,10 @@ struct environment { #define SCM_EXEC 6 #define SCM_NNTP 7 #define SCM_NEWS 8 -#define SCM_MAILTO 9 +#define SCM_NEWS_GROUP 9 +#define SCM_MAILTO 10 #ifdef USE_SSL -#define SCM_HTTPS 10 +#define SCM_HTTPS 11 #endif /* USE_SSL */ #endif /* _HTML_H */ diff --git a/main.c b/main.c @@ -445,6 +445,12 @@ main(int argc, char **argv, char **envp) ((p = getenv("NO_PROXY")) || (p = getenv("no_proxy")) || (p = getenv("NO_proxy")))) NO_proxy = p; +#ifdef USE_NNTP + if (!non_null(NNTP_server) && (p = getenv("NNTPSERVER")) != NULL) + NNTP_server = p; + if (!non_null(NNTP_mode) && (p = getenv("NNTPMODE")) != NULL) + NNTP_mode = p; +#endif if (!non_null(Editor) && (p = getenv("EDITOR")) != NULL) Editor = p; @@ -871,6 +877,7 @@ main(int argc, char **argv, char **envp) #ifdef USE_NNTP case SCM_NNTP: case SCM_NEWS: + case SCM_NEWS_GROUP: #endif /* USE_NNTP */ case SCM_MAILTO: break; @@ -2869,7 +2876,7 @@ followA(void) pushHashHist(URLHist, a->url); return; } -#ifdef USE_NNTP +#if 0 else if (!strncasecmp(a->url, "news:", 5) && strchr(a->url, '@') == NULL) { /* news:newsgroup is not supported */ disp_err_message("news:newsgroup_name is not supported", TRUE); @@ -3824,7 +3831,7 @@ cmd_loadURL(char *url, ParsedURL *current, char *referer) pushHashHist(URLHist, url); return; } -#ifdef USE_NNTP +#if 0 if (!strncasecmp(url, "news:", 5) && strchr(url, '@') == NULL) { /* news:newsgroup is not supported */ disp_err_message("news:newsgroup_name is not supported", TRUE); @@ -5450,6 +5457,9 @@ w3m_exit(int i) #ifdef USE_SSL free_ssl_ctx(); #endif +#ifdef USE_NNTP + disconnectNews(); +#endif exit(i); } diff --git a/news.c b/news.c @@ -0,0 +1,438 @@ +/* $Id$ */ +#include "fm.h" +#include "myctype.h" +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <signal.h> +#include <setjmp.h> + +#ifdef USE_NNTP + +#define NEWS_ENDLINE(p) \ + ((*(p) == '.' && ((p)[1] == '\n' || (p)[1] == '\r' || (p)[1] == '\0')) || \ + *(p) == '\n' || *(p) == '\r' || *(p) == '\0') + +typedef struct _News { + char *host; + int port; + char *mode; + InputStream rf; + FILE *wf; +} News; + +static News current_news = { NULL, 0, NULL, NULL, NULL }; + +static JMP_BUF AbortLoading; + +static MySignalHandler +KeyAbort(SIGNAL_ARG) +{ + LONGJMP(AbortLoading, 1); + SIGNAL_RETURN; +} + +static Str +news_command(News *news, char *command, int *status) +{ + Str tmp; + char c; + + if (!news->host) + return NULL; + if (command) { + fprintf(news->wf, "%s\r\n", command); + fflush(news->wf); + } + if (!status) + return NULL; + *status = -1; + tmp = StrISgets(news->rf); + if (tmp->length) + sscanf(tmp->ptr, "%d", status); + return tmp; +} + +static void +news_close(News *news) +{ + if (!news->host) + return; + if (news->rf) { + ISclose(news->rf); + news->rf = NULL; + } + if (news->wf) { + fclose(news->wf); + news->wf = NULL; + } + news->host = NULL; +} + +static int +news_open(News *news) +{ + Str tmp; + int sock, status; + + sock = openSocket(news->host, "nntp", news->port); + if (sock < 0) + goto open_err; + news->rf = newInputStream(sock); + news->wf = fdopen(dup(sock), "wb"); + if (!news->rf || !news->wf) + goto open_err; + news_command(news, NULL, &status); + if (status != 200 && status != 201) + goto open_err; + if (news->mode) { + news_command(news, Sprintf("MODE %s", news->mode)->ptr, &status); + if (status != 200 && status != 201) + goto open_err; + } + return TRUE; + open_err: + news_close(news); + return FALSE; +} + +static void +news_quit(News *news) +{ + news_command(news, "QUIT", NULL); + news_close(news); +} + +static char * +name_from_address(char *str, int n) +{ + char *s, *p; + int i, l, space = TRUE; + + s = allocStr(str, -1); + SKIP_BLANKS(s); + if (*s == '<' && (p = strchr(s, '>'))) { + *p++ = '\0'; + SKIP_BLANKS(p); + if (*p == '\0') /* <address> */ + s++; + else /* <address> name ? */ + s = p; + } + else if ((p = strchr(s, '<'))) /* name <address> */ + *p = '\0'; + else if ((p = strchr(s, '('))) /* address (name) */ + s = p; + if (*s == '"' && (p = strchr(s + 1, '"'))) { /* "name" */ + *p = '\0'; + s++; + } + else if (*s == '(' && (p = strchr(s + 1, ')'))) { /* (name) */ + *p = '\0'; + s++; + } + for (p = s, l = 0; *p; p += i) { + i = get_mclen(get_mctype(p)); + if (IS_SPACE(*p)) { + if (space) + continue; + space = TRUE; + } + else + space = FALSE; + l += i; + if (l > n) + break; + } + *p = '\0'; + return s; +} + +static char * +html_quote_s(char *str) +{ + Str tmp = NULL; + char *p, *q; + int space = TRUE; + + for (p = str; *p; p++) { + if (IS_SPACE(*p)) { + if (space) + continue; + q = "&nbsp;"; + space = TRUE; + } + else { + q = html_quote_char(*p); + space = FALSE; + } + if (q) { + if (tmp == NULL) + tmp = Strnew_charp_n(str, (int)(p - str)); + Strcat_charp(tmp, q); + } + else { + if (tmp) + Strcat_char(tmp, *p); + } + } + if (tmp) + return tmp->ptr; + return str; +} + +static void +add_news_message(Str str, int index, char *date, char *name, char *subject, + char *mid) +{ + time_t t; + struct tm *tm; + + name = name_from_address(name, 16); + t = mymktime(date); + tm = localtime(&t); + Strcat(str, + Sprintf("<tr valign=top><td>%d<td nowrap>(%02d/%02d)<td nowrap>%s<td><a href=\"news:%s\">%s</a>\n", + index, tm->tm_mon + 1, tm->tm_mday, html_quote_s(name), + html_quote(file_quote(mid)), html_quote(subject))); +} + +InputStream +openNewsStream(ParsedURL *pu) +{ + char *host, *mode, *group, *p; + Str tmp; + int port, status; + + if (pu->file == NULL || *pu->file == '\0') + return NULL; + if (pu->scheme == SCM_NNTP) + host = pu->host; + else + host = NNTP_server; + if (!host || *host == '\0') + return NULL; + if (pu->scheme != SCM_NNTP && (p = strchr(host, ':'))) { + host = allocStr(host, p - host); + port = atoi(p + 1); + } + else + port = pu->port; + if (NNTP_mode && *NNTP_mode) + mode = NNTP_mode; + else + mode = NULL; + if (current_news.host) { + if (!strcmp(current_news.host, host) && + current_news.port == port) { + tmp = Sprintf("MODE %s", mode ? mode : "READER"); + tmp = news_command(&current_news, tmp->ptr, &status); + if (status != 200 && status != 201) + news_close(&current_news); + } + else + news_quit(&current_news); + } + if (!current_news.host) { + current_news.host = allocStr(host, -1); + current_news.port = port; + current_news.mode = mode ? allocStr(mode, -1) : NULL; + if (!news_open(&current_news)) + return NULL; + } + if (pu->scheme == SCM_NNTP) { + /* first char of pu->file is '/' */ + group = file_unquote(Strnew_charp(pu->file + 1)->ptr); + p = strchr(group, '/'); + if (p == NULL) + return NULL; + *p++ = '\0'; + news_command(&current_news, Sprintf("GROUP %s", group)->ptr, &status); + if (status != 211) + return NULL; + news_command(&current_news, Sprintf("ARTICLE %s", p)->ptr, &status); + if (status != 220) + return NULL; + return current_news.rf; + } + else if (pu->scheme == SCM_NEWS) { + tmp = Sprintf("ARTICLE <%s>", url_unquote(pu->file)); + news_command(&current_news, tmp->ptr, &status); + if (status != 220) + return NULL; + return current_news.rf; + } + return NULL; +} + +Str +readNewsgroup(ParsedURL *pu) +{ + Str page, tmp; + URLFile f; + Buffer *buf; + char *group, *qgroup, *p, *q, *s, *t, *n; + int status, flag = 0, i, first, last, start = 0, end = 0; +#ifdef JP_CHARSET + char code = '\0'; +#endif + MySignalHandler(*volatile trap) (SIGNAL_ARG) = NULL; + + if (current_news.host == NULL || !pu->file || *pu->file == '\0') + return NULL; + group = file_unquote(pu->file); + qgroup = html_quote(group); + + if (fmInitialized) { + message(Sprintf("Reading newsgroup %s...", group)->ptr, 0, 0); + refresh(); + } + if (SETJMP(AbortLoading) != 0) { + news_close(&current_news); + Strcat_charp(page, "</table><p>Transfer Interrupted!\n"); + goto news_end; + } + trap = signal(SIGINT, KeyAbort); + if (fmInitialized) + term_cbreak(); + + page = Sprintf("<title>Newsgroup: %s</title>\n<h1>Newsgroup:&nbsp;%s</h1>\n<hr>\n", + qgroup, qgroup); + + qgroup = html_quote(file_quote(group)); /* URL */ + tmp = news_command(&current_news, Sprintf("GROUP %s", group)->ptr, &status); + if (status != 211) + goto news_list; + if (sscanf(tmp->ptr, "%d %d %d %d", &status, &i, &first, &last) != 4) + goto news_list; + if (pu->label) { + start = atoi(pu->label); + if (start > 0) { + if (start < first) + start = first; + end = start + MaxNewsMessage; + } + } + if (start <= 0) { + start = first; + end = last + 1; + if (end - start > MaxNewsMessage) + start = end - MaxNewsMessage; + } + if (start > first) { + i = start - MaxNewsMessage; + if (i < first) + i = first; + Strcat(page, Sprintf("<a href=\"news:%s#%d\">[%d-%d]</a>\n", + qgroup, i, i, start - 1)); + } + + Strcat_charp(page, "<table>\n"); + news_command(&current_news, Sprintf("XOVER %d-%d", start, end - 1)->ptr, + &status); + if (status == 224) { + f.scheme = SCM_NEWS; + while (1) { + tmp = StrISgets(current_news.rf); + if (NEWS_ENDLINE(tmp->ptr)) + break; + if (sscanf(tmp->ptr, "%d", &i) != 1) + continue; + if (!(s = strchr(tmp->ptr, '\t'))) + continue; + s++; + if (!(n = strchr(s, '\t'))) + continue; + *n++ = '\0'; + if (!(t = strchr(n, '\t'))) + continue; + *t++ = '\0'; + if (!(p = strchr(t, '\t'))) + continue; + *p++ = '\0'; + if (*p == '<') + p++; + if (!(q = strchr(p, '>')) && !(q = strchr(p, '\t'))) + continue; + *q = '\0'; + s = convertLine(&f, decodeMIME(s), &code, HEADER_MODE)->ptr; + n = convertLine(&f, decodeMIME(n), &code, HEADER_MODE)->ptr; + add_news_message(page, i, t, n, s, p); + } + } + else { + init_stream(&f, SCM_NEWS, current_news.rf); + buf = newBuffer(INIT_BUFFER_WIDTH); + for (i = start; i < end && i <= last; i++) { + news_command(&current_news, Sprintf("HEAD %d", i)->ptr, &status); + if (status != 221) + continue; + readHeader(&f, buf, FALSE, NULL); + if (!(p = checkHeader(buf, "Message-ID:"))) + continue; + if (*p == '<') + p++; + if (!(q = strchr(p, '>')) && !(q = strchr(p, '\t'))) + *q = '\0'; + if (!(s = checkHeader(buf, "Subject:"))) + continue; + if (!(n = checkHeader(buf, "From:"))) + continue; + if (!(t = checkHeader(buf, "Date:"))) + continue; + add_news_message(page, i, t, n, s, p); + } + } + Strcat_charp(page, "</table>\n"); + + if (end <= last) { + i = end + MaxNewsMessage - 1; + if (i > last) + i = last; + Strcat(page, Sprintf("<a href=\"news:%s#%d\">[%d-%d]</a>\n", + qgroup, end, end, i)); + } + flag = 1; + + news_list: + news_command(&current_news, Sprintf("LIST ACTIVE %s.*", group)->ptr, + &status); + if (status != 215) + goto news_end; + while (1) { + tmp = StrISgets(current_news.rf); + if (NEWS_ENDLINE(tmp->ptr)) + break; + if (flag < 2) { + if (flag == 1) + Strcat_charp(page, "<hr>\n"); + Strcat_charp(page, "<table>\n"); + flag = 2; + } + p = tmp->ptr; + for (q = p; *q && !IS_SPACE(*q); q++) ; + *(q++) = '\0'; + i = 0; + if (sscanf(q, "%d %d", &last, &first) == 2 && last >= first) + i = last - first + 1; + Strcat(page, + Sprintf("<tr><td align=right>%d<td><a href=\"news:%s\">%s</a>\n", + i, html_quote(file_quote(p)), html_quote(p))); + } + if (flag == 2) + Strcat_charp(page, "</table>\n"); + + news_end: + if (fmInitialized) + term_raw(); + signal(SIGINT, trap); + return page; +} + +void +disconnectNews(void) +{ + news_quit(&current_news); +} + +#endif /* USE_NNTP */ diff --git a/proto.h b/proto.h @@ -509,6 +509,11 @@ extern FILE *openFTP(ParsedURL *pu, URLFile *uf); extern Str readFTPDir(ParsedURL *pu); extern void closeFTP(FILE * f); extern int Ftpfclose(FILE * f); +#ifdef USE_NNTP +extern InputStream openNewsStream(ParsedURL *pu); +extern Str readNewsgroup(ParsedURL *pu); +extern void disconnectNews(void); +#endif extern AnchorList *putAnchor(AnchorList *al, char *url, char *target, Anchor **anchor_return, char *referer, char *title, unsigned char key, int line, diff --git a/rc.c b/rc.c @@ -106,6 +106,11 @@ static char *config_file = NULL; #define CMT_NO_PROXY "プロキシから除外するドメイン" #define CMT_NOPROXY_NETADDR "ネットワークアドレスでプロキシ除外のチェック" #define CMT_NO_CACHE "Cache を使わない" +#ifdef USE_NNTP +#define CMT_NNTP_SERVER "News サーバ" +#define CMT_NNTP_MODE "News サーバのモード" +#define CMT_MAX_NEWS "News を一覧表示する時の数" +#endif #define CMT_DNS_ORDER "名前解決の順序" #define CMT_DROOT "/ で表されるディレクトリ(document root)" #define CMT_PDROOT "/~user で表されるディレクトリ" @@ -264,6 +269,11 @@ static char *config_file = NULL; #define CMT_NO_PROXY "Domains to be accessed directly (no proxy)" #define CMT_NOPROXY_NETADDR "Check noproxy by network address" #define CMT_NO_CACHE "Disable cache" +#ifdef USE_NNTP +#define CMT_NNTP_SERVER "News server" +#define CMT_NNTP_MODE "Mode of news server" +#define CMT_MAX_NEWS "Number of news messages" +#endif #define CMT_DNS_ORDER "Order of name resolution" #define CMT_DROOT "Directory corresponding to / (document root)" #define CMT_PDROOT "Directory corresponding to /~user" @@ -783,6 +793,12 @@ struct param_ptr params9[] = { {"dns_order", P_INT, PI_SEL_C, (void *)&DNS_order, CMT_DNS_ORDER, dnsorders}, #endif /* INET6 */ +#ifdef USE_NNTP + {"nntpserver", P_STRING, PI_TEXT, (void *)&NNTP_server, CMT_NNTP_SERVER, + NULL}, + {"nntpmode", P_STRING, PI_TEXT, (void *)&NNTP_mode, CMT_NNTP_MODE, NULL}, + {"max_news", P_INT, PI_TEXT, (void *)&MaxNewsMessage, CMT_MAX_NEWS, NULL}, +#endif {NULL, 0, 0, NULL, NULL, NULL}, }; diff --git a/url.c b/url.c @@ -54,6 +54,7 @@ static int 0, /* exec - not defined? */ 119, /* nntp */ 119, /* news */ + 119, /* news group */ 0, /* mailto - not defined */ #ifdef USE_SSL 443, /* https */ @@ -69,6 +70,7 @@ struct cmdtable schemetable[] = { /* {"exec", SCM_EXEC}, */ {"nntp", SCM_NNTP}, {"news", SCM_NEWS}, + /* {"news", SCM_NEWS_GROUP}, */ #ifndef USE_W3MMAILER {"mailto", SCM_MAILTO}, #endif @@ -969,6 +971,11 @@ parseURL2(char *url, ParsedURL *pu, ParsedURL *current) if (pu->scheme == SCM_MAILTO) return; #endif + if (pu->scheme == SCM_NEWS) { + if (pu->file && !strchr(pu->file, '@')) + pu->scheme = SCM_NEWS_GROUP; + return; + } if (pu->scheme == SCM_LOCAL) pu->file = expandName(pu->file); @@ -989,7 +996,7 @@ parseURL2(char *url, ParsedURL *pu, ParsedURL *current) pu->scheme != SCM_GOPHER && #endif /* USE_GOPHER */ #ifdef USE_NNTP - pu->scheme != SCM_NEWS && + pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP && #endif /* USE_NNTP */ pu->file[0] != '/' #ifdef SUPPORT_DOS_DRIVE_PREFIX @@ -1070,7 +1077,7 @@ parseURL2(char *url, ParsedURL *pu, ParsedURL *current) pu->scheme != SCM_GOPHER && #endif /* USE_GOPHER */ #ifdef USE_NNTP - pu->scheme != SCM_NEWS && + pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP && #endif /* USE_NNTP */ pu->file[0] == '/') { /* @@ -1102,7 +1109,7 @@ _parsedURL2Str(ParsedURL *pu, int pass) Str tmp; static char *scheme_str[] = { "http", "gopher", "ftp", "ftp", "file", "file", "exec", "nntp", "news", - "mailto", + "news", "mailto", #ifdef USE_SSL "https", #endif /* USE_SSL */ @@ -1139,7 +1146,7 @@ _parsedURL2Str(ParsedURL *pu, int pass) } #endif #ifdef USE_NNTP - if (pu->scheme != SCM_NEWS) + if (pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP) #endif /* USE_NNTP */ { Strcat_charp(tmp, "//"); @@ -1161,7 +1168,7 @@ _parsedURL2Str(ParsedURL *pu, int pass) } if ( #ifdef USE_NNTP - pu->scheme != SCM_NEWS && + pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP && #endif /* USE_NNTP */ (pu->file == NULL || (pu->file[0] != '/' #ifdef SUPPORT_DOS_DRIVE_PREFIX @@ -1766,80 +1773,14 @@ openURL(char *url, ParsedURL *pu, ParsedURL *current, case SCM_NNTP: /* nntp://<host>:<port>/<newsgroup-name>/<article-number> */ case SCM_NEWS: - /* news:<newsgroup-name> XXX: not yet */ /* news:<unique>@<full_domain_name> */ - if (pu->scheme == SCM_NNTP) { - p = pu->host; - } - else { - p = getenv("NNTPSERVER"); - } - r = getenv("NNTPMODE"); - if (p == NULL) - return uf; - sock = openSocket(p, "nntp", pu->port); - if (sock < 0) - return uf; - stream = newInputStream(sock); - fw = fdopen(sock, "wb"); - if (stream == NULL || fw == NULL) - return uf; - tmp = StrISgets(stream); - if (tmp->length == 0) - goto nntp_error; - sscanf(tmp->ptr, "%d", &i); - if (i != 200 && i != 201) - goto nntp_error; - if (r && *r != '\0') { - fprintf(fw, "MODE %s\r\n", r); - fflush(fw); - tmp = StrISgets(stream); - if (tmp->length == 0) - goto nntp_error; - sscanf(tmp->ptr, "%d", &i); - if (i != 200 && i != 201) - goto nntp_error; - } - if (pu->scheme == SCM_NNTP) { - char *group; - if (pu->file == NULL || *pu->file == '\0') - goto nntp_error; - /* first char of pu->file is '/' */ - group = url_unquote(Strnew_charp(pu->file + 1)->ptr); - p = strchr(group, '/'); - if (p == NULL) - goto nntp_error; - *p++ = '\0'; - fprintf(fw, "GROUP %s\r\n", group); - fflush(fw); - tmp = StrISgets(stream); - if (tmp->length == 0) { - goto nntp_error; - } - sscanf(tmp->ptr, "%d", &i); - if (i != 211) - goto nntp_error; - fprintf(fw, "ARTICLE %s\r\n", p); - } - else { - if (pu->file == NULL || *pu->file == '\0') - goto nntp_error; - /* pu-file contains '@' => news:<message-id> */ - fprintf(fw, "ARTICLE <%s>\r\n", url_unquote(pu->file)); - } - fflush(fw); - tmp = StrISgets(stream); - if (tmp->length == 0) - goto nntp_error; - sscanf(tmp->ptr, "%d", &i); - if (i != 220) - goto nntp_error; - uf.scheme = SCM_NEWS; /* XXX */ - uf.stream = stream; - return uf; - nntp_error: - ISclose(stream); - fclose(fw); + case SCM_NEWS_GROUP: + /* news:<newsgroup-name> */ + uf.stream = openNewsStream(pu); + if (uf.stream) + uf.scheme = SCM_NEWS; /* XXX */ + else + uf.scheme = pu->scheme; return uf; #endif /* USE_NNTP */ case SCM_UNKNOWN: