diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 1997-08-17 13:18:55 -0400 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 1997-08-17 13:18:55 -0400 |
commit | fbcb509d8db6255777742b09da479531108aa8d0 (patch) | |
tree | f1b14aa04f7c8eee2464f4575113db0c4c680900 /WWW/Library/Implementation/HTNews.c | |
parent | 050803d49a91559644e86a4ed38f11ba0afffbe4 (diff) | |
download | lynx-snapshots-fbcb509d8db6255777742b09da479531108aa8d0.tar.gz |
snapshot of project "lynx", label v2-7-1ac_0-52
Diffstat (limited to 'WWW/Library/Implementation/HTNews.c')
-rw-r--r-- | WWW/Library/Implementation/HTNews.c | 373 |
1 files changed, 362 insertions, 11 deletions
diff --git a/WWW/Library/Implementation/HTNews.c b/WWW/Library/Implementation/HTNews.c index 21da80d8..bcf2993e 100644 --- a/WWW/Library/Implementation/HTNews.c +++ b/WWW/Library/Implementation/HTNews.c @@ -78,6 +78,7 @@ PRIVATE HTStructured * target; /* The output sink */ PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */ PRIVATE HTParentAnchor *node_anchor; /* Its anchor */ PRIVATE int diagnostic; /* level: 0=none 2=source */ +PRIVATE HTList *NNTP_AuthInfo = NULL; /* AUTHINFO database */ #define PUTC(c) (*targetClass.put_character)(target, c) #define PUTS(s) (*targetClass.put_string)(target, s) @@ -86,13 +87,42 @@ PRIVATE int diagnostic; /* level: 0=none 2=source */ #define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ (*targetClass.end_element)(target, e, 0) +typedef struct _NNTPAuth { + char * host; + char * user; + char * pass; +} NNTPAuth; + PRIVATE void free_news_globals NOARGS { + if (s >= 0) { + NEWS_NETCLOSE(s); + s = -1; + } FREE(HTNewsHost); FREE(NewsHost); FREE(NewsHREF); } +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; @@ -260,6 +290,239 @@ PRIVATE BOOL match ARGS2 (CONST char *,unknown, CONST char *,template) 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; + extern BOOL dump_output_immediately; + + /* + ** 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(); + atexit(free_NNTP_AuthInfo); + } + + /* + ** Handle the username. - FM + */ + buffer[511] = '\0'; + tries = 3; + + while (tries) { + if (UserName == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "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", 495, UserName, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) + _HTProgress("Connection interrupted."); + else + HTAlert("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 OK and no Password is required. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + } else { + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + if (status != 381) { + /* + ** Not a request for the password, so it must be an error. - FM + */ + HTAlert(response_text); + tries--; + if ((tries > 0) && HTConfirm("Change username?")) { + if (!auth || auth->user != UserName) { + FREE(UserName); + } + if ((UserName = HTPrompt("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) { + /* + ** Username is OK, and a password is required. - FM + */ + tries = 3; + while (tries) { + if (PassWord == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "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", 495, PassWord, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + } else { + HTAlert("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 is OK. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + if (auth->pass != PassWord) { + FREE(auth->pass); + auth->pass = PassWord; + } + } else { + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + auth->pass = PassWord; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + /* + ** Show the error message and see if we should try again. - FM + */ + HTAlert(response_text); + if (!auth || auth->pass != PassWord) { + FREE(PassWord); + } else { + PassWord = NULL; + } + tries--; + if ((tries > 0) && HTConfirm("Change password?")) { + continue; + } + if (auth) { + if (auth->user == UserName) + UserName = NULL; + FREE(auth->user); + FREE(auth->pass); + } + FREE(UserName); + break; + } + } + + return NNTPAUTH_ERROR; +} + /* Find Author's name in mail address ** ---------------------------------- ** @@ -1919,7 +2182,7 @@ PUBLIC int HTLoadNews ARGS4( if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { strcpy(command, "POST"); } else if (list_wanted) { - strcpy(command, "LIST NEWSGROUPS"); + sprintf(command, "XGTITLE %.*s", 249, p1); } else if (group_wanted) { char * slash = strchr(p1, '/'); strcpy(command, "GROUP "); @@ -2170,10 +2433,10 @@ PUBLIC int HTLoadNews ARGS4( } else { /* ** Ensure reader mode, but don't bother checking the - ** status for anything but HT_INERRUPTED, because if - ** the reader mode command is not needed, the server - ** probably return a 500, which is irrelevant at - ** this point. - FM + ** status for anything but HT_INTERRUPTED or a 480 + ** Authorization request, because if the reader mode + ** command is not needed, the server probably returned + ** a 500, which is irrelevant at this point. - FM */ char buffer[20]; @@ -2182,6 +2445,22 @@ PUBLIC int HTLoadNews ARGS4( _HTProgress("Connection interrupted."); break; } + if (status == 480) { + NNTPAuthResult auth_result = HTHandleAuthInfo(NewsHost); + if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + } + if (auth_result != NNTPAUTH_OK) { + break; + } + if ((status = response(buffer)) == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + break; + } + } } Send_NNTP_command: @@ -2196,12 +2475,41 @@ Send_NNTP_command: break; } } + /* + * For some well known error responses which are expected + * to occur in normal use, break from the loop without retrying + * and without closing the connection. It is unlikely that + * these are leftovers from a timed-out connection (but we do + * some checks to see whether the response rorresponds to the + * last command), or that they will give anything else when + * automatically retried. - kw + */ + if (status == 411 && group_wanted && + !strncmp(command, "GROUP ", 6) && + !strncasecomp(response_text + 3, " No such group ", 15) && + !strcmp(response_text + 18, groupName)) { + + HTAlert(response_text); + break; + } else if (status == 430 && !group_wanted && !list_wanted && + !strncmp(command, "ARTICLE <", 9) && + !strcasecomp(response_text + 3, " No such article")) { + + HTAlert(response_text); + break; + } if ((status/100) != 2 && - status != 340) { - if (retries) + status != 340 && + status != 480) { + if (retries) { + if (list_wanted && !strncmp(command, "XGTITLE", 7)) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } HTAlert(response_text); - else + } else { _HTProgress(response_text); + } NEWS_NETCLOSE(s); s = -1; /* @@ -2215,7 +2523,36 @@ Send_NNTP_command: /* ** Post or load a group, article, etc */ - if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { + if (status == 480) { + NNTPAuthResult auth_result; + /* + * Some servers return 480 for a failed XGTITLE. - FM + */ + if (list_wanted && !strncmp(command, "XGTITLE", 7) && + strstr(response_text, "uthenticat") == NULL && + strstr(response_text, "uthor") == NULL) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } + /* + ** Handle Authorization. - FM + */ + if ((auth_result = HTHandleAuthInfo(NewsHost)) == NNTPAUTH_OK) { + goto Send_NNTP_command; + } else if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + if (retries < 1) + continue; + } + status = HT_NOT_LOADED; + } else if (post_wanted || reply_wanted || + spost_wanted || sreply_wanted) { + /* + ** Handle posting of an article. - FM + */ if (status != 340) { HTAlert("Cannot POST to this host."); if (postfile) { @@ -2232,9 +2569,15 @@ Send_NNTP_command: FREE(postfile); status = HT_NOT_LOADED; } else if (list_wanted) { + /* + ** List available newsgroups. - FM + */ _HTProgress("Reading list of available newsgroups."); status = read_list(ListArg); } else if (group_wanted) { + /* + ** List articles in a news group. - FM + */ if (last < 0) { /* ** We got one article number rather than a range @@ -2252,6 +2595,9 @@ Send_NNTP_command: _HTProgress("Reading list of articles in newsgroup."); status = read_group(groupName, first, last); } else { + /* + ** Get an article from a news group. - FM + */ _HTProgress("Reading news article."); status = read_article(); } @@ -2260,8 +2606,13 @@ Send_NNTP_command: status = HT_LOADED; } if (!(post_wanted || reply_wanted || - spost_wanted || sreply_wanted)) - (*targetClass._free)(target); + spost_wanted || sreply_wanted)) { + if (status == HT_NOT_LOADED) { + (*targetClass._abort)(target, NULL); + } else { + (*targetClass._free)(target); + } + } FREE(NewsHREF); if (ProxyHREF) { StrAllocCopy(NewsHost, ProxyHost); |