?? htnews.c
字號:
/* NEWS ACCESS HTNews.c** ===========**** History:** 26 Sep 90 Written TBL** 29 Nov 91 Downgraded to C, for portable implementation.** 16 Feb 94 AL Added Lou Montulli's Lynx & LIST NEWSGROUPS diffs.** 2 May 94 AL Added HTUnEscape() to HTLoadNews(), and** fixed a possible security hole when the URL contains** a newline, that could cause multiple commands to be** sent to an NNTP server.** 8 Jul 94 FM Insulate free() from _free structure element.** 30 Aug 95 FTLO Added POST functionality and updated state machine** 30 Aug 95 HFN Cleaned up a whole lot and made a state machine*//* Library Include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "WWWStream.h"#include "WWWTrans.h"#include "HTReqMan.h" /* @@@ */#include "HTNewsRq.h"#include "HTNewsLs.h"#include "HTNews.h" /* Implements *//* Macros and other defines */#ifndef NEWS_LIST_FILE#define NEWS_LIST_FILE ".www_news" /* Name of news list file */#endif#define MAX_NEWS_ARTICLES 0 /* No default max number of articles */#define PUTBLOCK(b, l) (*me->target->isa->put_block) (me->target, b, l)#define ABORT_TARGET (*me->target->isa->abort) (me->target, e)/* Local context structure used in the HTNet object */typedef enum _HTNewsState { NEWS_ERROR = -3, NEWS_SUCCESS = -2, NEWS_NO_DATA = -1, NEWS_BEGIN = 0, NEWS_SEEK_CACHE, NEWS_NEED_CONNECTION, NEWS_NEED_GREETING, NEWS_NEED_SWITCH, NEWS_NEED_ARTICLE,#if HT_LISTGROUP NEWS_NEED_LGRP,#endif NEWS_NEED_LIST, NEWS_NEED_GROUP, NEWS_NEED_XOVER, NEWS_NEED_HEAD, NEWS_NEED_POST, NEWS_NEED_BODY} HTNewsState;typedef struct _news_info { HTChunk * cmd; int repcode; char * reply; HTNewsState state; /* State of the connection */ HTFormat format; char * name; /* Name of article or newsgroup */ BOOL sent; /* Read or write command */ int first; /* First article in the group list */ int last; /* Last article in the group list */ int total; /* Estimated number of articles */ int current; /* To count # of HEADS sent */ HTNet * net;} news_info;/* This version of a stream is used for NEWS LIST conversion to HTML */struct _HTStream { const HTStreamClass * isa; HTStream * target; HTRequest * request; news_info * news; HTEOLState EOLstate; BOOL semi_trans; BOOL junk; char buffer[MAX_NEWS_LINE+1]; int buflen; HTHost * host;};struct _HTInputStream { const HTInputStreamClass * isa;};PRIVATE int MaxArt = MAX_NEWS_ARTICLES;/* ------------------------------------------------------------------------- *//* NEWS INPUT STREAM *//* ------------------------------------------------------------------------- *//* ScanResponse** ------------** Analyzes the response from the NNTP server.** We only expect one line response codes.** Returns HT_LOADED if OK, HT_ERROR if error*/PRIVATE int ScanResponse (HTStream * me){ news_info *news = me->news; *(me->buffer+me->buflen) = '\0'; if (isdigit((int) *(me->buffer))) sscanf(me->buffer, "%d", &news->repcode); me->buflen = 0; news->reply = me->buffer+4; HTTRACE(PROT_TRACE, "News Rx..... `%s\'\n" _ news->reply); /* If 2xx code and we expect data then go into semi-transparent mode */ if (me->news->format && news->repcode/100 == 2) { HTRequest *req = me->request; me->target = HTStreamStack(me->news->format, req->output_format, req->output_stream, req, NO); me->semi_trans = YES; if (!me->target) return HT_ERROR; } else if (news->repcode/100 == 4) { HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND, news->reply, strlen(news->reply), "ScanResponse"); } return HT_LOADED;}/*** Searches for NNTP header line until buffer fills up or a CRLF or LF** is found*/PRIVATE int HTNewsStatus_put_block (HTStream * me, const char * b, int l){ int status; HTHost_setConsumed(me->host, l); while (!me->semi_trans && l-- > 0) { if (me->EOLstate == EOL_FCR) { if (*b == LF) { if (me->junk) me->junk = NO; me->EOLstate = EOL_BEGIN; if ((status = ScanResponse(me)) != HT_LOADED) return status; } } else if (*b == CR) { me->EOLstate = EOL_FCR; } else if (*b == LF) { if (me->junk) me->junk = NO; me->EOLstate = EOL_BEGIN; if ((status = ScanResponse(me)) != HT_LOADED) return status; } else { *(me->buffer+me->buflen++) = *b; if (me->buflen >= MAX_NEWS_LINE) { HTTRACE(PROT_TRACE, "News Status. Line too long - chopped\n"); me->junk = YES; if ((status = ScanResponse(me)) != HT_LOADED) return status; } } b++; } /* ** Now see if we have parts of the body to put down the stream pipe. ** At this point we are looking for CRLF.CRLF. We are guaranteed a stream */ if (l > 0) { int rest = l; const char *ptr = b; while (rest-- > 0) { if (*ptr == CR) { me->EOLstate = me->EOLstate==EOL_DOT ? EOL_SCR : EOL_FCR; } else if (*ptr == '.') { me->EOLstate = me->EOLstate==EOL_FLF ? EOL_DOT : EOL_BEGIN; } else if (*ptr == LF) { me->EOLstate = me->EOLstate>EOL_DOT ? EOL_SLF : EOL_FLF; } else me->EOLstate = EOL_BEGIN; ptr++; } if (me->EOLstate == EOL_SLF) { int status = PUTBLOCK(b, l-5); return status != HT_OK ? status : HT_LOADED; } else { int status = PUTBLOCK(b, l); return status; } } return HT_LOADED;}PRIVATE int HTNewsStatus_put_character (HTStream * me, char ch){ return HTNewsStatus_put_block(me, &ch, 1);}PRIVATE int HTNewsStatus_put_string (HTStream * me, const char * str){ return HTNewsStatus_put_block(me, str, (int) strlen(str));}PRIVATE int HTNewsStatus_flush (HTStream * me){ return me->target ? (*me->target->isa->flush)(me->target) : HT_OK;}PRIVATE int HTNewsStatus_free (HTStream * me){ int status = HT_OK; if (me->target) { if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; } HT_FREE(me); return status;}PRIVATE int HTNewsStatus_abort (HTStream * me, HTList * e){ if (me->target) ABORT_TARGET; HT_FREE(me); HTTRACE(PROT_TRACE, "NewsStatus.. ABORTING...\n"); return HT_ERROR;}PRIVATE const HTStreamClass HTNewsStatusClass ={ "NewsStatus", HTNewsStatus_flush, HTNewsStatus_free, HTNewsStatus_abort, HTNewsStatus_put_character, HTNewsStatus_put_string, HTNewsStatus_put_block};PRIVATE HTStream * HTNewsStatus_new (HTRequest * request, news_info * news, HTHost * host){ HTStream *me; if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL) HT_OUTOFMEM("HTNewsStatus_new"); me->isa = &HTNewsStatusClass; me->request = request; me->news = news; me->EOLstate = EOL_BEGIN; me->host = host; return me;}/* ------------------------------------------------------------------------- *//* PROTOCOL FUNCTIONS *//* ------------------------------------------------------------------------- *//*** Set the max number of articles at the same time.** Default is MAX_NEWS_ARTICLES*/PUBLIC BOOL HTNews_setMaxArticles (int new_max){ if (new_max >= 0) { MaxArt = new_max; return YES; } return NO;}/*** Get current max number of articles at the same time.*/PUBLIC int HTNews_maxArticles (void){ return MaxArt;}/* HTNewsCleanup** -------------** This function closes the connection and frees memory.** Returns YES on OK, else NO*/PRIVATE int HTNewsCleanup (HTRequest * req, int status){ HTNet * net = HTRequest_net(req); news_info *news = (news_info *) HTNet_context(net); HTStream * input = HTRequest_inputStream(req); /* Free stream with data TO network */ if (!HTRequest_isDestination(req)) HTRequest_removeDestination(req); else if (input) { if (status == HT_INTERRUPTED) (*input->isa->abort)(input, NULL); else (*input->isa->_free)(input); HTRequest_setInputStream(req, NULL); } /* Remove the request object and our own context structure for nntp */ HTNet_delete(net, status); if (news) { HT_FREE(news->name); HTChunk_delete(news->cmd); HT_FREE(news); } return YES;}PRIVATE int SendCommand (HTRequest *request, news_info *news, char *token, char *pars){ HTStream * input = HTRequest_inputStream(request); int len = strlen(token) + (pars ? strlen(pars)+1:0) + 2; HTChunk_setSize(news->cmd, len); if (pars && *pars) sprintf(HTChunk_data(news->cmd), "%s %s%c%c", token, pars, CR, LF); else sprintf(HTChunk_data(news->cmd), "%s%c%c", token, CR, LF); HTTRACE(PROT_TRACE, "News Tx..... %s" _ HTChunk_data(news->cmd)); return (*input->isa->put_block)(input, HTChunk_data(news->cmd), len);}/* Load data object from NNTP Server HTLoadNews** =================================**** Given a hypertext addres, this routine loads a document**** On Entry,** request The request structure**** returns HT_ERROR Error has occured or interrupted** HT_WOULD_BLOCK if operation would have blocked** HT_LOADED if 200 OK** HT_NO_DATA if No Response** HT_RETRY if Service Unavail.*/PRIVATE int NewsEvent (SOCKET soc, void * pVoid, HTEventType type);PUBLIC int HTLoadNews (SOCKET soc, HTRequest * request){ news_info *news; HTParentAnchor *anchor = HTRequest_anchor(request); HTNet * net = HTRequest_net(request); char * url = HTAnchor_physical(anchor); HTTRACE(PROT_TRACE, "NNTP........ Looking for `%s\'\n" _ url); if ((news = (news_info *) HT_CALLOC(1, sizeof(news_info))) == NULL) HT_OUTOFMEM("HTLoadNews"); news->cmd = HTChunk_new(128); news->state = NEWS_BEGIN; news->net = net; HTNet_setContext(net, news); HTNet_setEventCallback(net, NewsEvent); HTNet_setEventParam(net, news); /* callbacks get http* */ return NewsEvent(soc, news, HTEvent_BEGIN); /* get it started - ops is ignored */}PRIVATE int NewsEvent (SOCKET soc, void * pVoid, HTEventType type){ news_info *news = (news_info *)pVoid; int status = HT_ERROR; HTNet * net = news->net; HTRequest * request = HTNet_request(net); HTParentAnchor * anchor = HTRequest_anchor(request); char * url = HTAnchor_physical(anchor); HTHost * host = HTNet_host(net); /* ** Initiate a new nntp structure and bind to request structure ** This is actually state NNTP_BEGIN, but it can't be in the state ** machine as we need the structure first. */ if (type == HTEvent_CLOSE) { /* Interrupted */ HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED, NULL, 0, "HTLoadHTTP"); HTNewsCleanup(request, HT_INTERRUPTED); return HT_OK; } else news = (news_info *) HTNet_context(net); /* Get existing copy */ /* Now jump into the machine. We know the state from the previous run */ while (1) { switch (news->state) { case NEWS_BEGIN: news->state = (!strchr(url, '@') && strchr(url, '*')) ? NEWS_SEEK_CACHE : NEWS_NEED_CONNECTION; break; case NEWS_SEEK_CACHE:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -