*p++ = ich;
*p++ = (char) ich;
PRIVATE int read_article ARGS1(	HTParentAnchor *,	thisanchor){    char line[LINE_LENGTH+1];    char *full_line = NULL;    char *subject = NULL;			/* Subject string	    */    char *from = NULL;				/* From string		    */    char *replyto = NULL;			/* Reply-to string	    */    char *date = NULL;				/* Date string		    */    char *organization = NULL;			/* Organization string	    */    char *references = NULL;			/* Hrefs for other articles */    char *newsgroups = NULL;			/* Newsgroups list	    */    char *followupto = NULL;			/* Followup list	    */    char *href = NULL;    char *p = line;    char *cp;    CONST char *ccp;    BOOL done = NO;    /*    **	Read in the HEADer of the article.    **    **	The header fields are either ignored,    **	or formatted and put into the text.    */    if (!diagnostic && !rawtext) {	while (!done) {	    int ich = NEXT_CHAR;	    *p++ = ich;	    if (ich == EOF) {		if (interrupted_in_htgetcharacter) {		    interrupted_in_htgetcharacter = 0;		    CTRACE(tfp, "HTNews: Interrupted on read, closing socket %d\n",				s);		    NEWS_NETCLOSE(s);		    s = -1;		    return(HT_INTERRUPTED);		}		abort_socket(); 	/* End of file, close socket */		return(HT_LOADED);	/* End of file on response */	    }	    if (((char)ich == LF) || (p == &line[LINE_LENGTH])) {		*--p = '\0';			/* Terminate the string */		CTRACE(tfp, "H %s\n", line);		if (line[0] == '\t' || line[0] == ' ') {		    int i = 0;		    while (line[i]) {			if (line[i] == '\t')			    line[i] = ' ';			i++;		    }		    if (full_line == NULL) {			StrAllocCopy(full_line, line);		    } else {			StrAllocCat(full_line, line);		    }		} else {		    StrAllocCopy(full_line, line);		}		if (full_line[0] == '.') {		    /*		    **	End of article?		    */		    if ((unsigned char)full_line[1] < ' ') {			done = YES;			break;		    }		} else if ((unsigned char)full_line[0] < ' ') {		    break;		/* End of Header? */		} else if (match(full_line, "SUBJECT:")) {		    StrAllocCopy(subject, HTStrip(strchr(full_line,':')+1));		    if (HTCJK == JAPANESE) {			HTmmdecode(subject, subject);			HTrjis(subject, subject);		    }		    if (*subject) {			HTAnchor_setSubject(thisanchor, subject);		    }		} else if (match(full_line, "DATE:")) {		    StrAllocCopy(date, HTStrip(strchr(full_line,':')+1));		} else if (match(full_line, "ORGANIZATION:")) {		    StrAllocCopy(organization,				 HTStrip(strchr(full_line,':')+1));		    if (HTCJK == JAPANESE) {			HTmmdecode(organization, organization);			HTrjis(organization, organization);		    }		} else if (match(full_line, "FROM:")) {		    StrAllocCopy(from, HTStrip(strchr(full_line,':')+1));		    if (HTCJK == JAPANESE) {			HTmmdecode(from, from);			HTrjis(from, from);		    }		} else if (match(full_line, "REPLY-TO:")) {		    StrAllocCopy(replyto, HTStrip(strchr(full_line,':')+1));		    if (HTCJK == JAPANESE) {			HTmmdecode(replyto, replyto);			HTrjis(replyto, replyto);		    }		} else if (match(full_line, "NEWSGROUPS:")) {		    StrAllocCopy(newsgroups, HTStrip(strchr(full_line,':')+1));		} else if (match(full_line, "REFERENCES:")) {		    StrAllocCopy(references, HTStrip(strchr(full_line,':')+1));		} else if (match(full_line, "FOLLOWUP-TO:")) {		    StrAllocCopy(followupto, HTStrip(strchr(full_line,':')+1));		} else if (match(full_line, "MESSAGE-ID:")) {		    char * msgid = HTStrip(full_line+11);		    if (msgid[0] == '<' && msgid[strlen(msgid)-1] == '>') {			msgid[strlen(msgid)-1] = '\0';	/* Chop > */			msgid++; 			/* Chop < */			HTAnchor_setMessageID(thisanchor, msgid);		    }		} /* end if match */		p = line;			/* Restart at beginning */	    } /* if end of line */	} /* Loop over characters */	FREE(full_line);	START(HTML_HEAD);	PUTC('\n');	START(HTML_TITLE);	if (subject && *subject != '\0')	    PUTS(subject);	else	    PUTS("No Subject");	END(HTML_TITLE);	PUTC('\n');	/*	**  Put in the owner as a link rel.	*/	if (from || replyto) {	    char *temp=NULL;	    StrAllocCopy(temp, author_address(replyto ? replyto : from));	    StrAllocCopy(href,"mailto:");	    if (strchr(temp, '%') || strchr(temp, '?')) {		cp = HTEscape(temp, URL_XPALPHAS);		StrAllocCat(href, cp);		FREE(cp);	    } else {		StrAllocCat(href, temp);	    }	    start_link(href, "made");	    PUTC('\n');	    FREE(temp);	}	END(HTML_HEAD);	PUTC('\n');	START(HTML_H1);	if (subject && *subject != '\0')	    PUTS(subject);	else	    PUTS("No Subject");	END(HTML_H1);	PUTC('\n');	if (subject)	    FREE(subject);	START(HTML_DLC);	PUTC('\n');	if (from || replyto) {	    START(HTML_DT);	    START(HTML_B);	    PUTS("From:");	    END(HTML_B);	    PUTC(' ');	    if (from)		PUTS(from);	    else		PUTS(replyto);	    MAYBE_END(HTML_DT);	    PUTC('\n');	    if (!replyto)		StrAllocCopy(replyto, from);	    START(HTML_DT);	    START(HTML_B);	    PUTS("Reply to:");	    END(HTML_B);	    PUTC(' ');	    start_anchor(href);	    if (*replyto != '<')		PUTS(author_name(replyto));	    else		PUTS(author_address(replyto));	    END(HTML_A);	    START(HTML_BR);	    MAYBE_END(HTML_DT);	    PUTC('\n');	    FREE(from);	    FREE(replyto);	}	if (date) {	    START(HTML_DT);	    START(HTML_B);	    PUTS("Date:");	    END(HTML_B);	    PUTC(' ');	    PUTS(date);	    MAYBE_END(HTML_DT);	    PUTC('\n');	    FREE(date);	}	if (organization) {	    START(HTML_DT);	    START(HTML_B);	    PUTS("Organization:");	    END(HTML_B);	    PUTC(' ');	    PUTS(organization);	    MAYBE_END(HTML_DT);	    PUTC('\n');	    FREE(organization);	}	/* sanitize some headers - kw */	if (newsgroups &&	    ((cp = strchr(newsgroups, '/')) ||	     (cp = strchr(newsgroups, '(')))) {	    *cp = '\0';	}	if (newsgroups && !*newsgroups) {	    FREE(newsgroups);	}	if (followupto &&	    ((cp = strchr(followupto, '/')) ||	     (cp = strchr(followupto, '(')))) {	    *cp = '\0';	}	if (followupto && !*followupto) {	    FREE(followupto);	}	if (newsgroups && HTCanPost) {	    START(HTML_DT);	    START(HTML_B);	    PUTS("Newsgroups:");	    END(HTML_B);	    PUTC('\n');	    MAYBE_END(HTML_DT);	    START(HTML_DD);	    write_anchors(newsgroups);	    MAYBE_END(HTML_DD);	    PUTC('\n');	}	if (followupto && !strcasecomp(followupto, "poster")) {	    /*	    **	"Followup-To: poster" has special meaning.	    **  Don't use it to construct a newsreply link. -kw	    */	    START(HTML_DT);	    START(HTML_B);	    PUTS("Followup to:");	    END(HTML_B);	    PUTC(' ');	    if (href) {		start_anchor(href);		PUTS("poster");		END(HTML_A);	    } else {		PUTS("poster");	    }	    MAYBE_END(HTML_DT);	    PUTC('\n');	    FREE(followupto);	}	if (newsgroups && HTCanPost) {	    /*	    **	We have permission to POST to this host,	    **	so add a link for posting followups for	    **	this article. - FM	    */	    if (!strncasecomp(NewsHREF, "snews:", 6))		StrAllocCopy(href,"snewsreply://");	    else		StrAllocCopy(href,"newsreply://");	    StrAllocCat(href, NewsHost);	    StrAllocCat(href, "/");	    StrAllocCat(href, (followupto ? followupto : newsgroups));	    if (*href == 'n' &&		(ccp = HTAnchor_messageID(thisanchor)) && *ccp) {		StrAllocCat(href, ";ref=");		if (strchr(ccp, '<') || strchr(ccp, '&') ||		    strchr(ccp, ' ') || strchr(ccp, ':') ||		    strchr(ccp, '/') || strchr(ccp, '%') ||		    strchr(ccp, ';')) {		    char *cp1 = HTEscape(ccp, URL_XPALPHAS);		    StrAllocCat(href, cp1);		    FREE(cp1);		} else {		    StrAllocCat(href, ccp);		}	    }	    START(HTML_DT);	    START(HTML_B);	    PUTS("Followup to:");	    END(HTML_B);	    PUTC(' ');	    start_anchor(href);	    if (strchr((followupto ? followupto : newsgroups), ',')) {		PUTS("newsgroups");	    } else {		PUTS("newsgroup");	    }	    END(HTML_A);	    MAYBE_END(HTML_DT);	    PUTC('\n');	}	FREE(newsgroups);	FREE(followupto);	if (references) {	    START(HTML_DT);	    START(HTML_B);	    PUTS("References:");	    END(HTML_B);	    MAYBE_END(HTML_DT);	    PUTC('\n');	    START(HTML_DD);	    write_anchors(references);	    MAYBE_END(HTML_DD);	    PUTC('\n');	    FREE(references);	}	END(HTML_DLC);	PUTC('\n');	FREE(href);    }    if (rawtext) {	/*	 *  No tags - kw	 */	;    } else if (diagnostic) {	/*	**  Read in the HEAD and BODY of the Article	**  as XMP formatted text. - FM	*/	START(HTML_XMP);    } else {	/*	**  Read in the BODY of the Article	**  as PRE formatted text. - FM	*/	START(HTML_PRE);    }    PUTC('\n');    p = line;    while (!done) {	int ich = NEXT_CHAR;	*p++ = ich;	if (ich == EOF) {	    if (interrupted_in_htgetcharacter) {		interrupted_in_htgetcharacter = 0;		CTRACE(tfp, "HTNews: Interrupted on read, closing socket %d\n",			    s);		NEWS_NETCLOSE(s);		s = -1;		return(HT_INTERRUPTED);	    }	    abort_socket();	/* End of file, close socket */	    return(HT_LOADED);	/* End of file on response */	}	if (((char)ich == LF) || (p == &line[LINE_LENGTH])) {	    *p++ = '\0';			/* Terminate the string */	    CTRACE(tfp, "B %s", line);	    if (line[0] == '.') {		/*		**  End of article?		*/		if ((unsigned char)line[1] < ' ') {		    done = YES;		    break;		} else {			/* Line starts with dot */		    if (rawtext)			RAW_PUTS(&line[1]);		    else			PUTS(&line[1]); /* Ignore first dot */		}	    } else {		if (rawtext) {		    RAW_PUTS(line);		} else if (diagnostic || !scan_for_buried_news_references) {		    /*		    **	All lines are passed as unmodified source. - FM		    */		    PUTS(line);		} else {		    /*		    **	Normal lines are scanned for buried references		    **	to other articles.  Unfortunately, it could pick		    **	up mail addresses as well!  It also can corrupt		    **	uuencoded messages!  So we don't do this when		    **	fetching articles as WWW_SOURCE or when downloading		    **	(diagnostic is TRUE) or if the client has set		    **	scan_for_buried_news_references to FALSE.		    **	Otherwise, we convert all "<...@...>" strings		    **	preceded by "rticle " to "news:...@..." links,		    **	and any strings that look like URLs to links. - FM		    */		    char *l = line;		    char *p2;		    while ((p2 = strstr(l, "rticle <")) != NULL) {			char *q  = strchr(p2,'>');			char *at = strchr(p2, '@');			if (q && at && at<q) {			    char c = q[1];			    q[1] = 0;		/* chop up */			    p2 += 7;			    *p2 = 0;			    while (*l) {				if (strncmp(l, "news:", 5) &&				    strncmp(l, "snews://", 8) &&				    strncmp(l, "nntp://", 7) &&				    strncmp(l, "snewspost:", 10) &&				    strncmp(l, "snewsreply:", 11) &&				    strncmp(l, "newspost:", 9) &&				    strncmp(l, "newsreply:", 10) &&				    strncmp(l, "ftp://", 6) &&				    strncmp(l, "file:/", 6) &&				    strncmp(l, "finger://", 9) &&				    strncmp(l, "http://", 7) &&				    strncmp(l, "https://", 8) &&				    strncmp(l, "wais://", 7) &&				    strncmp(l, "mailto:", 7) &&				    strncmp(l, "cso://", 6) &&				    strncmp(l, "gopher://", 9))				    PUTC (*l++);				else {				    StrAllocCopy(href, l);				    start_anchor(strtok(href, " \r\n\t,>)\""));				    while (*l && !strchr(" \r\n\t,>)\"", *l))					PUTC(*l++);				    END(HTML_A);				    FREE(href);				}			    }			    *p2 = '<';		/* again */			    *q = 0;			    start_anchor(p2+1);			    *q = '>';		/* again */			    PUTS(p2);			    END(HTML_A);			    q[1] = c;		/* again */			    l=q+1;			} else {			    break;		/* line has unmatched <> */			}		    }		    while (*l) {		/* Last bit of the line */			if (strncmp(l, "news:", 5) &&			    strncmp(l, "snews://", 8) &&			    strncmp(l, "nntp://", 7) &&			    strncmp(l, "snewspost:", 10) &&			    strncmp(l, "snewsreply:", 11) &&			    strncmp(l, "newspost:", 9) &&			    strncmp(l, "newsreply:", 10) &&			    strncmp(l, "ftp://", 6) &&			    strncmp(l, "file:/", 6) &&			    strncmp(l, "finger://", 9) &&			    strncmp(l, "http://", 7) &&			    strncmp(l, "https://", 8) &&			    strncmp(l, "wais://", 7) &&			    strncmp(l, "mailto:", 7) &&			    strncmp(l, "cso://", 6) &&			    strncmp(l, "gopher://", 9))			    PUTC (*l++);			else {			    StrAllocCopy(href, l);			    start_anchor(strtok(href, " \r\n\t,>)\""));			    while (*l && !strchr(" \r\n\t,>)\"", *l))				PUTC(*l++);			    END(HTML_A);			    FREE(href);			}		    }		} /* if diagnostic or not scan_for_buried_news_references */	    } /* if not dot */	    p = line;				/* Restart at beginning */	} /* if end of line */    } /* Loop over characters */    if (rawtext)	return(HT_LOADED);    if (diagnostic)	END(HTML_XMP);    else	END(HTML_PRE);    PUTC('\n');    return(HT_LOADED);}