1 /* $Id: news.c,v 1.17 2003/10/05 18:52:51 ukai Exp $ */
12 #define NEWS_ENDLINE(p) \
13 ((*(p) == '.' && ((p)[1] == '\n' || (p)[1] == '\r' || (p)[1] == '\0')) || \
14 *(p) == '\n' || *(p) == '\r' || *(p) == '\0')
16 typedef struct _News {
24 static News current_news = { NULL, 0, NULL, NULL, NULL };
26 static JMP_BUF AbortLoading;
28 static MySignalHandler
31 LONGJMP(AbortLoading, 1);
36 news_command(News * news, char *cmd, char *arg, int *status)
44 tmp = Sprintf("%s %s\r\n", cmd, arg);
46 tmp = Sprintf("%s\r\n", cmd);
47 fwrite(tmp->ptr, sizeof(char), tmp->length, news->wf);
53 tmp = StrISgets(news->rf);
55 sscanf(tmp->ptr, "%d", status);
60 news_close(News * news)
65 IStype(news->rf) &= ~IST_UNCLOSE;
77 news_open(News * news)
81 sock = openSocket(news->host, "nntp", news->port);
84 news->rf = newInputStream(sock);
85 news->wf = fdopen(dup(sock), "wb");
86 if (!news->rf || !news->wf)
88 IStype(news->rf) |= IST_UNCLOSE;
89 news_command(news, NULL, NULL, &status);
90 if (status != 200 && status != 201)
93 news_command(news, "MODE", news->mode, &status);
94 if (status != 200 && status != 201)
104 news_quit(News * news)
106 news_command(news, "QUIT", NULL, NULL);
111 name_from_address(char *str, int n)
116 s = allocStr(str, -1);
118 if (*s == '<' && (p = strchr(s, '>'))) {
121 if (*p == '\0') /* <address> */
123 else /* <address> name ? */
126 else if ((p = strchr(s, '<'))) /* name <address> */
128 else if ((p = strchr(s, '('))) /* address (name) */
130 if (*s == '"' && (p = strchr(s + 1, '"'))) { /* "name" */
134 else if (*s == '(' && (p = strchr(s + 1, ')'))) { /* (name) */
138 for (p = s, l = 0; *p; p += get_mclen(p)) {
155 html_quote_s(char *str)
161 for (p = str; *p; p++) {
169 q = html_quote_char(*p);
174 tmp = Strnew_charp_n(str, (int)(p - str));
175 Strcat_charp(tmp, q);
179 Strcat_char(tmp, *p);
188 add_news_message(Str str, int index, char *date, char *name, char *subject,
189 char *mid, char *scheme, char *group)
194 name = name_from_address(name, 16);
198 Sprintf("<tr valign=top><td>%d<td nowrap>(%02d/%02d)<td nowrap>%s",
199 index, tm->tm_mon + 1, tm->tm_mday, html_quote_s(name)));
201 Strcat(str, Sprintf("<td><a href=\"%s%s/%d\">%s</a>\n", scheme, group,
202 index, html_quote(subject)));
204 Strcat(str, Sprintf("<td><a href=\"%s%s\">%s</a>\n", scheme,
205 html_quote(file_quote(mid)), html_quote(subject)));
211 * nntp://<host>:<port>/<newsgroup-name>/<article-number>
215 * nntp://<host>:<port>/<newsgroup-name>/<message-id>
216 * nntp://<host>:<port>/<message-id>
217 * news:<newsgroup-name>/<article-number>
218 * news:<newsgroup-name>/<message-id>
222 * news:<newsgroup-name>
225 * nntp://<host>:<port>/<newsgroup-name>
226 * nntp://<host>:<port>/<newsgroup-name>/<start-number>-<end-number>
227 * news:<newsgroup-name>/<start-number>-<end-number>
229 * <message-id> = <unique>@<full_domain_name>
233 openNewsStream(ParsedURL *pu)
235 char *host, *mode, *group, *p;
239 if (pu->file == NULL || *pu->file == '\0')
241 if (pu->scheme == SCM_NNTP || pu->scheme == SCM_NNTP_GROUP)
245 if (!host || *host == '\0') {
246 if (current_news.host)
247 news_quit(¤t_news);
250 if (pu->scheme != SCM_NNTP && pu->scheme != SCM_NNTP_GROUP &&
251 (p = strchr(host, ':'))) {
252 host = allocStr(host, p - host);
257 if (NNTP_mode && *NNTP_mode)
261 if (current_news.host) {
262 if (!strcmp(current_news.host, host) && current_news.port == port) {
263 tmp = news_command(¤t_news, "MODE", mode ? mode : "READER",
265 if (status != 200 && status != 201)
266 news_close(¤t_news);
269 news_quit(¤t_news);
271 if (!current_news.host) {
272 current_news.host = allocStr(host, -1);
273 current_news.port = port;
274 current_news.mode = mode ? allocStr(mode, -1) : NULL;
275 if (!news_open(¤t_news))
278 if (pu->scheme == SCM_NNTP || pu->scheme == SCM_NEWS) {
280 group = file_unquote(allocStr(pu->file, -1));
281 p = strchr(group, '/');
282 if (p == NULL) { /* <message-id> */
283 if (!strchr(group, '@'))
287 else { /* <newsgroup>/<message-id or article-number> */
289 news_command(¤t_news, "GROUP", group, &status);
293 if (strchr(p, '@')) /* <message-id> */
294 news_command(¤t_news, "ARTICLE", Sprintf("<%s>", p)->ptr,
296 else /* <article-number> */
297 news_command(¤t_news, "ARTICLE", p, &status);
300 return current_news.rf;
308 loadNewsgroup(ParsedURL *pu, wc_ces * charset)
311 loadNewsgroup0(ParsedURL *pu)
318 char *qgroup, *p, *q, *s, *t, *n;
319 char *volatile scheme, *volatile group, *volatile list;
320 int status, i, first, last;
321 volatile int flag = 0, start = 0, end = 0;
322 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
324 wc_ces doc_charset = DocumentCharset, mime_charset;
326 *charset = WC_CES_US_ASCII;
328 if (current_news.host == NULL || !pu->file || *pu->file == '\0')
330 group = allocStr(pu->file, -1);
331 if (pu->scheme == SCM_NNTP_GROUP)
335 if ((list = strchr(group, '/'))) {
336 /* <newsgroup>/<start-number>-<end-number> */
340 message(Sprintf("Reading newsgroup %s...", group)->ptr, 0, 0);
343 qgroup = html_quote(group);
344 group = file_unquote(group);
345 page = Strnew_m_charp("<html>\n<head>\n<base href=\"",
346 parsedURL2Str(pu)->ptr, "\">\n<title>Newsgroup: ",
347 qgroup, "</title>\n</head>\n<body>\n<h1>Newsgroup: ",
348 qgroup, "</h1>\n<hr>\n", NULL);
350 if (SETJMP(AbortLoading) != 0) {
351 news_close(¤t_news);
352 Strcat_charp(page, "</table>\n<p>Transfer Interrupted!\n");
357 tmp = news_command(¤t_news, "GROUP", group, &status);
360 if (sscanf(tmp->ptr, "%d %d %d %d", &status, &i, &first, &last) != 4)
363 if ((p = strchr(list, '-'))) {
372 end = start + MaxNewsMessage - 1;
378 if (end - start > MaxNewsMessage - 1)
379 start = end - MaxNewsMessage + 1;
381 page = Sprintf("<html>\n<head>\n<base href=\"%s\">\n\
382 <title>Newsgroup: %s %d-%d</title>\n\
383 </head>\n<body>\n<h1>Newsgroup: %s %d-%d</h1>\n<hr>\n", parsedURL2Str(pu)->ptr, qgroup, start, end, qgroup, start, end);
385 i = start - MaxNewsMessage;
388 Strcat(page, Sprintf("<a href=\"%s%s/%d-%d\">[%d-%d]</a>\n", scheme,
389 qgroup, i, start - 1, i, start - 1));
392 Strcat_charp(page, "<table>\n");
393 news_command(¤t_news, "XOVER", Sprintf("%d-%d", start, end)->ptr,
398 tmp = StrISgets(current_news.rf);
399 if (NEWS_ENDLINE(tmp->ptr))
401 if (sscanf(tmp->ptr, "%d", &i) != 1)
403 if (!(s = strchr(tmp->ptr, '\t')))
406 if (!(n = strchr(s, '\t')))
409 if (!(t = strchr(n, '\t')))
412 if (!(p = strchr(t, '\t')))
417 if (!(q = strchr(p, '>')) && !(q = strchr(p, '\t')))
420 tmp = decodeMIME(Strnew_charp(s), &mime_charset);
421 s = convertLine(&f, tmp, HEADER_MODE,
422 mime_charset ? &mime_charset : charset,
423 mime_charset ? mime_charset : doc_charset)->ptr;
424 tmp = decodeMIME(Strnew_charp(n), &mime_charset);
425 n = convertLine(&f, tmp, HEADER_MODE,
426 mime_charset ? &mime_charset : charset,
427 mime_charset ? mime_charset : doc_charset)->ptr;
428 add_news_message(page, i, t, n, s, p, scheme,
429 pu->scheme == SCM_NNTP_GROUP ? qgroup : NULL);
433 init_stream(&f, SCM_NEWS, current_news.rf);
434 buf = newBuffer(INIT_BUFFER_WIDTH);
435 for (i = start; i <= end && i <= last; i++) {
436 news_command(¤t_news, "HEAD", Sprintf("%d", i)->ptr,
440 readHeader(&f, buf, FALSE, NULL);
441 if (!(p = checkHeader(buf, "Message-ID:")))
445 if (!(q = strchr(p, '>')) && !(q = strchr(p, '\t')))
447 if (!(s = checkHeader(buf, "Subject:")))
449 if (!(n = checkHeader(buf, "From:")))
451 if (!(t = checkHeader(buf, "Date:")))
453 add_news_message(page, i, t, n, s, p, scheme,
454 pu->scheme == SCM_NNTP_GROUP ? qgroup : NULL);
457 Strcat_charp(page, "</table>\n");
460 i = end + MaxNewsMessage;
463 Strcat(page, Sprintf("<a href=\"%s%s/%d-%d\">[%d-%d]</a>\n", scheme,
464 qgroup, end + 1, i, end + 1, i));
469 tmp = Sprintf("ACTIVE %s", group);
470 if (!strchr(group, '*'))
471 Strcat_charp(tmp, ".*");
472 news_command(¤t_news, "LIST", tmp->ptr, &status);
476 tmp = StrISgets(current_news.rf);
477 if (NEWS_ENDLINE(tmp->ptr))
481 Strcat_charp(page, "<hr>\n");
482 Strcat_charp(page, "<table>\n");
486 for (q = p; *q && !IS_SPACE(*q); q++) ;
488 if (sscanf(q, "%d %d", &last, &first) == 2 && last >= first)
489 i = last - first + 1;
494 ("<tr><td align=right>%d<td><a href=\"%s%s\">%s</a>\n", i,
495 scheme, html_quote(file_quote(p)), html_quote(p)));
498 Strcat_charp(page, "</table>\n");
501 Strcat_charp(page, "</body>\n</html>\n");
509 news_close(¤t_news);
515 news_quit(¤t_news);
518 #endif /* USE_NNTP */