📄 htnews.c
字号:
/* NEWS ACCESS HTNews.c** ===========**** History:** 26 Sep 90 Written TBL** 29 Nov 91 Downgraded to C, for portable implementation.*/#include <HTUtils.h> /* Coding convention macros */#ifndef DISABLE_NEWS/* Implements:*/#include <HTNews.h>#include <HTCJK.h>#include <HTMIME.h>#include <HTFont.h>#include <HTFormat.h>#include <HTTCP.h>#include <LYUtils.h>#include <LYStrings.h>#define NEWS_PORT 119 /* See rfc977 */#define SNEWS_PORT 563 /* See Lou Montulli */#define APPEND /* Use append methods */PUBLIC int HTNewsChunkSize = 30;/* Number of articles for quick display */PUBLIC int HTNewsMaxChunk = 40; /* Largest number of articles in one window */#ifndef DEFAULT_NEWS_HOST#define DEFAULT_NEWS_HOST "news"#endif /* DEFAULT_NEWS_HOST */#ifndef SERVER_FILE#define SERVER_FILE "/usr/local/lib/rn/server"#endif /* SERVER_FILE */#ifdef USE_SSLextern SSL_CTX * ssl_ctx;PRIVATE SSL * Handle = NULL;PRIVATE int channel_s = 1;#define NEWS_NETWRITE(sock, buff, size) \ (Handle ? SSL_write(Handle, buff, size) : NETWRITE(sock, buff, size))#define NEWS_NETCLOSE(sock) \ { (void)NETCLOSE(sock); if (Handle) SSL_free(Handle); Handle = NULL; }PRIVATE char HTNewsGetCharacter NOPARAMS;#define NEXT_CHAR HTNewsGetCharacter()#else#define NEWS_NETWRITE NETWRITE#define NEWS_NETCLOSE NETCLOSE#define NEXT_CHAR HTGetCharacter()#endif /* USE_SSL */#include <HTML.h>#include <HTAccess.h>#include <HTParse.h>#include <HTFormat.h>#include <HTAlert.h>#include <LYNews.h>#include <LYGlobalDefs.h>#include <LYLeaks.h>#define SnipIn(d,fmt,len,s) sprintf(d, fmt, (int)sizeof(d)-len, s)#define SnipIn2(d,fmt,tag,len,s) sprintf(d, fmt, tag, (int)sizeof(d)-len, s)struct _HTStructured { CONST HTStructuredClass * isa; /* ... */};struct _HTStream{ HTStreamClass * isa;};#define LINE_LENGTH 512 /* Maximum length of line of ARTICLE etc */#define GROUP_NAME_LENGTH 256 /* Maximum length of group name *//*** Module-wide variables.*/PUBLIC char * HTNewsHost = NULL; /* Default host */PRIVATE char * NewsHost = NULL; /* Current host */PRIVATE char * NewsHREF = NULL; /* Current HREF prefix */PRIVATE int s; /* Socket for NewsHost */PRIVATE int HTCanPost = FALSE; /* Current POST permission */PRIVATE char response_text[LINE_LENGTH+1]; /* Last response *//* PRIVATE HText * HT; */ /* the new hypertext */PRIVATE HTStructured * target; /* The output sink */PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */PRIVATE HTStream * rawtarget = NULL; /* The output sink for rawtext */PRIVATE HTStreamClass rawtargetClass; /* Copy of fn addresses */PRIVATE HTParentAnchor *node_anchor; /* Its anchor */PRIVATE int diagnostic; /* level: 0=none 2=source */PRIVATE BOOL rawtext = NO; /* Flag: HEAD or -mime_headers */PRIVATE HTList *NNTP_AuthInfo = NULL; /* AUTHINFO database */PRIVATE char *name = NULL;PRIVATE char *address = NULL;PRIVATE char *dbuf = NULL; /* dynamic buffer for long messages etc. */#define PUTC(c) (*targetClass.put_character)(target, c)#define PUTS(s) (*targetClass.put_string)(target, s)#define RAW_PUTS(s) (*rawtargetClass.put_string)(rawtarget, s)#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0)#define END(e) (*targetClass.end_element)(target, e, 0)#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ (*targetClass.end_element)(target, e, 0)#define FREE_TARGET if (rawtext) (*rawtargetClass._free)(rawtarget); \ else (*targetClass._free)(target)#define ABORT_TARGET if (rawtext) (*rawtargetClass._abort)(rawtarget, NULL); \ else (*targetClass._abort)(target, NULL)typedef struct _NNTPAuth { char * host; char * user; char * pass;} NNTPAuth;#ifdef LY_FIND_LEAKSPRIVATE void free_news_globals NOARGS{ if (s >= 0) { NEWS_NETCLOSE(s); s = -1; } FREE(HTNewsHost); FREE(NewsHost); FREE(NewsHREF); FREE(name); FREE(address); FREE(dbuf);}#endif /* LY_FIND_LEAKS */PRIVATE void free_NNTP_AuthInfo NOARGS{ HTList *cur = NNTP_AuthInfo; NNTPAuth *auth = NULL; if (!cur) return; while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { FREE(auth->host); FREE(auth->user); FREE(auth->pass); FREE(auth); } HTList_delete(NNTP_AuthInfo); NNTP_AuthInfo = NULL; return;}PUBLIC CONST char * HTGetNewsHost NOARGS{ return HTNewsHost;}PUBLIC void HTSetNewsHost ARGS1(CONST char *, value){ StrAllocCopy(HTNewsHost, value);}/* Initialisation for this module** ------------------------------**** Except on the NeXT, we pick up the NewsHost name from**** 1. Environment variable NNTPSERVER** 2. File SERVER_FILE** 3. Compilation time macro DEFAULT_NEWS_HOST** 4. Default to "news"**** On the NeXT, we pick up the NewsHost name from, in order:**** 1. WorldWideWeb default "NewsHost"** 2. Global default "NewsHost"** 3. News default "NewsHost"** 4. Compilation time macro DEFAULT_NEWS_HOST** 5. Default to "news"*/PRIVATE BOOL initialized = NO;PRIVATE BOOL initialize NOARGS{#ifdef NeXTStep char *cp = NULL;#endif /* ** Get name of Host. */#ifdef NeXTStep if ((cp = NXGetDefaultValue("WorldWideWeb","NewsHost"))==0) { if ((cp = NXGetDefaultValue("News","NewsHost")) == 0) { StrAllocCopy(HTNewsHost, DEFAULT_NEWS_HOST); } } if (cp) { StrAllocCopy(HTNewsHost, cp); cp = NULL; }#else if (LYGetEnv("NNTPSERVER")) { StrAllocCopy(HTNewsHost, LYGetEnv("NNTPSERVER")); CTRACE((tfp, "HTNews: NNTPSERVER defined as `%s'\n", HTNewsHost)); } else { FILE* fp = fopen(SERVER_FILE, TXT_R); if (fp) { char server_name[MAXHOSTNAMELEN+1]; if (fgets(server_name, sizeof server_name, fp) != NULL) { char *p = strchr(server_name, '\n'); if (p != NULL) *p = '\0'; StrAllocCopy(HTNewsHost, server_name); CTRACE((tfp, "HTNews: File %s defines news host as `%s'\n", SERVER_FILE, HTNewsHost)); } fclose(fp); } } if (!HTNewsHost) StrAllocCopy(HTNewsHost, DEFAULT_NEWS_HOST);#endif /* NeXTStep */ s = -1; /* Disconnected */#ifdef LY_FIND_LEAKS atexit(free_news_globals);#endif return YES;}/* Send NNTP Command line to remote host & Check Response** ------------------------------------------------------**** On entry,** command points to the command to be sent, including CRLF, or is null** pointer if no command to be sent.** On exit,** Negative status indicates transmission error, socket closed.** Positive status is an NNTP status.*/PRIVATE int response ARGS1(char *,command){ int result; char * p = response_text; int ich; if (command) { int status; int length = strlen(command); CTRACE((tfp, "NNTP command to be sent: %s", command));#ifdef NOT_ASCII { CONST char * p; char * q; char ascii[LINE_LENGTH+1]; for(p = command, q=ascii; *p; p++, q++) { *q = TOASCII(*p); } status = NEWS_NETWRITE(s, ascii, length); }#else status = NEWS_NETWRITE(s, (char *)command, length);#endif /* NOT_ASCII */ if (status < 0){ CTRACE((tfp, "HTNews: Unable to send command. Disconnecting.\n")); NEWS_NETCLOSE(s); s = -1; return status; } /* if bad status */ } /* if command to be sent */ for (;;) { ich = NEXT_CHAR; if (((*p++ = (char) ich) == LF) || (p == &response_text[LINE_LENGTH])) { *--p = '\0'; /* Terminate the string */ CTRACE((tfp, "NNTP Response: %s\n", response_text)); sscanf(response_text, "%d", &result); return result; } /* if end of line */ if (ich == EOF) { *(p-1) = '\0'; if (interrupted_in_htgetcharacter) { CTRACE((tfp, "HTNews: Interrupted on read, closing socket %d\n", s)); } else { CTRACE((tfp, "HTNews: EOF on read, closing socket %d\n", s)); } NEWS_NETCLOSE(s); /* End of file, close socket */ s = -1; if (interrupted_in_htgetcharacter) { interrupted_in_htgetcharacter = 0; return(HT_INTERRUPTED); } return((int)EOF); /* End of file on response */ } } /* Loop over characters */}/* Case insensitive string comparisons** -----------------------------------**** On entry,** template must be already un upper case.** unknown may be in upper or lower or mixed case to match.*/PRIVATE BOOL match ARGS2 (CONST char *,unknown, CONST char *,template){ CONST char * u = unknown; CONST char * t = template; for (; *u && *t && (TOUPPER(*u) == *t); u++, t++) ; /* Find mismatch or end */ return (BOOL)(*t == 0); /* OK if end of template */}typedef enum { NNTPAUTH_ERROR = 0, /* general failure */ NNTPAUTH_OK = 281, /* authenticated successfully */ NNTPAUTH_CLOSE = 502 /* server probably closed connection */} NNTPAuthResult;/*** This function handles nntp authentication. - FM*/PRIVATE NNTPAuthResult HTHandleAuthInfo ARGS1( char *, host){ HTList *cur = NULL; NNTPAuth *auth = NULL; char *UserName = NULL; char *PassWord = NULL; char *msg = NULL; char buffer[512]; int status, tries; /* ** Make sure we have an interactive user and a host. - FM */ if (dump_output_immediately || !(host && *host)) return NNTPAUTH_ERROR; /* ** Check for an existing authorization entry. - FM */ if (NNTP_AuthInfo != NULL) { cur = NNTP_AuthInfo; while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { if (!strcmp(auth->host, host)) { UserName = auth->user; PassWord = auth->pass; break; } } } else { NNTP_AuthInfo = HTList_new();#ifdef LY_FIND_LEAKS atexit(free_NNTP_AuthInfo);#endif } /* ** Handle the username. - FM */ buffer[sizeof(buffer)-1] = '\0'; tries = 3; while (tries) { if (UserName == NULL) { HTSprintf0(&msg, gettext("Username for news host '%s':"), host); UserName = HTPrompt(msg, NULL); FREE(msg); if (!(UserName && *UserName)) { FREE(UserName); return NNTPAUTH_ERROR; } } sprintf(buffer, "AUTHINFO USER %.*s%c%c", (int) sizeof(buffer)-17, UserName, CR, LF); if ((status = response(buffer)) < 0) { if (status == HT_INTERRUPTED) _HTProgress(CONNECTION_INTERRUPTED); else HTAlert(FAILED_CONNECTION_CLOSED); if (auth) { if (auth->user != UserName) { FREE(auth->user); auth->user = UserName; } } else { FREE(UserName); } return NNTPAUTH_CLOSE; } if (status == 281) { /* ** Username is accepted and no password is required. - FM */ if (auth) { if (auth->user != UserName) { FREE(auth->user); auth->user = UserName; } } else { /* ** Store the accepted username and no password. - FM */ if ((auth = typecalloc(NNTPAuth)) != NULL) { StrAllocCopy(auth->host, host); auth->user = UserName; HTList_appendObject(NNTP_AuthInfo, auth); } } return NNTPAUTH_OK; } if (status != 381) { /* ** Not success, nor a request for the password, ** so it must be an error. - FM */ HTAlert(response_text); tries--; if ((tries > 0) && HTConfirm(gettext("Change username?"))) { if (!auth || auth->user != UserName) { FREE(UserName); } if ((UserName = HTPrompt(gettext("Username:"), UserName)) != NULL && *UserName) { continue; } } if (auth) { if (auth->user != UserName) { FREE(auth->user); } FREE(auth->pass); } FREE(UserName); return NNTPAUTH_ERROR; } break; } if (status == 381) { /* ** Handle the password. - FM */ tries = 3; while (tries) { if (PassWord == NULL) { HTSprintf0(&msg, gettext("Password for news host '%s':"), host); PassWord = HTPromptPassword(msg); FREE(msg); if (!(PassWord && *PassWord)) { FREE(PassWord); return NNTPAUTH_ERROR; } } sprintf(buffer, "AUTHINFO PASS %.*s%c%c", (int) sizeof(buffer)-17, PassWord, CR, LF); if ((status = response(buffer)) < 0) { if (status == HT_INTERRUPTED) { _HTProgress(CONNECTION_INTERRUPTED); } else { HTAlert(FAILED_CONNECTION_CLOSED); } if (auth) { if (auth->user != UserName) { FREE(auth->user); auth->user = UserName; } if (auth->pass != PassWord) { FREE(auth->pass); auth->pass = PassWord; } } else { FREE(UserName); FREE(PassWord); } return NNTPAUTH_CLOSE; } if (status == 502) { /* * That's what INN's nnrpd returns. * It closes the connection after this. - kw */ HTAlert(response_text); if (auth) { if (auth->user == UserName) UserName = NULL; FREE(auth->user); if (auth->pass == PassWord) PassWord = NULL; FREE(auth->pass); } FREE(UserName); FREE(PassWord); return NNTPAUTH_CLOSE; } if (status == 281) { /* ** Password also is accepted, and everything ** has been stored. - FM */ if (auth) { if (auth->user != UserName) { FREE(auth->user); auth->user = UserName; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -