[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>
This commit is contained in:
@@ -1,3 +1,39 @@
|
||||
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
|
||||
@@ -6103,4 +6139,4 @@ a * [w3m-dev 03276] compile error on EWS4800
|
||||
* release-0-2-1
|
||||
* import w3m-0.2.1
|
||||
|
||||
$Id: ChangeLog,v 1.651 2002/12/27 15:53:03 ukai Exp $
|
||||
$Id: ChangeLog,v 1.652 2002/12/27 16:07:44 ukai Exp $
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# $Id: XMakefile,v 1.33 2002/11/13 15:53:45 ukai Exp $
|
||||
# $Id: XMakefile,v 1.34 2002/12/27 16:07:44 ukai Exp $
|
||||
SRCS=main.c file.c buffer.c display.c etc.c search.c linein.c table.c local.c \
|
||||
form.c map.c frame.c rc.c menu.c mailcap.c image.c\
|
||||
func.c cookie.c history.c backend.c $(KEYBIND_SRC)
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: file.c,v 1.171 2002/12/26 15:25:04 ukai Exp $ */
|
||||
/* $Id: file.c,v 1.172 2002/12/27 16:07:44 ukai Exp $ */
|
||||
#include "fm.h"
|
||||
#include <sys/types.h>
|
||||
#include "myctype.h"
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: fm.h,v 1.99 2002/12/18 16:42:31 ukai Exp $ */
|
||||
/* $Id: fm.h,v 1.100 2002/12/27 16:07:44 ukai Exp $ */
|
||||
/*
|
||||
* w3m: WWW wo Miru utility
|
||||
*
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: html.h,v 1.16 2002/12/14 15:18:38 ukai Exp $ */
|
||||
/* $Id: html.h,v 1.17 2002/12/27 16:07:44 ukai Exp $ */
|
||||
#ifndef _HTML_H
|
||||
#define _HTML_H
|
||||
#ifdef USE_SSL
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: main.c,v 1.182 2002/12/27 15:50:33 ukai Exp $ */
|
||||
/* $Id: main.c,v 1.183 2002/12/27 16:07:44 ukai Exp $ */
|
||||
#define MAINPROGRAM
|
||||
#include "fm.h"
|
||||
#include <signal.h>
|
||||
@@ -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);
|
||||
@@ -5449,6 +5456,9 @@ w3m_exit(int i)
|
||||
deleteFiles();
|
||||
#ifdef USE_SSL
|
||||
free_ssl_ctx();
|
||||
#endif
|
||||
#ifdef USE_NNTP
|
||||
disconnectNews();
|
||||
#endif
|
||||
exit(i);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/* $Id: news.c,v 1.1 2002/12/27 16:07:44 ukai Exp $ */
|
||||
#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 */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: proto.h,v 1.74 2002/12/24 17:28:49 ukai Exp $ */
|
||||
/* $Id: proto.h,v 1.75 2002/12/27 16:07:44 ukai Exp $ */
|
||||
/*
|
||||
* This file was automatically generated by version 1.7 of cextract.
|
||||
* Manual editing not recommended.
|
||||
@@ -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,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: rc.c,v 1.73 2002/12/24 17:20:48 ukai Exp $ */
|
||||
/* $Id: rc.c,v 1.74 2002/12/27 16:07:44 ukai Exp $ */
|
||||
/*
|
||||
* Initialization file etc.
|
||||
*/
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: url.c,v 1.60 2002/12/14 16:09:51 ukai Exp $ */
|
||||
/* $Id: url.c,v 1.61 2002/12/27 16:07:45 ukai Exp $ */
|
||||
#include "fm.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user