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:
M | ChangeLog | | | 36 | ++++++++++++++++++++++++++++++++++++ |
M | XMakefile | | | 4 | ++-- |
M | file.c | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | fm.h | | | 5 | +++++ |
M | html.h | | | 5 | +++-- |
M | main.c | | | 14 | ++++++++++++-- |
A | news.c | | | 438 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | proto.h | | | 5 | +++++ |
M | rc.c | | | 16 | ++++++++++++++++ |
M | url.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 = " ";
+ 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(¤t_news, tmp->ptr, &status);
+ if (status != 200 && status != 201)
+ news_close(¤t_news);
+ }
+ else
+ news_quit(¤t_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(¤t_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(¤t_news, Sprintf("GROUP %s", group)->ptr, &status);
+ if (status != 211)
+ return NULL;
+ news_command(¤t_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(¤t_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(¤t_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: %s</h1>\n<hr>\n",
+ qgroup, qgroup);
+
+ qgroup = html_quote(file_quote(group)); /* URL */
+ tmp = news_command(¤t_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(¤t_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(¤t_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(¤t_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(¤t_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: