home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
- /*
- * State machine to implement NNTP access
- *
- * Designed and originally implemented by Lou Montulli '94
- * Heavily modified by libmsg folks
- */
-
- /* Please leave outside of ifdef for windows precompiled headers */
- #define FORCE_PR_LOG /* Allow logging in the release build (sorry this breaks the PCH) */
- #include "rosetta.h"
- #include "mkutils.h"
-
- #ifdef MOZILLA_CLIENT
-
- #include "merrors.h"
-
- #include "mime.h"
- #include "shist.h"
- #include "glhist.h"
- #include "xp_reg.h"
- #include "mknews.h"
- #include "mktcp.h"
- #include "mkparse.h"
- #include "mkformat.h"
- #include "mkstream.h"
- #include "mkaccess.h"
- #include "mksort.h"
- #include "mkcache.h"
- #include "mkextcac.h"
- #include "mknewsgr.h"
- #include "libi18n.h"
- #include "gui.h"
- #include "cert.h"
- #include "ssl.h"
- #include "mknews.h"
-
- #include "msgcom.h"
- #include "msgnet.h"
- #include "msg_srch.h"
- #include "libmime.h"
-
- #include "prtime.h"
- #include "prlog.h"
-
- #include "xp_error.h"
- #include "secnav.h"
- #include "prefapi.h"
-
- /*#define CACHE_NEWSGRP_PASSWORD*/
-
- /* for XP_GetString() */
- #include "xpgetstr.h"
- extern int MK_MALFORMED_URL_ERROR;
- extern int MK_NEWS_ERROR_FMT;
- extern int MK_NNTP_CANCEL_CONFIRM;
- extern int MK_NNTP_CANCEL_DISALLOWED;
- extern int MK_NNTP_NOT_CANCELLED;
- extern int MK_OUT_OF_MEMORY;
- extern int XP_CONFIRM_SAVE_NEWSGROUPS;
- extern int XP_HTML_ARTICLE_EXPIRED;
- extern int XP_HTML_NEWS_ERROR;
- extern int XP_PROGRESS_READ_NEWSGROUPINFO;
- extern int XP_PROGRESS_RECEIVE_ARTICLE;
- extern int XP_PROGRESS_RECEIVE_LISTARTICLES;
- extern int XP_PROGRESS_RECEIVE_NEWSGROUP;
- extern int XP_PROGRESS_SORT_ARTICLES;
- extern int XP_PROGRESS_READ_NEWSGROUP_COUNTS;
- extern int XP_THERMO_PERCENT_FORM;
- extern int XP_PROMPT_ENTER_USERNAME;
- extern int MK_BAD_NNTP_CONNECTION;
- extern int MK_NNTP_AUTH_FAILED;
- extern int MK_NNTP_ERROR_MESSAGE;
- extern int MK_NNTP_NEWSGROUP_SCAN_ERROR;
- extern int MK_NNTP_SERVER_ERROR;
- extern int MK_NNTP_SERVER_NOT_CONFIGURED;
- extern int MK_SECURE_NEWS_PROXY_ERROR;
- extern int MK_TCP_READ_ERROR;
- extern int MK_TCP_WRITE_ERROR;
- extern int MK_NNTP_CANCEL_ERROR;
- extern int XP_CONNECT_NEWS_HOST_CONTACTED_WAITING_FOR_REPLY;
- extern int XP_PLEASE_ENTER_A_PASSWORD_FOR_NEWS_SERVER_ACCESS;
- extern int XP_GARBAGE_COLLECTING;
- extern int XP_MESSAGE_SENT_WAITING_NEWS_REPLY;
- extern int MK_MSG_DELIV_NEWS;
- extern int MK_MSG_COLLABRA_DISABLED;
- extern int MK_MSG_EXPIRE_NEWS_ARTICLES;
-
- /* Logging stuff */
- #ifndef NSPR20
- PR_LOG_DEFINE(NNTP);
- #define NNTP_LOG_READ(buf) PR_LOG(NNTP, out, ("Receiving: %s", buf))
- #define NNTP_LOG_WRITE(buf) PR_LOG(NNTP, out, ("Sending: %s", buf))
- #define NNTP_LOG_NOTE(buf) PR_LOG(NNTP, out, buf)
- #else
- PRLogModuleInfo* NNTP = NULL;
- #define out PR_LOG_ALWAYS
-
- #define NNTP_LOG_READ(buf) \
- if (NNTP==NULL) \
- NNTP = PR_NewLogModule("NNTP"); \
- PR_LOG(NNTP, out, ("Receiving: %s", buf)) ;
-
- #define NNTP_LOG_WRITE(buf) \
- if (NNTP==NULL) \
- NNTP = PR_NewLogModule("NNTP"); \
- PR_LOG(NNTP, out, ("Sending: %s", buf)) ;
-
- #define NNTP_LOG_NOTE(buf) \
- if (NNTP==NULL) \
- NNTP = PR_NewLogModule("NNTP"); \
- PR_LOG(NNTP, out, buf) ;
-
- #endif /* NSPR20 */
-
- /* Forward declarations */
- static int net_xpat_send (ActiveEntry*);
- static int net_list_pretty_names(ActiveEntry*);
- PRIVATE int32 net_ProcessNews (ActiveEntry *ce);
-
- #ifdef PROFILE
- #pragma profile on
- #endif
-
- #define LIST_WANTED 0
- #define ARTICLE_WANTED 1
- #define CANCEL_WANTED 2
- #define GROUP_WANTED 3
- #define NEWS_POST 4
- #define READ_NEWS_RC 5
- #define NEW_GROUPS 6
- #define SEARCH_WANTED 7
- #define PRETTY_NAMES_WANTED 8
- #define PROFILE_WANTED 9
- #define IDS_WANTED 10
-
- /* the output_buffer_size must be larger than the largest possible line
- * 2000 seems good for news
- *
- * jwz: I increased this to 4k since it must be big enough to hold the
- * entire button-bar HTML, and with the new "mailto" format, that can
- * contain arbitrarily long header fields like "references".
- *
- * fortezza: proxy auth is huge, buffer increased to 8k (sigh).
- */
- #define OUTPUT_BUFFER_SIZE (4096*2)
-
- /* the amount of time to subtract from the machine time
- * for the newgroup command sent to the nntp server
- */
- #define NEWGROUPS_TIME_OFFSET 60L*60L*12L /* 12 hours */
-
- /* Allow the user to open at most this many connections to one news host*/
- #define kMaxConnectionsPerHost 3
-
- /* Keep this many connections cached. The cache is global, not per host */
- #define kMaxCachedConnections 2
-
- /* globals
- */
- PRIVATE char * NET_NewsHost = NULL;
- PRIVATE XP_List * nntp_connection_list=0;
-
- PRIVATE XP_Bool net_news_last_username_probably_valid=FALSE;
- PRIVATE int32 net_NewsChunkSize=-1; /* default */
-
- #define PUTSTRING(s) (*cd->stream->put_block) \
- (cd->stream, s, XP_STRLEN(s))
- #define COMPLETE_STREAM (*cd->stream->complete) \
- (cd->stream)
- #define ABORT_STREAM(s) (*cd->stream->abort) \
- (cd->stream, s)
- #define PUT_STREAM(buf, size) (*cd->stream->put_block) \
- (cd->stream, buf, size)
-
- /* states of the machine
- */
- typedef enum _StatesEnum {
- NNTP_RESPONSE,
- #ifdef BLOCK_UNTIL_AVAILABLE_CONNECTION
- NNTP_BLOCK_UNTIL_CONNECTIONS_ARE_AVAILABLE,
- NNTP_CONNECTIONS_ARE_AVAILABLE,
- #endif
- NNTP_CONNECT,
- NNTP_CONNECT_WAIT,
- HG86722
- NNTP_LOGIN_RESPONSE,
- NNTP_SEND_MODE_READER,
- NNTP_SEND_MODE_READER_RESPONSE,
- SEND_LIST_EXTENSIONS,
- SEND_LIST_EXTENSIONS_RESPONSE,
- SEND_LIST_SEARCHES,
- SEND_LIST_SEARCHES_RESPONSE,
- NNTP_LIST_SEARCH_HEADERS,
- NNTP_LIST_SEARCH_HEADERS_RESPONSE,
- NNTP_GET_PROPERTIES,
- NNTP_GET_PROPERTIES_RESPONSE,
- SEND_LIST_SUBSCRIPTIONS,
- SEND_LIST_SUBSCRIPTIONS_RESPONSE,
- SEND_FIRST_NNTP_COMMAND,
- SEND_FIRST_NNTP_COMMAND_RESPONSE,
- SETUP_NEWS_STREAM,
- NNTP_BEGIN_AUTHORIZE,
- NNTP_AUTHORIZE_RESPONSE,
- NNTP_PASSWORD_RESPONSE,
- NNTP_READ_LIST_BEGIN,
- NNTP_READ_LIST,
- DISPLAY_NEWSGROUPS,
- NNTP_NEWGROUPS_BEGIN,
- NNTP_NEWGROUPS,
- NNTP_BEGIN_ARTICLE,
- NNTP_READ_ARTICLE,
- NNTP_XOVER_BEGIN,
- NNTP_FIGURE_NEXT_CHUNK,
- NNTP_XOVER_SEND,
- NNTP_XOVER_RESPONSE,
- NNTP_XOVER,
- NEWS_PROCESS_XOVER,
- NNTP_READ_GROUP,
- NNTP_READ_GROUP_RESPONSE,
- NNTP_READ_GROUP_BODY,
- NNTP_SEND_GROUP_FOR_ARTICLE,
- NNTP_SEND_GROUP_FOR_ARTICLE_RESPONSE,
- NNTP_PROFILE_ADD,
- NNTP_PROFILE_ADD_RESPONSE,
- NNTP_PROFILE_DELETE,
- NNTP_PROFILE_DELETE_RESPONSE,
- NNTP_SEND_ARTICLE_NUMBER,
- NEWS_PROCESS_BODIES,
- NNTP_PRINT_ARTICLE_HEADERS,
- NNTP_SEND_POST_DATA,
- NNTP_SEND_POST_DATA_RESPONSE,
- NNTP_CHECK_FOR_MESSAGE,
- NEWS_NEWS_RC_POST,
- NEWS_DISPLAY_NEWS_RC,
- NEWS_DISPLAY_NEWS_RC_RESPONSE,
- NEWS_START_CANCEL,
- NEWS_DO_CANCEL,
- NNTP_XPAT_SEND,
- NNTP_XPAT_RESPONSE,
- NNTP_SEARCH,
- NNTP_SEARCH_RESPONSE,
- NNTP_SEARCH_RESULTS,
- NNTP_LIST_PRETTY_NAMES,
- NNTP_LIST_PRETTY_NAMES_RESPONSE,
- NNTP_LIST_XACTIVE,
- NNTP_LIST_XACTIVE_RESPONSE,
- NNTP_LIST_GROUP,
- NNTP_LIST_GROUP_RESPONSE,
- NEWS_DONE,
- NEWS_ERROR,
- NNTP_ERROR,
- NEWS_FREE
- } StatesEnum;
-
- #ifdef DEBUG
- char *stateLabels[] = {
- "NNTP_RESPONSE",
- #ifdef BLOCK_UNTIL_AVAILABLE_CONNECTION
- "NNTP_BLOCK_UNTIL_CONNECTIONS_ARE_AVAILABLE",
- "NNTP_CONNECTIONS_ARE_AVAILABLE",
- #endif
- "NNTP_CONNECT",
- "NNTP_CONNECT_WAIT",
- HG87489
- "NNTP_LOGIN_RESPONSE",
- "NNTP_SEND_MODE_READER",
- "NNTP_SEND_MODE_READER_RESPONSE",
- "SEND_LIST_EXTENSIONS",
- "SEND_LIST_EXTENSIONS_RESPONSE",
- "SEND_LIST_SEARCHES",
- "SEND_LIST_SEARCHES_RESPONSE",
- "NNTP_LIST_SEARCH_HEADERS",
- "NNTP_LIST_SEARCH_HEADERS_RESPONSE",
- "NNTP_GET_PROPERTIES",
- "NNTP_GET_PROPERTIES_RESPONSE",
- "SEND_LIST_SUBSCRIPTIONS",
- "SEND_LIST_SUBSCRIPTIONS_RESPONSE",
- "SEND_FIRST_NNTP_COMMAND",
- "SEND_FIRST_NNTP_COMMAND_RESPONSE",
- "SETUP_NEWS_STREAM",
- "NNTP_BEGIN_AUTHORIZE",
- "NNTP_AUTHORIZE_RESPONSE",
- "NNTP_PASSWORD_RESPONSE",
- "NNTP_READ_LIST_BEGIN",
- "NNTP_READ_LIST",
- "DISPLAY_NEWSGROUPS",
- "NNTP_NEWGROUPS_BEGIN",
- "NNTP_NEWGROUPS",
- "NNTP_BEGIN_ARTICLE",
- "NNTP_READ_ARTICLE",
- "NNTP_XOVER_BEGIN",
- "NNTP_FIGURE_NEXT_CHUNK",
- "NNTP_XOVER_SEND",
- "NNTP_XOVER_RESPONSE",
- "NNTP_XOVER",
- "NEWS_PROCESS_XOVER",
- "NNTP_READ_GROUP",
- "NNTP_READ_GROUP_RESPONSE",
- "NNTP_READ_GROUP_BODY",
- "NNTP_SEND_GROUP_FOR_ARTICLE",
- "NNTP_SEND_GROUP_FOR_ARTICLE_RESPONSE",
- "NNTP_PROFILE_ADD",
- "NNTP_PROFILE_ADD_RESPONSE",
- "NNTP_PROFILE_DELETE",
- "NNTP_PROFILE_DELETE_RESPONSE",
- "NNTP_SEND_ARTICLE_NUMBER",
- "NEWS_PROCESS_BODIES",
- "NNTP_PRINT_ARTICLE_HEADERS",
- "NNTP_SEND_POST_DATA",
- "NNTP_SEND_POST_DATA_RESPONSE",
- "NNTP_CHECK_FOR_MESSAGE",
- "NEWS_NEWS_RC_POST",
- "NEWS_DISPLAY_NEWS_RC",
- "NEWS_DISPLAY_NEWS_RC_RESPONSE",
- "NEWS_START_CANCEL",
- "NEWS_DO_CANCEL",
- "NNTP_XPAT_SEND",
- "NNTP_XPAT_RESPONSE",
- "NNTP_SEARCH",
- "NNTP_SEARCH_RESPONSE",
- "NNTP_SEARCH_RESULTS",
- "NNTP_LIST_PRETTY_NAMES",
- "NNTP_LIST_PRETTY_NAMES_RESPONSE",
- "NNTP_LIST_XACTIVE_RESPONSE",
- "NNTP_LIST_XACTIVE",
- "NNTP_LIST_GROUP",
- "NNTP_LIST_GROUP_RESPONSE",
- "NEWS_DONE",
- "NEWS_ERROR",
- "NNTP_ERROR",
- "NEWS_FREE"
- };
-
- #endif
-
- /* structure to hold data about a tcp connection
- * to a news host
- */
- typedef struct _NNTPConnection {
- char *hostname; /* hostname string (may contain :port) */
- PRFileDesc *csock; /* control socket */
- XP_Bool busy; /* is the connection in use already? */
- XP_Bool prev_cache; /* did this connection come from the cache? */
- XP_Bool posting_allowed;/* does this server allow posting */
- XP_Bool default_host;
- XP_Bool no_xover; /* xover command is not supported here */
- XP_Bool secure; /* is it a secure connection? */
-
- char *current_group; /* last GROUP command sent on this connection */
-
- } NNTPConnection;
-
-
- /* structure to hold all the state and data
- * for the state machine
- */
- typedef struct _NewsConData {
- MSG_Pane *pane;
- MSG_NewsHost *host;
-
- StatesEnum next_state;
- StatesEnum next_state_after_response;
- int type_wanted; /* Article, List, or Group */
- int response_code; /* code returned from NNTP server */
- char *response_txt; /* text returned from NNTP server */
- Bool pause_for_read; /* should we pause for the next read? */
-
- char *ssl_proxy_server; /* ssl proxy server hostname */
- XP_Bool proxy_auth_required; /* is auth required */
- XP_Bool sent_proxy_auth; /* have we sent a proxy auth? */
-
- XP_Bool newsrc_performed; /* have we done a newsrc update? */
- XP_Bool mode_reader_performed; /* have we sent any cmds to the server yet? */
-
- #ifdef XP_WIN
- XP_Bool calling_netlib_all_the_time;
- #endif
- NET_StreamClass * stream;
-
- NNTPConnection * control_con; /* all the info about a connection */
-
- char *data_buf;
- int32 data_buf_size;
-
- /* for group command */
- char *path; /* message id */
-
- char *group_name;
- int32 first_art;
- int32 last_art;
- int32 first_possible_art;
- int32 last_possible_art;
-
- int32 num_loaded; /* How many articles we got XOVER lines for. */
- int32 num_wanted; /* How many articles we wanted to get XOVER
- lines for. */
-
- /* for cancellation: the headers to be used */
- char *cancel_from;
- char *cancel_newsgroups;
- char *cancel_distribution;
- char *cancel_id;
- char *cancel_msg_file;
- int cancel_status;
-
- /* variables for ReadNewsRC */
- int32 newsrc_list_index;
- int32 newsrc_list_count;
-
- XP_Bool use_fancy_newsgroup_listing; /* use LIST XACTIVE or LIST */
- XP_Bool destroy_graph_progress; /* do we need to destroy
- * graph progress?
- */
-
- char *output_buffer; /* use it to write out lines */
-
- int32 article_num; /* current article number */
-
- char *message_id; /* for reading groups */
- char *author;
- char *subject;
-
- int32 original_content_length; /* the content length at the time of
- * calling graph progress
- */
-
- /* random pointer for libmsg state */
- void *xover_parse_state;
- void *newsgroup_parse_state;
-
- TCP_ConData * tcp_con_data;
-
- void * write_post_data_data;
-
- XP_Bool some_protocol_succeeded; /* We know we have done some protocol
- with this newsserver recently, so don't
- respond to an error by closing and
- reopening it. */
- char *command_specific_data;
- char *current_search;
- void *offlineState; /* offline news state machine for article retrieval */
- int previous_response_code;
-
- } NewsConData;
-
-
- /* publicly available function to set the news host
- * this will be a useful front end callable routine
- */
- PUBLIC void NET_SetNewsHost (const char * value)
- {
- /* ### This routine is obsolete and should go away. */
- }
-
-
-
- /* set the default number of articles retrieved by news at any one time
- */
- PUBLIC void
- NET_SetNumberOfNewsArticlesInListing(int32 number)
- {
- net_NewsChunkSize = number;
- }
-
- /* Whether we cache XOVER data. NYI. */
- PUBLIC void
- NET_SetCacheXOVER(XP_Bool value)
- {
- }
-
-
-
- PUBLIC void NET_CleanTempXOVERCache(void)
- {
- }
-
-
-
- static void net_nntp_close (PRFileDesc *sock, int status)
- {
- if (status != MK_INTERRUPTED)
- {
- const char *command = "QUIT" CRLF;
- NET_BlockingWrite (sock, command, XP_STRLEN(command));
- NNTP_LOG_WRITE (command);
- }
- PR_Close(sock);
- }
-
-
- /* user has removed a news host from the UI.
- * be sure it has also been removed from the
- * connection cache so we renegotiate news host
- * capabilities if we try to use it again
- */
- PUBLIC void NET_OnNewsHostDeleted (const char *hostName)
- {
- NNTPConnection *conn;
- XP_List *list = nntp_connection_list;
-
- while ((conn = (NNTPConnection*) XP_ListNextObject(list)) != NULL)
- {
- if (!(XP_STRCASECMP(conn->hostname, hostName)))
- net_nntp_close (conn->csock, conn->busy ? MK_INTERRUPTED : 0);
-
- list = list->prev ? list->prev : nntp_connection_list;
- XP_ListRemoveObject (nntp_connection_list, conn);
-
- FREEIF(conn->current_group);
- FREEIF(conn->hostname);
- FREE(conn);
- }
- }
-
-
- /* display HTML error state in the context window
- * returns negative error status
- */
- PRIVATE int
- net_display_html_error_state (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- XP_Bool inMsgPane = FALSE;
- int major_opcode = cd->response_code/100;
- /* #### maybe make this a dialog box
- to do that, just return an error.
- */
-
- /* ERROR STATE
- * Set up the HTML stream
- */
- ce->format_out = CLEAR_CACHE_BIT(ce->format_out);
- StrAllocCopy(ce->URL_s->content_type, TEXT_HTML);
-
- /* If we're not in a message pane, don't try to spew HTML
- * This allows error reporting from the folder pane, subscribe UI, etc.
- */
- if (ce->URL_s->msg_pane)
- inMsgPane = (MSG_MESSAGEPANE == MSG_GetPaneType(ce->URL_s->msg_pane));
-
- if (ce->format_out == FO_PRESENT && inMsgPane)
- {
- cd->stream = NET_StreamBuilder(ce->format_out, ce->URL_s,
- ce->window_id);
- if(!cd->stream)
- {
- ce->URL_s->error_msg =
- NET_ExplainErrorDetails(MK_UNABLE_TO_CONVERT);
- return MK_UNABLE_TO_CONVERT;
- }
-
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- XP_GetString(XP_HTML_NEWS_ERROR),
- cd->response_txt);
- if(ce->status > -1)
- ce->status = PUTSTRING(cd->output_buffer);
-
- if(cd->type_wanted == ARTICLE_WANTED ||
- cd->type_wanted == CANCEL_WANTED)
- {
- XP_STRCPY(cd->output_buffer,
- XP_GetString(XP_HTML_ARTICLE_EXPIRED));
- if(ce->status > -1)
- PUTSTRING(cd->output_buffer);
-
- if (cd->path && *cd->path && ce->status > -1)
- {
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "<P><%.512s>", cd->path);
- if (cd->article_num > 0)
- {
- PR_snprintf(cd->output_buffer+XP_STRLEN(cd->output_buffer),
- OUTPUT_BUFFER_SIZE-XP_STRLEN(cd->output_buffer),
- " (%lu)\n", (unsigned long) cd->article_num);
- if (ce->URL_s->msg_pane)
- MSG_MarkMessageKeyRead(ce->URL_s->msg_pane, cd->article_num, "");
- }
- PUTSTRING(cd->output_buffer);
- PR_snprintf(cd->output_buffer, OUTPUT_BUFFER_SIZE, "<P> <A HREF=\"news://%s/%s?list-ids\">%s</A> </P>\n", cd->control_con->hostname, cd->group_name, XP_GetString(MK_MSG_EXPIRE_NEWS_ARTICLES));
- PUTSTRING(cd->output_buffer);
- }
-
- if(ce->status > -1)
- {
- COMPLETE_STREAM;
- cd->stream = 0;
- }
- }
- else
- if (cd->type_wanted == SEARCH_WANTED)
- ce->status = net_xpat_send(ce);
-
- ce->URL_s->expires = 1;
- /* ce->URL_s->error_msg =
- NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- */
- }
- else
- {
- /* FORMAT_OUT is not FO_PRESENT - so instead of emitting an HTML
- error message, present it in a dialog box. */
-
- PR_snprintf(cd->output_buffer, /* #### i18n */
- OUTPUT_BUFFER_SIZE,
- XP_GetString(MK_NEWS_ERROR_FMT),
- cd->response_txt);
- ce->URL_s->error_msg = XP_STRDUP (cd->output_buffer);
- }
-
- /* if the server returned a 400 error then it is an expected
- * error. the NEWS_ERROR state will not sever the connection
- */
- if(major_opcode == 4)
- cd->next_state = NEWS_ERROR;
- else
- cd->next_state = NNTP_ERROR;
-
- /* If we ever get an error, let's re-issue the GROUP command
- before the next ARTICLE command; the overhead isn't very high,
- and weird stuff seems to be happening... */
- FREEIF(cd->control_con->current_group);
-
- /* cd->control_con->prev_cache = FALSE; to keep if from reconnecting */
- return MK_NNTP_SERVER_ERROR;
- }
-
-
- /* gets the response code from the nntp server and the
- * response line
- *
- * returns the TCP return code from the read
- */
- PRIVATE int
- net_news_response (ActiveEntry * ce)
- {
- char * line;
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- NNTP_LOG_READ(cd->data_buf);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- /* if TCP error of if there is not a full line yet return
- */
- if(ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR,
- SOCKET_ERRNO);
-
- /* return TCP error
- */
- return MK_TCP_READ_ERROR;
- }
- else if(!line)
- {
- return ce->status;
- }
-
- cd->pause_for_read = FALSE; /* don't pause if we got a line */
-
- if(ce->bytes_received == 0)
- {
- /* this is where kipp says that I can finally query
- * for the security data. We can't do it after the
- * connect since the handshake isn't done yet...
- */
- /* clear existing data
- */
- FREEIF(ce->URL_s->key_cipher);
- FREEIF(ce->URL_s->key_issuer);
- FREEIF(ce->URL_s->key_subject);
- CERT_DestroyCertificate(ce->URL_s->certificate);
-
- SSL_SecurityStatus(ce->socket,
- &ce->URL_s->security_on,
- &ce->URL_s->key_cipher,
- &ce->URL_s->key_size,
- &ce->URL_s->key_secret_size,
- &ce->URL_s->key_issuer,
- &ce->URL_s->key_subject);
- ce->URL_s->certificate = SSL_PeerCertificate(ce->socket);
- }
-
- /* almost correct
- */
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- FE_GraphProgress(ce->window_id, ce->URL_s, ce->bytes_received, ce->status, ce->URL_s->content_length);
- }
-
- StrAllocCopy(cd->response_txt, line+4);
-
- cd->previous_response_code = cd->response_code;
-
- sscanf(line, "%d", &cd->response_code);
-
- /* authentication required can come at any time
- */
- #ifdef CACHE_NEWSGRP_PASSWORD
- /*
- * This is an effort of trying to cache the username/password
- * per newsgroup. It is extremely hard to make it work along with
- * nntp voluntary password checking mechanism. We are backing this
- * feature out. Instead of touching various of backend msg files
- * at this late Dogbert 4.0 beta4 game, the infrastructure will
- * remain in the msg library. We only modify codes within this file.
- * Maybe one day we will try to do it again. Zzzzz -- jht
- */
- if(480 == cd->response_code || 450 == cd->response_code ||
- 502 == cd->response_code)
- {
- cd->next_state = NNTP_BEGIN_AUTHORIZE;
- if (502 == cd->response_code) {
- if (2 == cd->previous_response_code/100) {
- if (net_news_last_username_probably_valid) {
- net_news_last_username_probably_valid = FALSE;
- }
- else {
- MSG_SetNewsgroupUsername(cd->pane, NULL);
- MSG_SetNewsgroupPassword(cd->pane, NULL);
- }
- }
- else {
- net_news_last_username_probably_valid = FALSE;
- if (NNTP_PASSWORD_RESPONSE == cd->next_state_after_response) {
- MSG_SetNewsgroupUsername(cd->pane, NULL);
- MSG_SetNewsgroupPassword(cd->pane, NULL);
- }
- }
-
- }
- }
- #else
- if (480 == cd->response_code || 450 == cd->response_code)
- {
- cd->next_state = NNTP_BEGIN_AUTHORIZE;
- }
- else if (502 == cd->response_code)
- {
- net_news_last_username_probably_valid = FALSE;
- return net_display_html_error_state(ce);
- }
- #endif
- else
- {
- cd->next_state = cd->next_state_after_response;
- }
-
- return(0); /* everything ok */
- }
-
- HG40560
-
- /* interpret the server response after the connect
- *
- * returns negative if the server responds unexpectedly
- */
- PRIVATE int
- net_nntp_login_response (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- XP_Bool postingAllowed = cd->response_code == 200;
-
- if((cd->response_code/100)!=2)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_ERROR_MESSAGE, cd->response_txt);
-
- cd->next_state = NNTP_ERROR;
- cd->control_con->prev_cache = FALSE; /* to keep if from reconnecting */
- return MK_BAD_NNTP_CONNECTION;
- }
-
- cd->control_con->posting_allowed = postingAllowed; /* ###phil dead code */
- MSG_SetNewsHostPostingAllowed (cd->host, postingAllowed);
-
- cd->next_state = NNTP_SEND_MODE_READER;
- return(0); /* good */
- }
-
- PRIVATE int
- net_nntp_send_mode_reader (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- XP_STRCPY(cd->output_buffer, "MODE READER" CRLF);
-
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_SEND_MODE_READER_RESPONSE;
- cd->pause_for_read = TRUE;
-
- return(ce->status);
-
- }
-
- PRIVATE int
- net_nntp_send_mode_reader_response (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- cd->mode_reader_performed = TRUE;
-
- /* ignore the response code and continue
- */
-
- if (MSG_GetNewsHostPushAuth(cd->host))
- /* if the news host is set up to require volunteered (pushed) authentication,
- * do that before we do anything else
- */
- cd->next_state = NNTP_BEGIN_AUTHORIZE;
- else
- cd->next_state = SEND_LIST_EXTENSIONS;
-
- return(0);
- }
-
- PRIVATE int net_nntp_send_list_extensions (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- XP_STRCPY(cd->output_buffer, "LIST EXTENSIONS" CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = SEND_LIST_EXTENSIONS_RESPONSE;
- cd->pause_for_read = TRUE;
- return ce->status;
- }
-
- PRIVATE int net_nntp_send_list_extensions_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- if (cd->response_code > 200 && cd->response_code < 300)
- {
- char *line = NULL;
- MSG_NewsHost *host = cd->host;
-
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- MSG_AddNewsExtension (host, line);
- else
- {
- /* tell libmsg that it's ok to ask this news host for extensions */
- MSG_SupportsNewsExtensions (cd->host, TRUE);
-
- /* all extensions received */
- cd->next_state = SEND_LIST_SEARCHES;
- cd->pause_for_read = FALSE;
- }
- }
- else
- {
- /* LIST EXTENSIONS not recognized
- * tell libmsg not to ask for any more extensions and move on to
- * the real NNTP command we were trying to do.
- */
- MSG_SupportsNewsExtensions (cd->host, FALSE);
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_nntp_send_list_searches (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- if (MSG_QueryNewsExtension (cd->host, "SEARCH"))
- {
- XP_STRCPY(cd->output_buffer, "LIST SEARCHES" CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = SEND_LIST_SEARCHES_RESPONSE;
- cd->pause_for_read = TRUE;
- }
- else
- {
- /* since SEARCH isn't supported, move on to GET */
- cd->next_state = NNTP_GET_PROPERTIES;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_nntp_send_list_searches_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- char *line = NULL;
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- {
- MSG_AddSearchableGroup (cd->host, line);
- }
- else
- {
- /* all searchable groups received */
- /* LIST SRCHFIELDS is legal if the server supports the SEARCH extension, which */
- /* we already know it does */
- cd->next_state = NNTP_LIST_SEARCH_HEADERS;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_send_list_search_headers (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- XP_STRCPY(cd->output_buffer, "LIST SRCHFIELDS" CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LIST_SEARCH_HEADERS_RESPONSE;
- cd->pause_for_read = TRUE;
-
- return ce->status;
- }
-
- PRIVATE int net_send_list_search_headers_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- MSG_NewsHost *host = cd->host;
-
- char *line = NULL;
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- MSG_AddSearchableHeader (host, line);
- else
- {
- cd->next_state = NNTP_GET_PROPERTIES;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- PRIVATE int nntp_get_properties (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- if (MSG_QueryNewsExtension (cd->host, "SETGET"))
- {
- XP_STRCPY(cd->output_buffer, "GET" CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_GET_PROPERTIES_RESPONSE;
- cd->pause_for_read = TRUE;
- }
- else
- {
- /* since GET isn't supported, move on LIST SUBSCRIPTIONS */
- cd->next_state = SEND_LIST_SUBSCRIPTIONS;
- cd->pause_for_read = FALSE;
- }
- return ce->status;
- }
-
- PRIVATE int nntp_get_properties_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- char *line = NULL;
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- {
- char *propertyName = XP_STRDUP(line);
- if (propertyName)
- {
- char *space = XP_STRCHR(propertyName, ' ');
- if (space)
- {
- char *propertyValue = space + 1;
- *space = '\0';
- MSG_AddPropertyForGet (cd->host,
- propertyName, propertyValue);
- }
- XP_FREE(propertyName);
- }
- }
- else
- {
- /* all GET properties received, move on to LIST SUBSCRIPTIONS */
- cd->next_state = SEND_LIST_SUBSCRIPTIONS;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_send_list_subscriptions (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- #ifdef LATER
- if (MSG_QueryNewsExtension (cd->host, "LISTSUBSCR"))
- #else
- if (0)
- #endif
- {
- XP_STRCPY(cd->output_buffer, "LIST SUBSCRIPTIONS" CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = SEND_LIST_SUBSCRIPTIONS_RESPONSE;
- cd->pause_for_read = TRUE;
- }
- else
- {
- /* since LIST SUBSCRIPTIONS isn't supported, move on to real work */
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_send_list_subscriptions_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- char *line = NULL;
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- {
- #ifdef LATER
- char *urlScheme = cd->control_con->secure ? "snews:" : "news:";
- char *url = PR_smprintf ("%s//%s/%s", urlScheme, cd->control_con->hostname, line);
- if (url)
- MSG_AddSubscribedNewsgroup (cd->pane, url);
- #endif
- }
- else
- {
- /* all default subscriptions received */
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- /* figure out what the first command is and send it
- *
- * returns the status from the NETWrite
- */
- PRIVATE int
- net_send_first_nntp_command (ActiveEntry *ce)
- {
- char *command=0;
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->type_wanted == ARTICLE_WANTED)
- {
- const char *group = 0;
- uint32 number = 0;
-
- MSG_NewsGroupAndNumberOfID (cd->pane, cd->path,
- &group, &number);
- if (group && number)
- {
- cd->article_num = number;
- StrAllocCopy (cd->group_name, group);
-
- if (cd->control_con->current_group && !XP_STRCMP (cd->control_con->current_group, group))
- cd->next_state = NNTP_SEND_ARTICLE_NUMBER;
- else
- cd->next_state = NNTP_SEND_GROUP_FOR_ARTICLE;
-
- cd->pause_for_read = FALSE;
- return 0;
- }
- }
-
- if(cd->type_wanted == NEWS_POST && !ce->URL_s->post_data)
- {
- XP_ASSERT(0);
- return(-1);
- }
- else if(cd->type_wanted == NEWS_POST)
- { /* posting to the news group */
- StrAllocCopy(command, "POST");
- }
- else if(cd->type_wanted == READ_NEWS_RC)
- {
- if(ce->URL_s->method == URL_POST_METHOD ||
- XP_STRCHR(ce->URL_s->address, '?'))
- cd->next_state = NEWS_NEWS_RC_POST;
- else
- cd->next_state = NEWS_DISPLAY_NEWS_RC;
- return(0);
- }
- else if(cd->type_wanted == NEW_GROUPS)
- {
- time_t last_update =
- MSG_NewsgroupsLastUpdatedTime(cd->host);
- char small_buf[64];
- #ifndef NSPR20
- PRTime expandedTime;
- #else
- PRExplodedTime expandedTime;
- #endif /* NSPR20 */
-
- if(!last_update)
- {
-
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_NEWSGROUP_SCAN_ERROR);
- cd->next_state = NEWS_ERROR;
- return(MK_INTERRUPTED);
- }
-
- /* subtract some hours just to be sure */
- last_update -= NEWGROUPS_TIME_OFFSET;
-
- {
- int64 secToUSec, timeInSec, timeInUSec;
- LL_I2L(timeInSec, last_update);
- LL_I2L(secToUSec, PR_USEC_PER_SEC);
- LL_MUL(timeInUSec, timeInSec, secToUSec);
- #ifndef NSPR20
- PR_ExplodeTime( &expandedTime, timeInUSec );
- #else
- PR_ExplodeTime(timeInUSec, PR_LocalTimeParameters, &expandedTime);
- #endif /* NSPR20 */
- }
- PR_FormatTimeUSEnglish(small_buf, sizeof(small_buf),
- "NEWGROUPS %y%m%d %H%M%S", &expandedTime);
-
- StrAllocCopy(command, small_buf);
-
- }
- else if(cd->type_wanted == LIST_WANTED)
- {
-
- cd->use_fancy_newsgroup_listing = FALSE;
- if (MSG_NewsgroupsLastUpdatedTime(cd->host))
- {
- cd->next_state = DISPLAY_NEWSGROUPS;
- return(0);
- }
- else
- {
- #ifdef BUG_21013
- if(!FE_Confirm(ce->window_id, XP_GetString(XP_CONFIRM_SAVE_NEWSGROUPS)))
- {
- cd->next_state = NEWS_ERROR;
- return(MK_INTERRUPTED);
- }
- #endif /* BUG_21013 */
-
- if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
- {
- StrAllocCopy(command, "LIST XACTIVE");
- cd->use_fancy_newsgroup_listing = TRUE;
- }
- else
- {
- StrAllocCopy(command, "LIST");
- }
- }
- }
- else if(cd->type_wanted == GROUP_WANTED)
- {
- /* Don't use MKParse because the news: access URL doesn't follow traditional
- * rules. For instance, if the article reference contains a '#',
- * the rest of it is lost.
- */
- char * slash;
-
- StrAllocCopy(command, "GROUP ");
-
- slash = XP_STRCHR(cd->group_name, '/'); /* look for a slash */
- cd->first_art = 0;
- cd->last_art = 0;
- if (slash)
- {
- *slash = '\0';
- #ifdef __alpha
- (void) sscanf(slash+1, "%d-%d", &cd->first_art, &cd->last_art);
- #else
- (void) sscanf(slash+1, "%ld-%ld", &cd->first_art, &cd->last_art);
- #endif
- }
-
- StrAllocCopy (cd->control_con->current_group, cd->group_name);
- StrAllocCat(command, cd->control_con->current_group);
- }
- else if (cd->type_wanted == SEARCH_WANTED)
- {
- if (MSG_QueryNewsExtension(cd->host, "SEARCH"))
- {
- /* use the SEARCH extension */
- char *slash = XP_STRCHR (cd->command_specific_data, '/');
- if (slash)
- {
- char *allocatedCommand = MSG_UnEscapeSearchUrl (slash + 1);
- if (allocatedCommand)
- {
- StrAllocCopy (command, allocatedCommand);
- XP_FREE(allocatedCommand);
- }
- }
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_SEARCH_RESPONSE;
- }
- else
- {
- /* for XPAT, we have to GROUP into the group before searching */
- StrAllocCopy (command, "GROUP ");
- StrAllocCat (command, cd->group_name);
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_XPAT_SEND;
- }
- }
- else if (cd->type_wanted == PRETTY_NAMES_WANTED)
- {
- if (MSG_QueryNewsExtension(cd->host, "LISTPRETTY"))
- {
- cd->next_state = NNTP_LIST_PRETTY_NAMES;
- return 0;
- }
- else
- {
- XP_ASSERT(FALSE);
- cd->next_state = NNTP_ERROR;
- }
- }
- else if (cd->type_wanted == PROFILE_WANTED)
- {
- char *slash = XP_STRCHR (cd->command_specific_data, '/');
- if (slash)
- {
- char *allocatedCommand = MSG_UnEscapeSearchUrl (slash + 1);
- if (allocatedCommand)
- {
- StrAllocCopy (command, allocatedCommand);
- XP_FREE(allocatedCommand);
- }
- }
- cd->next_state = NNTP_RESPONSE;
- if (XP_STRSTR(ce->URL_s->address, "PROFILE NEW"))
- cd->next_state_after_response = NNTP_PROFILE_ADD_RESPONSE;
- else
- cd->next_state_after_response = NNTP_PROFILE_DELETE_RESPONSE;
- }
- else if (cd->type_wanted == IDS_WANTED)
- {
- char *slash = XP_STRCHR(cd->group_name, '/'); /* look for a slash */
- if (slash)
- *slash = '\0';
-
- cd->next_state = NNTP_LIST_GROUP;
- return 0;
- }
- else /* article or cancel */
- {
- if (cd->type_wanted == CANCEL_WANTED)
- StrAllocCopy(command, "HEAD ");
- else
- StrAllocCopy(command, "ARTICLE ");
- if (*cd->path != '<')
- StrAllocCat(command,"<");
- StrAllocCat(command, cd->path);
- if (XP_STRCHR(command+8, '>')==0)
- StrAllocCat(command,">");
- }
-
- StrAllocCat(command, CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket, command, XP_STRLEN(command));
- NNTP_LOG_WRITE(command);
- XP_FREE(command);
-
- cd->next_state = NNTP_RESPONSE;
- if (cd->type_wanted != SEARCH_WANTED && cd->type_wanted != PROFILE_WANTED)
- cd->next_state_after_response = SEND_FIRST_NNTP_COMMAND_RESPONSE;
- cd->pause_for_read = TRUE;
- return(ce->status);
-
- } /* sent first command */
-
-
- /* interprets the server response from the first command sent
- *
- * returns negative if the server responds unexpectedly
- */
- PRIVATE int
- net_send_first_nntp_command_response (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- int major_opcode = cd->response_code/100;
-
- if((major_opcode == 3 && cd->type_wanted == NEWS_POST)
- || (major_opcode == 2 && cd->type_wanted != NEWS_POST) )
- {
-
- cd->next_state = SETUP_NEWS_STREAM;
- cd->some_protocol_succeeded = TRUE;
-
- return(0); /* good */
- }
- else
- {
- if (cd->response_code == 411 && cd->type_wanted == GROUP_WANTED)
- MSG_GroupNotFound(cd->pane, cd->host,
- cd->control_con->current_group, TRUE /* opening group */);
- return net_display_html_error_state(ce);
- }
-
- /* start the graph progress indicator
- */
- FE_GraphProgressInit(ce->window_id, ce->URL_s, ce->URL_s->content_length);
- cd->destroy_graph_progress = TRUE; /* we will need to destroy it */
- cd->original_content_length = ce->URL_s->content_length;
-
- return(ce->status);
- }
-
-
- PRIVATE int
- net_send_group_for_article (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- StrAllocCopy (cd->control_con->current_group, cd->group_name);
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "GROUP %.512s" CRLF,
- cd->control_con->current_group);
-
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,
- XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_SEND_GROUP_FOR_ARTICLE_RESPONSE;
- cd->pause_for_read = TRUE;
-
- return(ce->status);
- }
-
- PRIVATE int
- net_send_group_for_article_response (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- /* ignore the response code and continue
- */
- cd->next_state = NNTP_SEND_ARTICLE_NUMBER;
-
- return(0);
- }
-
-
- PRIVATE int
- net_send_article_number (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "ARTICLE %lu" CRLF,
- cd->article_num);
-
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,
- XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = SEND_FIRST_NNTP_COMMAND_RESPONSE;
- cd->pause_for_read = TRUE;
-
- return(ce->status);
- }
-
-
-
-
- static char *
- news_generate_news_url_fn (const char *dest, void *closure,
- MimeHeaders *headers)
- {
- ActiveEntry *ce = (ActiveEntry *) closure;
- /* NOTE: you can't use NewsConData here, because ce might refer
- to a file in the disk cache rather than an NNTP connection. */
- char *prefix = NET_ParseURL(ce->URL_s->address,
- (GET_PROTOCOL_PART | GET_HOST_PART));
- char *new_dest = NET_Escape (dest, URL_XALPHAS);
- char *result = (char *) XP_ALLOC (XP_STRLEN (prefix) +
- (new_dest ? XP_STRLEN (new_dest) : 0)
- + 40);
- if (result && prefix)
- {
- XP_STRCPY (result, prefix);
- if (prefix[XP_STRLEN(prefix) - 1] != ':')
- /* If there is a host, it must be terminated with a slash. */
- XP_STRCAT (result, "/");
- XP_STRCAT (result, new_dest);
- }
- FREEIF (prefix);
- FREEIF (new_dest);
- return result;
- }
-
- static char *
- news_generate_reference_url_fn (const char *dest, void *closure,
- MimeHeaders *headers)
- {
- return news_generate_news_url_fn (dest, closure, headers);
- }
-
-
-
- /* Initiates the stream and sets state for the transfer
- *
- * returns negative if unable to setup stream
- */
- PRIVATE int
- net_setup_news_stream (ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->type_wanted == NEWS_POST)
- {
- NET_ClearReadSelect(ce->window_id, ce->socket);
- NET_SetConnectSelect(ce->window_id, ce->socket);
- #ifdef XP_WIN
- cd->calling_netlib_all_the_time = TRUE;
- NET_SetCallNetlibAllTheTime(ce->window_id, "mknews");
- #endif /* XP_WIN */
-
- ce->con_sock = ce->socket;
- cd->next_state = NNTP_SEND_POST_DATA;
-
- NET_Progress(ce->window_id, XP_GetString(MK_MSG_DELIV_NEWS));
- }
- else if(cd->type_wanted == LIST_WANTED)
- {
- if (cd->use_fancy_newsgroup_listing)
- cd->next_state = NNTP_LIST_XACTIVE_RESPONSE;
- else
- cd->next_state = NNTP_READ_LIST_BEGIN;
- }
- else if(cd->type_wanted == GROUP_WANTED)
- cd->next_state = NNTP_XOVER_BEGIN;
- else if(cd->type_wanted == NEW_GROUPS)
- cd->next_state = NNTP_NEWGROUPS_BEGIN;
- else if(cd->type_wanted == ARTICLE_WANTED ||
- cd->type_wanted == CANCEL_WANTED)
- cd->next_state = NNTP_BEGIN_ARTICLE;
- else if (cd->type_wanted == SEARCH_WANTED)
- cd->next_state = NNTP_XPAT_SEND;
- else if (cd->type_wanted == PRETTY_NAMES_WANTED)
- cd->next_state = NNTP_LIST_PRETTY_NAMES;
- else if (cd->type_wanted == PROFILE_WANTED)
- {
- if (XP_STRSTR(ce->URL_s->address, "PROFILE NEW"))
- cd->next_state = NNTP_PROFILE_ADD;
- else
- cd->next_state = NNTP_PROFILE_DELETE;
- }
- else
- {
- XP_ASSERT(0);
- return -1;
- }
-
- return(0); /* good */
- }
-
- /* This doesn't actually generate HTML - but it is our hook into the
- message display code, so that we can get some values out of it
- after the headers-to-be-displayed have been parsed.
- */
- static char *
- news_generate_html_header_fn (const char *dest, void *closure,
- MimeHeaders *headers)
- {
- ActiveEntry *ce = (ActiveEntry *) closure;
- /* NOTE: you can't always use NewsConData here if, because ce might
- refer to a file in the disk cache rather than an NNTP connection. */
- NewsConData *cd = 0;
-
- XP_ASSERT(ce->protocol == NEWS_TYPE_URL ||
- ce->protocol == FILE_CACHE_TYPE_URL ||
- ce->protocol == MEMORY_CACHE_TYPE_URL);
- if (ce->protocol == NEWS_TYPE_URL)
- cd = (NewsConData *)ce->con_data;
-
- if (cd && cd->type_wanted == CANCEL_WANTED)
- {
- /* Save these for later (used in NEWS_DO_CANCEL state.) */
- cd->cancel_from =
- MimeHeaders_get(headers, HEADER_FROM, FALSE, FALSE);
- cd->cancel_newsgroups =
- MimeHeaders_get(headers, HEADER_NEWSGROUPS, FALSE, TRUE);
- cd->cancel_distribution =
- MimeHeaders_get(headers, HEADER_DISTRIBUTION, FALSE, FALSE);
- cd->cancel_id =
- MimeHeaders_get(headers, HEADER_MESSAGE_ID, FALSE, FALSE);
- }
- else
- {
- MSG_Pane *messagepane = ce->URL_s->msg_pane;
- if (!messagepane)
- {
- NNTP_LOG_NOTE(("news_generate_html_header_fn: url->msg_pane NULL for URL: %s", ce->URL_s->address));
- messagepane = MSG_FindPane(ce->window_id, MSG_MESSAGEPANE);
- }
- XP_ASSERT (!cd || cd->type_wanted == ARTICLE_WANTED);
-
- if (messagepane)
- MSG_ActivateReplyOptions (messagepane, headers);
- }
- return 0;
- }
-
-
-
- XP_Bool NET_IsNewsMessageURL (const char *url);
-
- int
- net_InitializeNewsFeData (ActiveEntry * ce)
- {
- MimeDisplayOptions *opt;
-
- if (!NET_IsNewsMessageURL (ce->URL_s->address))
- {
- XP_ASSERT(0);
- return -1;
- }
-
- if (ce->URL_s->fe_data)
- {
- XP_ASSERT(0);
- return -1;
- }
-
- opt = XP_NEW (MimeDisplayOptions);
- if (!opt) return MK_OUT_OF_MEMORY;
- XP_MEMSET (opt, 0, sizeof(*opt));
-
- opt->generate_reference_url_fn = news_generate_reference_url_fn;
- opt->generate_news_url_fn = news_generate_news_url_fn;
- opt->generate_header_html_fn = 0;
- opt->generate_post_header_html_fn = news_generate_html_header_fn;
- opt->html_closure = ce;
-
- ce->URL_s->fe_data = opt;
- return 0;
- }
-
-
- PRIVATE int
- net_begin_article(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- if (cd->type_wanted != ARTICLE_WANTED &&
- cd->type_wanted != CANCEL_WANTED)
- return 0;
-
- /* Set up the HTML stream
- */
- FREEIF (ce->URL_s->content_type);
- ce->URL_s->content_type = XP_STRDUP (MESSAGE_RFC822);
-
- #ifdef NO_ARTICLE_CACHEING
- ce->format_out = CLEAR_CACHE_BIT (ce->format_out);
- #endif
-
- if (cd->type_wanted == CANCEL_WANTED)
- {
- XP_ASSERT(ce->format_out == FO_PRESENT);
- ce->format_out = FO_PRESENT;
- }
-
- /* Only put stuff in the fe_data if this URL is going to get
- passed to MIME_MessageConverter(), since that's the only
- thing that knows what to do with this structure. */
- if (CLEAR_CACHE_BIT(ce->format_out) == FO_PRESENT)
- {
- ce->status = net_InitializeNewsFeData (ce);
- if (ce->status < 0)
- {
- /* #### what error message? */
- return ce->status;
- }
- }
-
- cd->stream = NET_StreamBuilder(ce->format_out, ce->URL_s, ce->window_id);
- XP_ASSERT (cd->stream);
- if (!cd->stream) return -1;
-
- cd->next_state = NNTP_READ_ARTICLE;
-
- return 0;
- }
-
-
- PRIVATE int
- net_news_begin_authorize(ActiveEntry * ce)
- {
- char * command = 0;
- NewsConData * cd = (NewsConData *)ce->con_data;
- char * username = 0, * munged_username = 0;
- char * cp;
- static char * last_username=0;
- static char * last_username_hostname=0;
-
- #ifdef CACHE_NEWSGRP_PASSWORD
- /* reuse cached username from newsgroup folder info*/
- if (cd->pane &&
- (!net_news_last_username_probably_valid ||
- (last_username_hostname &&
- strcasecomp(last_username_hostname, cd->control_con->hostname)))) {
- username = SECNAV_UnMungeString(MSG_GetNewsgroupUsername(cd->pane));
- if (username && last_username &&
- !XP_STRCMP (username, last_username) &&
- (cd->previous_response_code == 281 ||
- cd->previous_response_code == 250 ||
- cd->previous_response_code == 211)) {
- FREEIF (username);
- MSG_SetNewsgroupUsername(cd->pane, NULL);
- MSG_SetNewsgroupPassword(cd->pane, NULL);
- }
- }
- #endif
-
- if (cd->pane)
- {
- /* Following a snews://username:password@newhost.domain.com/newsgroup.topic
- * backend calls MSG_Master::FindNewsHost() to locate the folderInfo and setting
- * the username/password to the newsgroup folderInfo
- */
- username = SECNAV_UnMungeString(MSG_GetNewsgroupUsername(cd->pane));
- if (username && *username)
- {
- StrAllocCopy(last_username, username);
- StrAllocCopy(last_username_hostname, cd->control_con->hostname);
- /* use it for only once */
- MSG_SetNewsgroupUsername(cd->pane, NULL);
- }
- else {
- /* empty username; free and clear it so it will work with
- * our logic
- */
- FREEIF(username);
- }
- }
-
- /* If the URL/cd->control_con->hostname contains @ this must be triggered
- * from the bookmark. Use the embed username if we could.
- */
- if ((cp = XP_STRCHR(cd->control_con->hostname, '@')) != NULL)
- {
- /* in this case the username and possibly
- * the password are in the URL
- */
- char * colon;
- *cp = '\0';
-
- colon = XP_STRCHR(cd->control_con->hostname, ':');
- if(colon)
- *colon = '\0';
-
- StrAllocCopy(username, cd->control_con->hostname);
- StrAllocCopy(last_username, cd->control_con->hostname);
- StrAllocCopy(last_username_hostname, cp+1);
-
- *cp = '@';
-
- if(colon)
- *colon = ':';
- }
- /* reuse global saved username if we think it is
- * valid
- */
- if (!username && net_news_last_username_probably_valid)
- {
- if( last_username_hostname &&
- !strcasecomp(last_username_hostname, cd->control_con->hostname) )
- StrAllocCopy(username, last_username);
- else
- net_news_last_username_probably_valid = FALSE;
- }
-
-
- if (!username) {
- username = FE_Prompt(ce->window_id,
- XP_GetString(XP_PROMPT_ENTER_USERNAME),
- username ? username : "");
-
- /* reset net_news_last_username_probably_valid to false */
- net_news_last_username_probably_valid = FALSE;
- if(!username) {
- ce->URL_s->error_msg =
- NET_ExplainErrorDetails( MK_NNTP_AUTH_FAILED, "Aborted by user");
- return(MK_NNTP_AUTH_FAILED);
- }
- else {
- StrAllocCopy(last_username, username);
- StrAllocCopy(last_username_hostname, cd->control_con->hostname);
- }
- }
-
- #ifdef CACHE_NEWSGRP_PASSWORD
- if (cd->pane && !MSG_GetNewsgroupUsername(cd->pane)) {
- munged_username = SECNAV_MungeString(username);
- MSG_SetNewsgroupUsername(cd->pane, munged_username);
- XP_FREEIF(munged_username);
- }
- #endif
-
- StrAllocCopy(command, "AUTHINFO user ");
- StrAllocCat(command, username);
- StrAllocCat(command, CRLF);
-
- ce->status = (int) NET_BlockingWrite(ce->socket, command, XP_STRLEN(command));
- NNTP_LOG_WRITE(command);
-
- FREE(command);
- FREE(username);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_AUTHORIZE_RESPONSE;;
-
- cd->pause_for_read = TRUE;
-
- return ce->status;
- }
-
- PRIVATE int
- net_news_authorize_response(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- static char * last_password = 0;
- static char * last_password_hostname = 0;
-
- if (281 == cd->response_code || 250 == cd->response_code)
- {
- /* successful login */
-
- /* If we're here because the host demanded authentication before we
- * even sent a single command, then jump back to the beginning of everything
- */
- if (!cd->mode_reader_performed)
- cd->next_state = NNTP_SEND_MODE_READER;
- /* If we're here because the host needs pushed authentication, then we
- * should jump back to SEND_LIST_EXTENSIONS
- */
- else if (MSG_GetNewsHostPushAuth(cd->host))
- cd->next_state = SEND_LIST_EXTENSIONS;
- else
- /* Normal authentication */
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
-
- net_news_last_username_probably_valid = TRUE;
- return(0);
- }
- else if (381 == cd->response_code)
- {
- /* password required
- */
- char * command = 0;
- char * password = 0, * munged_password = 0;
- char * cp;
-
- if (cd->pane)
- {
- password = SECNAV_UnMungeString(MSG_GetNewsgroupPassword(cd->pane));
- /* use it only once */
- MSG_SetNewsgroupPassword(cd->pane, NULL);
- }
-
- if (net_news_last_username_probably_valid
- && last_password
- && last_password_hostname
- && !strcasecomp(last_password_hostname, cd->control_con->hostname))
- {
- #ifdef CACHE_NEWSGRP_PASSWORD
- if (cd->pane)
- password = SECNAV_UnMungeString(MSG_GetNewsgroupPassword(cd->pane));
- #else
- StrAllocCopy(password, last_password);
- #endif
- }
- else if ((cp = XP_STRCHR(cd->control_con->hostname, '@')) != NULL)
- {
- /* in this case the username and possibly
- * the password are in the URL
- */
- char * colon;
- *cp = '\0';
-
- colon = XP_STRCHR(cd->control_con->hostname, ':');
- if(colon)
- {
- *colon = '\0';
-
- StrAllocCopy(password, colon+1);
- StrAllocCopy(last_password, colon+1);
- StrAllocCopy(last_password_hostname, cp+1);
-
- *colon = ':';
- }
-
- *cp = '@';
-
- }
- if (!password) {
- password =
- FE_PromptPassword(ce->window_id, XP_GetString(
- XP_PLEASE_ENTER_A_PASSWORD_FOR_NEWS_SERVER_ACCESS ) );
- net_news_last_username_probably_valid = FALSE;
- }
-
- if(!password) {
- ce->URL_s->error_msg =
- NET_ExplainErrorDetails(MK_NNTP_AUTH_FAILED, "Aborted by user");
- return(MK_NNTP_AUTH_FAILED);
- }
- else {
- StrAllocCopy(last_password, password);
- StrAllocCopy(last_password_hostname, cd->control_con->hostname);
- }
-
- #ifdef CACHE_NEWSGRP_PASSWORD
- if (cd->pane && !MSG_GetNewsgroupPassword(cd->pane)) {
- munged_password = SECNAV_MungeString(password);
- MSG_SetNewsgroupPassword(cd->pane, munged_password);
- XP_FREEIF(munged_password);
- }
- #endif
-
- StrAllocCopy(command, "AUTHINFO pass ");
- StrAllocCat(command, password);
- StrAllocCat(command, CRLF);
-
- ce->status = (int) NET_BlockingWrite(ce->socket, command, XP_STRLEN(command));
- NNTP_LOG_WRITE(command);
-
- FREE(command);
- FREE(password);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_PASSWORD_RESPONSE;
- cd->pause_for_read = TRUE;
-
- return ce->status;
- }
- else
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(
- MK_NNTP_AUTH_FAILED,
- cd->response_txt ? cd->response_txt : "");
- #ifdef CACHE_NEWSGRP_PASSWORD
- if (cd->pane)
- MSG_SetNewsgroupUsername(cd->pane, NULL);
- #endif
- net_news_last_username_probably_valid = FALSE;
-
- return(MK_NNTP_AUTH_FAILED);
- }
-
- XP_ASSERT(0); /* should never get here */
- return(-1);
-
- }
-
- PRIVATE int
- net_news_password_response(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (281 == cd->response_code || 250 == cd->response_code)
- {
- /* successful login */
-
- /* If we're here because the host demanded authentication before we
- * even sent a single command, then jump back to the beginning of everything
- */
- if (!cd->mode_reader_performed)
- cd->next_state = NNTP_SEND_MODE_READER;
- /* If we're here because the host needs pushed authentication, then we
- * should jump back to SEND_LIST_EXTENSIONS
- */
- else if (MSG_GetNewsHostPushAuth(cd->host))
- cd->next_state = SEND_LIST_EXTENSIONS;
- else
- /* Normal authentication */
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
-
- net_news_last_username_probably_valid = TRUE;
- MSG_ResetXOVER( ce->URL_s->msg_pane, &cd->xover_parse_state );
- return(0);
- }
- else
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(
- MK_NNTP_AUTH_FAILED,
- cd->response_txt ? cd->response_txt : "");
- #ifdef CACHE_NEWSGRP_PASSWORD
- if (cd->pane)
- MSG_SetNewsgroupPassword(cd->pane, NULL);
- #endif
- return(MK_NNTP_AUTH_FAILED);
- }
-
- XP_ASSERT(0); /* should never get here */
- return(-1);
- }
-
- PRIVATE int
- net_display_newsgroups (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- cd->next_state = NEWS_DONE;
- cd->pause_for_read = FALSE;
-
- NNTP_LOG_NOTE(("about to display newsgroups. path: %s",cd->path));
-
- #if 0
- /* #### Now ignoring "news:alt.fan.*"
- Need to open the root tree of the default news host and keep
- opening one child at each level until we've exhausted the
- wildcard...
- */
- if(rv < 0)
- return(rv);
- else
- #endif
- return(MK_DATA_LOADED); /* all finished */
- }
-
- PRIVATE int
- net_newgroups_begin (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- cd->next_state = NNTP_NEWGROUPS;
- NET_Progress(ce->window_id, XP_GetString(XP_PROGRESS_RECEIVE_NEWSGROUP));
-
- ce->bytes_received = 0;
-
- return(ce->status);
-
- }
-
- PRIVATE int
- net_process_newgroups (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- char *line, *s, *s1, *s2, *flag;
- int32 oldest, youngest;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if(!line)
- return(ce->status); /* no line yet */
-
- if(ce->status<0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
-
- /* return TCP error
- */
- return MK_TCP_READ_ERROR;
- }
-
- /* End of list?
- */
- if (line[0]=='.' && line[1]=='\0')
- {
- cd->pause_for_read = FALSE;
- if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
- {
- cd->group_name = MSG_GetFirstGroupNeedingExtraInfo(cd->host);
- if (cd->group_name)
- {
- cd->next_state = NNTP_LIST_XACTIVE;
- #ifdef DEBUG_bienvenu
- XP_Trace("listing xactive for %s\n", cd->group_name);
- #endif
- return 0;
- }
- }
- cd->next_state = NEWS_DONE;
-
- if(ce->bytes_received == 0)
- {
- /* #### no new groups */
- }
-
- NET_SortNewsgroups(cd->control_con->hostname, cd->control_con->secure);
- NET_SaveNewsgroupsToDisk(cd->control_con->hostname, cd->control_con->secure);
- if(ce->status > 0)
- return MK_DATA_LOADED;
- else
- return ce->status;
- }
- else if (line [0] == '.' && line [1] == '.')
- /* The NNTP server quotes all lines beginning with "." by doubling it. */
- line++;
-
- /* almost correct
- */
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- FE_GraphProgress(ce->window_id, ce->URL_s, ce->bytes_received, ce->status, ce->URL_s->content_length);
- }
-
- /* format is "rec.arts.movies.past-films 7302 7119 y"
- */
- s = XP_STRCHR (line, ' ');
- if (s)
- {
- *s = 0;
- s1 = s+1;
- s = XP_STRCHR (s1, ' ');
- if (s)
- {
- *s = 0;
- s2 = s+1;
- s = XP_STRCHR (s2, ' ');
- if (s)
- {
- *s = 0;
- flag = s+1;
- }
- }
- }
- youngest = s2 ? atol(s1) : 0;
- oldest = s1 ? atol(s2) : 0;
-
- ce->bytes_received++; /* small numbers of groups never seem
- * to trigger this
- */
-
- MSG_AddNewNewsGroup(ce->URL_s->msg_pane, cd->host,
- line, oldest, youngest, flag, FALSE);
- if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
- {
- MSG_SetGroupNeedsExtraInfo(cd->host, line, TRUE);
- }
- return(ce->status);
- }
-
-
- /* Ahhh, this like print's out the headers and stuff
- *
- * always returns 0
- */
- PRIVATE int
- net_read_news_list_begin (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- cd->next_state = NNTP_READ_LIST;
-
- NET_Progress(ce->window_id, XP_GetString(XP_PROGRESS_RECEIVE_NEWSGROUP));
-
- return(ce->status);
-
-
- }
-
- /* display a list of all or part of the newsgroups list
- * from the news server
- */
- PRIVATE int
- net_read_news_list (ActiveEntry *ce)
- {
- char * line;
- char * description;
- int i=0;
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*) &cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if(!line)
- return(ce->status); /* no line yet */
-
- if(ce->status<0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
-
- /* return TCP error
- */
- return MK_TCP_READ_ERROR;
- }
-
- /* End of list? */
- if (line[0]=='.' && line[1]=='\0')
- {
- if (MSG_QueryNewsExtension(cd->host, "LISTPNAMES"))
- {
- cd->next_state = NNTP_LIST_PRETTY_NAMES;
- }
- else
- {
- cd->next_state = DISPLAY_NEWSGROUPS;
- }
- cd->pause_for_read = FALSE;
-
- NET_SortNewsgroups(cd->control_con->hostname, cd->control_con->secure);
- NET_SaveNewsgroupsToDisk(cd->control_con->hostname, cd->control_con->secure);
- return 0;
- }
- else if (line [0] == '.' && line [1] == '.')
- /* The NNTP server quotes all lines beginning with "." by doubling it. */
- line++;
-
- /* almost correct
- */
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- FE_GraphProgress(ce->window_id, ce->URL_s, ce->bytes_received, ce->status, ce->URL_s->content_length);
- }
-
- /* find whitespace seperator if it exits */
- for(i=0; line[i] != '\0' && !XP_IS_SPACE(line[i]); i++)
- ; /* null body */
-
- if(line[i] == '\0')
- description = &line[i];
- else
- description = &line[i+1];
-
- line[i] = 0; /* terminate group name */
-
- /* store all the group names
- */
- MSG_AddNewNewsGroup(ce->URL_s->msg_pane, cd->host,
- line, 0, 0, "", FALSE);
-
-
- return(ce->status);
- }
-
-
-
-
- /* start the xover command
- */
- PRIVATE int
- net_read_xover_begin (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- int32 count; /* Response fields */
-
- /* Make sure we never close and automatically reopen the connection at this
- point; we'll confuse libmsg too much... */
-
- cd->some_protocol_succeeded = TRUE;
-
- /* We have just issued a GROUP command and read the response.
- Now parse that response to help decide which articles to request
- xover data for.
- */
- sscanf(cd->response_txt,
- #ifdef __alpha
- "%d %d %d",
- #else
- "%ld %ld %ld",
- #endif
- &count,
- &cd->first_possible_art,
- &cd->last_possible_art);
-
- /* We now know there is a summary line there; make sure it has the
- right numbers in it. */
- ce->status = MSG_DisplaySubscribedGroup(cd->pane,
- cd->host,
- cd->group_name,
- cd->first_possible_art,
- cd->last_possible_art,
- count, TRUE);
- if (ce->status < 0) return ce->status;
-
- cd->num_loaded = 0;
- cd->num_wanted = net_NewsChunkSize > 0 ? net_NewsChunkSize : 1L << 30;
-
- cd->next_state = NNTP_FIGURE_NEXT_CHUNK;
- cd->pause_for_read = FALSE;
- return 0;
- }
-
-
-
- PRIVATE int
- net_figure_next_chunk(ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- XP_Bool secure_p = (ce->URL_s->address[0] == 's' ||
- ce->URL_s->address[0] == 'S');
- char *host_and_port = NET_ParseURL (ce->URL_s->address, GET_HOST_PART);
-
- if (!host_and_port) return MK_OUT_OF_MEMORY;
-
- if (cd->first_art > 0) {
- ce->status = MSG_AddToKnownArticles(cd->pane, cd->host,
- cd->group_name,
- cd->first_art, cd->last_art);
- if (ce->status < 0) {
- FREEIF (host_and_port);
- return ce->status;
- }
- }
-
-
- if (cd->num_loaded >= cd->num_wanted) {
- FREEIF (host_and_port);
- cd->next_state = NEWS_PROCESS_XOVER;
- cd->pause_for_read = FALSE;
- return 0;
- }
-
-
- ce->status = MSG_GetRangeOfArtsToDownload(cd->pane,
- &cd->xover_parse_state,
- cd->host,
- cd->group_name,
- cd->first_possible_art,
- cd->last_possible_art,
- cd->num_wanted - cd->num_loaded,
- &(cd->first_art),
- &(cd->last_art));
-
- if (ce->status < 0) {
- FREEIF (host_and_port);
- return ce->status;
- }
-
-
- if (cd->first_art <= 0 || cd->first_art > cd->last_art) {
- /* Nothing more to get. */
- FREEIF (host_and_port);
- cd->next_state = NEWS_PROCESS_XOVER;
- cd->pause_for_read = FALSE;
- return 0;
- }
-
- NNTP_LOG_NOTE((" Chunk will be (%ld-%ld)", cd->first_art, cd->last_art));
-
- cd->article_num = cd->first_art;
- ce->status = MSG_InitXOVER (cd->pane,
- cd->host, cd->group_name,
- cd->first_art, cd->last_art,
- cd->first_possible_art, cd->last_possible_art,
- &cd->xover_parse_state);
- FREEIF (host_and_port);
-
- if (ce->status < 0) {
- return ce->status;
- }
-
- cd->pause_for_read = FALSE;
- if (cd->control_con->no_xover) cd->next_state = NNTP_READ_GROUP;
- else cd->next_state = NNTP_XOVER_SEND;
-
- return 0;
- }
-
- PRIVATE int
- net_xover_send (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "XOVER %ld-%ld" CRLF,
- cd->first_art,
- cd->last_art);
-
- /* printf("XOVER %ld-%ld\n", cd->first_art, cd->last_art); */
-
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_XOVER_RESPONSE;
- cd->pause_for_read = TRUE;
-
- NET_Progress(ce->window_id, XP_GetString(XP_PROGRESS_RECEIVE_LISTARTICLES));
-
- return((int) NET_BlockingWrite(ce->socket,
- cd->output_buffer,
- XP_STRLEN(cd->output_buffer)));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- }
-
- /* see if the xover response is going to return us data
- * if the proper code isn't returned then assume xover
- * isn't supported and use
- * normal read_group
- */
- PRIVATE int
- net_read_xover_response (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- #ifdef TEST_NO_XOVER_SUPPORT
- cd->response_code = 500; /* pretend XOVER generated an error */
- #endif
-
- if(cd->response_code != 224)
- {
- /* If we didn't get back "224 data follows" from the XOVER request,
- then that must mean that this server doesn't support XOVER. Or
- maybe the server's XOVER support is busted or something. So,
- in that case, fall back to the very slow HEAD method.
-
- But, while debugging here at HQ, getting into this state means
- something went very wrong, since our servers do XOVER. Thus
- the assert.
- */
- /*XP_ASSERT (0);*/
- cd->next_state = NNTP_READ_GROUP;
- cd->control_con->no_xover = TRUE;
- }
- else
- {
- cd->next_state = NNTP_XOVER;
- }
-
- return(0); /* continue */
- }
-
- /* process the xover list as it comes from the server
- * and load it into the sort list.
- */
- PRIVATE int
- net_read_xover (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- char *line;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- NNTP_LOG_NOTE(("received unexpected TCP EOF!!!! aborting!"));
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if(!line)
- {
- return(ce->status); /* no line yet or TCP error */
- }
-
- if(ce->status<0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR,
- SOCKET_ERRNO);
-
- /* return TCP error
- */
- return MK_TCP_READ_ERROR;
- }
-
- if(line[0] == '.' && line[1] == '\0')
- {
- cd->next_state = NNTP_FIGURE_NEXT_CHUNK;
- cd->pause_for_read = FALSE;
- return(0);
- }
- else if (line [0] == '.' && line [1] == '.')
- /* The NNTP server quotes all lines beginning with "." by doubling it. */
- line++;
-
- /* almost correct
- */
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- /* FE_GraphProgress(ce->window_id, ce->URL_s, ce->bytes_received, ce->status,
- ce->URL_s->content_length);
- */
- }
-
- ce->status = MSG_ProcessXOVER (cd->pane, line, &cd->xover_parse_state);
-
- cd->num_loaded++;
-
- return ce->status; /* keep going */
- }
-
-
- /* Finished processing all the XOVER data.
- */
- PRIVATE int
- net_process_xover (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
-
- /* if (cd->xover_parse_state) { ### dmb - we need a different check */
- ce->status = MSG_FinishXOVER (cd->pane, &cd->xover_parse_state, 0);
- XP_ASSERT (!cd->xover_parse_state);
- if (ce->status < 0) return ce->status;
-
- cd->next_state = NEWS_DONE;
-
- return(MK_DATA_LOADED);
- }
-
-
- PRIVATE int net_profile_add (ActiveEntry *ce)
- {
- #if 0
- NewsConData *cd = (NewsConData*) ce->con_data;
- char *slash = XP_STRRCHR(ce->URL_s->address, '/');
- if (slash)
- {
- XP_STRCPY (cd->output_buffer, slash + 1);
- XP_STRCAT (cd->output_buffer, CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_PROFILE_ADD_RESPONSE;
- cd->pause_for_read = TRUE;
- }
- else
- {
- cd->next_state = NNTP_ERROR;
- ce->status = -1;
- }
-
- return ce->status;
- #else
- XP_ASSERT(FALSE);
- return -1;
- #endif
- }
-
- PRIVATE int net_profile_add_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- if (cd->response_code >= 200 && cd->response_code <= 299)
- {
- MSG_AddProfileGroup (cd->pane, cd->host, cd->response_txt);
- cd->next_state = NEWS_DONE;
- }
- else
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
-
- return ce->status;
- }
-
- PRIVATE int net_profile_delete (ActiveEntry *ce)
- {
- #if 0
- NewsConData *cd = (NewsConData*) ce->con_data;
- char *slash = XP_STRRCHR(ce->URL_s->address, '/');
- if (slash)
- {
- XP_STRCPY (cd->output_buffer, slash + 1);
- XP_STRCAT (cd->output_buffer, CRLF);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_PROFILE_DELETE_RESPONSE;
- cd->pause_for_read = TRUE;
- }
- else
- {
- cd->next_state = NNTP_ERROR;
- ce->status = -1;
- }
-
- return ce->status;
- #else
- XP_ASSERT(FALSE);
- return -1;
- #endif
- }
-
- PRIVATE int net_profile_delete_response (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- if (cd->response_code >= 200 && cd->response_code <= 299)
- cd->next_state = NEWS_DONE;
- else
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
-
- return ce->status;
- }
-
- PRIVATE
- int
- net_read_news_group (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if(cd->article_num > cd->last_art)
- { /* end of groups */
-
- cd->next_state = NNTP_FIGURE_NEXT_CHUNK;
- cd->pause_for_read = FALSE;
- return(0);
- }
- else
- {
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "HEAD %ld" CRLF,
- cd->article_num++);
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_READ_GROUP_RESPONSE;
-
- cd->pause_for_read = TRUE;
-
- NNTP_LOG_WRITE(cd->output_buffer);
- return((int) NET_BlockingWrite(ce->socket, cd->output_buffer, XP_STRLEN(cd->output_buffer)));
- }
- }
-
- /* See if the "HEAD" command was successful
- */
- PRIVATE int
- net_read_news_group_response (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->response_code == 221)
- { /* Head follows - parse it:*/
- cd->next_state = NNTP_READ_GROUP_BODY;
-
- if(cd->message_id)
- *cd->message_id = '\0';
-
- /* Give the message number to the header parser. */
- return MSG_ProcessNonXOVER (cd->pane, cd->response_txt,
- &cd->xover_parse_state);
- }
- else
- {
- NNTP_LOG_NOTE(("Bad group header found!"));
- cd->next_state = NNTP_READ_GROUP;
- return(0);
- }
- }
-
- /* read the body of the "HEAD" command
- */
- PRIVATE int
- net_read_news_group_body (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
- char *line;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- /* if TCP error of if there is not a full line yet return
- */
- if(!line)
- return ce->status;
-
- if(ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
-
- /* return TCP error
- */
- return MK_TCP_READ_ERROR;
- }
-
- NNTP_LOG_NOTE(("read_group_body: got line: %s|",line));
-
- /* End of body? */
- if (line[0]=='.' && line[1]=='\0')
- {
- cd->next_state = NNTP_READ_GROUP;
- cd->pause_for_read = FALSE;
- }
- else if (line [0] == '.' && line [1] == '.')
- /* The NNTP server quotes all lines beginning with "." by doubling it. */
- line++;
-
- return MSG_ProcessNonXOVER (cd->pane, line, &cd->xover_parse_state);
- }
-
-
- PRIVATE int
- net_send_news_post_data(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *) ce->con_data;
-
- /* returns 0 on done and negative on error
- * positive if it needs to continue.
- */
- ce->status = NET_WritePostData(ce->window_id, ce->URL_s,
- ce->socket,
- &cd->write_post_data_data,
- TRUE);
-
- cd->pause_for_read = TRUE;
-
- if(ce->status == 0)
- {
- /* normal done
- */
- XP_STRCPY(cd->output_buffer, CRLF "." CRLF);
- NNTP_LOG_WRITE(cd->output_buffer);
- ce->status = (int) NET_BlockingWrite(ce->socket,
- cd->output_buffer,
- XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- NET_Progress(ce->window_id,
- XP_GetString(XP_MESSAGE_SENT_WAITING_NEWS_REPLY));
-
- NET_ClearConnectSelect(ce->window_id, ce->socket);
- #ifdef XP_WIN
- if(cd->calling_netlib_all_the_time)
- {
- cd->calling_netlib_all_the_time = FALSE;
- NET_ClearCallNetlibAllTheTime(ce->window_id, "mknews");
- }
- #endif
- NET_SetReadSelect(ce->window_id, ce->socket);
- ce->con_sock = 0;
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_SEND_POST_DATA_RESPONSE;
- return(0);
- }
-
- return(ce->status);
-
- }
-
-
- /* interpret the response code from the server
- * after the post is done
- */
- PRIVATE int
- net_send_news_post_data_response(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *) ce->con_data;
-
-
- if (cd->response_code != 240) {
- ce->URL_s->error_msg =
- NET_ExplainErrorDetails(MK_NNTP_ERROR_MESSAGE,
- cd->response_txt ? cd->response_txt : "");
- if (cd->response_code == 441
- && MSG_GetPaneType(cd->pane) == MSG_COMPOSITIONPANE
- && MSG_IsDuplicatePost(cd->pane) &&
- MSG_GetCompositionMessageID(cd->pane)) {
- /* The news server won't let us post. We suspect that we're submitting
- a duplicate post, and that's why it's failing. So, let's go see
- if there really is a message out there with the same message-id.
- If so, we'll just silently pretend everything went well. */
- PR_snprintf(cd->output_buffer, OUTPUT_BUFFER_SIZE, "STAT %s" CRLF,
- MSG_GetCompositionMessageID(cd->pane));
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_CHECK_FOR_MESSAGE;
- NNTP_LOG_WRITE(cd->output_buffer);
- return (int) NET_BlockingWrite(ce->socket, cd->output_buffer,
- XP_STRLEN(cd->output_buffer));
- }
-
- MSG_ClearCompositionMessageID(cd->pane); /* So that if the user tries
- to just post again, we
- won't immediately decide
- that this was a duplicate
- message and ignore the
- error. */
- cd->next_state = NEWS_ERROR;
- return(MK_NNTP_ERROR_MESSAGE);
- }
- cd->next_state = NEWS_ERROR; /* even though it worked */
- cd->pause_for_read = FALSE;
- return(MK_DATA_LOADED);
- }
-
-
- PRIVATE int
- net_check_for_message(ActiveEntry* ce)
- {
- NewsConData * cd = (NewsConData *) ce->con_data;
-
- cd->next_state = NEWS_ERROR;
- if (cd->response_code >= 220 && cd->response_code <= 223) {
- /* Yes, this article is already there, we're all done. */
- return MK_DATA_LOADED;
- } else {
- /* The article isn't there, so the failure we had earlier wasn't due to
- a duplicate message-id. Return the error from that previous
- posting attempt (which is already in ce->URL_s->error_msg). */
- MSG_ClearCompositionMessageID(cd->pane);
- return MK_NNTP_ERROR_MESSAGE;
- }
- }
-
- PRIVATE int
- net_DisplayNewsRC(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *) ce->con_data;
-
- if(!cd->newsrc_performed)
- {
- cd->newsrc_performed = TRUE;
-
- cd->newsrc_list_count = MSG_GetNewsRCCount(cd->pane, cd->host);
- }
-
-
-
- FREEIF(cd->control_con->current_group);
- cd->control_con->current_group = MSG_GetNewsRCGroup(cd->pane, cd->host);
-
-
- if(cd->control_con->current_group)
- {
- /* send group command to server
- */
- int32 percent;
- char *statusText;
-
- PR_snprintf(NET_Socket_Buffer, OUTPUT_BUFFER_SIZE, "GROUP %.512s" CRLF,
- cd->control_con->current_group);
- ce->status = (int) NET_BlockingWrite(ce->socket, NET_Socket_Buffer,
- XP_STRLEN(NET_Socket_Buffer));
- NNTP_LOG_WRITE(NET_Socket_Buffer);
-
- percent = (int32) (100 * (((double) cd->newsrc_list_index) /
- ((double) cd->newsrc_list_count)));
- FE_SetProgressBarPercent (ce->window_id, percent);
- statusText = PR_smprintf (XP_GetString(XP_PROGRESS_READ_NEWSGROUP_COUNTS),
- (long) cd->newsrc_list_index, (long) cd->newsrc_list_count);
- if (statusText)
- {
- FE_Progress (ce->window_id, statusText);
- XP_FREE(statusText);
- }
-
- cd->newsrc_list_index++;
-
- cd->pause_for_read = TRUE;
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NEWS_DISPLAY_NEWS_RC_RESPONSE;
- }
- else
- {
- if (cd->newsrc_list_count)
- {
- FE_SetProgressBarPercent (ce->window_id, -1);
- cd->newsrc_list_count = 0;
- }
- else if (cd->response_code == 215)
- {
- /*
- * 5-9-96 jefft
- * If for some reason the news server returns an empty
- * newsgroups list with a nntp response code 215 -- list of
- * newsgroups follows. We set ce->status to MK_EMPTY_NEWS_LIST
- * to end the infinite dialog loop.
- */
- ce->status = MK_EMPTY_NEWS_LIST;
- }
- cd->next_state = NEWS_DONE;
-
- if(ce->status > -1)
- return MK_DATA_LOADED;
- else
- return(ce->status);
- }
-
- return(ce->status); /* keep going */
-
- }
-
- /* Parses output of GROUP command */
- PRIVATE int
- net_DisplayNewsRCResponse(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *) ce->con_data;
-
- if(cd->response_code == 211)
- {
- char *num_arts = 0, *low = 0, *high = 0, *group = 0;
- int32 first_art, last_art;
-
- /* line looks like:
- * 211 91 3693 3789 comp.infosystems
- */
-
- num_arts = cd->response_txt;
- low = XP_STRCHR(num_arts, ' ');
-
- if(low)
- {
- first_art = atol(low);
- *low++ = '\0';
- high= XP_STRCHR(low, ' ');
- }
- if(high)
- {
- *high++ = '\0';
- group = XP_STRCHR(high, ' ');
- }
- if(group)
- {
- *group++ = '\0';
- /* the group name may be contaminated by "group selected" at
- the end. This will be space separated from the group name.
- If a space is found in the group name terminate at that
- point. */
- XP_STRTOK(group, " ");
- last_art = atol(high);
- }
-
- ce->status = MSG_DisplaySubscribedGroup(cd->pane,
- cd->host,
- group,
- low ? atol(low) : 0,
- high ? atol(high) : 0,
- atol(num_arts), FALSE);
- if (ce->status < 0)
- return ce->status;
- }
- else if (cd->response_code == 411)
- {
- MSG_GroupNotFound(cd->pane, cd->host, cd->control_con->current_group, FALSE);
- }
- /* it turns out subscribe ui depends on getting this displaysubscribedgroup call,
- even if there was an error.
- */
- if(cd->response_code != 211)
- {
- /* only on news server error or when zero articles
- */
- ce->status = MSG_DisplaySubscribedGroup(cd->pane,
- cd->host,
- cd->control_con->current_group,
- 0, 0, 0, FALSE);
-
- }
-
- cd->next_state = NEWS_DISPLAY_NEWS_RC;
-
- return 0;
- }
-
-
- PRIVATE int
- net_NewsRCProcessPost(ActiveEntry *ce)
- {
- return(0);
- }
-
-
-
- static void
- net_cancel_done_cb (MWContext *context, void *data, int status,
- const char *file_name)
- {
- ActiveEntry *ce = (ActiveEntry *) data;
- NewsConData *cd = (NewsConData *) ce->con_data;
- cd->cancel_status = status;
- XP_ASSERT(status < 0 || file_name);
- cd->cancel_msg_file = (status < 0 ? 0 : XP_STRDUP(file_name));
- }
-
-
- static int
- net_start_cancel (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData *) ce->con_data;
- char *command = "POST" CRLF;
-
- ce->status = (int) NET_BlockingWrite(ce->socket, command, XP_STRLEN(command));
- NNTP_LOG_WRITE(command);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NEWS_DO_CANCEL;
- cd->pause_for_read = TRUE;
- return (ce->status);
- }
-
-
- static int
- net_do_cancel (ActiveEntry *ce)
- {
- int status = 0;
- NewsConData *cd = (NewsConData *) ce->con_data;
- char *id, *subject, *newsgroups, *distribution, *other_random_headers, *body;
- char *from, *old_from, *news_url;
- int L;
- MSG_CompositionFields *fields = NULL;
-
-
- /* #### Should we do a more real check than this? If the POST command
- didn't respond with "340 Ok", then it's not ready for us to throw a
- message at it... But the normal posting code doesn't do this check.
- Why?
- */
- XP_ASSERT (cd->response_code == 340);
-
- /* These shouldn't be set yet, since the headers haven't been "flushed" */
- XP_ASSERT (!cd->cancel_id &&
- !cd->cancel_from &&
- !cd->cancel_newsgroups &&
- !cd->cancel_distribution);
-
- /* Write out a blank line. This will tell mimehtml.c that the headers
- are done, and it will call news_generate_html_header_fn which will
- notice the fields we're interested in.
- */
- XP_STRCPY (cd->output_buffer, CRLF); /* CRLF used to be LINEBREAK.
- LINEBREAK is platform dependent
- and is only <CR> on a mac. This
- CRLF is the protocol delimiter
- and not platform dependent -km */
- ce->status = PUTSTRING(cd->output_buffer);
- if (ce->status < 0) return ce->status;
-
- /* Now news_generate_html_header_fn should have been called, and these
- should have values. */
- id = cd->cancel_id;
- old_from = cd->cancel_from;
- newsgroups = cd->cancel_newsgroups;
- distribution = cd->cancel_distribution;
-
- XP_ASSERT (id && newsgroups);
- if (!id || !newsgroups) return -1; /* "unknown error"... */
-
- cd->cancel_newsgroups = 0;
- cd->cancel_distribution = 0;
- cd->cancel_from = 0;
- cd->cancel_id = 0;
-
- L = XP_STRLEN (id);
-
- from = MIME_MakeFromField ();
- subject = (char *) XP_ALLOC (L + 20);
- other_random_headers = (char *) XP_ALLOC (L + 20);
- body = (char *) XP_ALLOC (XP_STRLEN (XP_AppCodeName) + 100);
-
- /* Make sure that this loser isn't cancelling someone else's posting.
- Yes, there are occasionally good reasons to do so. Those people
- capable of making that decision (news admins) have other tools with
- which to cancel postings (like telnet.)
- Don't do this if server tells us it will validate user. DMB 3/19/97
- */
- if (!MSG_QueryNewsExtension(cd->host, "CANCELCHK"))
- {
- char *us = MSG_ExtractRFC822AddressMailboxes (from);
- char *them = MSG_ExtractRFC822AddressMailboxes (old_from);
- XP_Bool ok = (us && them && !strcasecomp (us, them));
- FREEIF(us);
- FREEIF(them);
- if (!ok)
- {
- status = MK_NNTP_CANCEL_DISALLOWED;
- ce->URL_s->error_msg = XP_STRDUP (XP_GetString(status));
- cd->next_state = NEWS_ERROR; /* even though it worked */
- cd->pause_for_read = FALSE;
- goto FAIL;
- }
- }
-
- /* Last chance to cancel the cancel.
- */
- if (!FE_Confirm (ce->window_id, XP_GetString(MK_NNTP_CANCEL_CONFIRM)))
- {
- status = MK_NNTP_NOT_CANCELLED;
- goto FAIL;
- }
-
- news_url = ce->URL_s->address; /* we can just post here. */
-
- if (!from || !subject || !other_random_headers || !body)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
-
- XP_STRCPY (subject, "cancel ");
- XP_STRCAT (subject, id);
-
- XP_STRCPY (other_random_headers, "Control: cancel ");
- XP_STRCAT (other_random_headers, id);
- XP_STRCAT (other_random_headers, CRLF);
- if (distribution)
- {
- XP_STRCAT (other_random_headers, "Distribution: ");
- XP_STRCAT (other_random_headers, distribution);
- XP_STRCAT (other_random_headers, CRLF);
- }
-
- XP_STRCPY (body, "This message was cancelled from within ");
- XP_STRCAT (body, XP_AppCodeName);
- XP_STRCAT (body, "." CRLF);
-
- /* #### Would it be a good idea to S/MIME-sign all "cancel" messages? */
-
- fields = MSG_CreateCompositionFields(from, 0, 0, 0, 0, 0, newsgroups,
- 0, 0, subject, id, other_random_headers,
- 0, 0, news_url,
- FALSE, /* encrypt_p */
- FALSE /* sign_p */
- );
- if (!fields)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
- MSG_SetCompFieldsBoolHeader(fields, MSG_ENCRYPTED_BOOL_HEADER_MASK, FALSE);
- MSG_SetCompFieldsBoolHeader(fields, MSG_SIGNED_BOOL_HEADER_MASK, FALSE);
-
- cd->cancel_status = 0;
- MSG_StartMessageDelivery (cd->pane, (void *) ce,
- fields,
- FALSE, /* digest_p */
- TRUE, /* dont_deliver_p */
- TEXT_PLAIN, body, XP_STRLEN (body),
- 0, /* other attachments */
- NULL, /* multipart/related chunk */
- net_cancel_done_cb);
-
- /* Since there are no attachments, MSG_StartMessageDelivery will run
- net_cancel_done_cb right away (it will be called before the return.) */
-
- if (!cd->cancel_msg_file)
- {
- status = cd->cancel_status;
- XP_ASSERT (status < 0);
- if (status >= 0) status = -1;
- goto FAIL;
- }
-
- /* Now send the data - do it blocking, who cares; the message is known
- to be very small. First suck the whole file into memory. Then delete
- the file. Then do a blocking write of the data.
-
- (We could use file-posting, maybe, but I couldn't figure out how.)
- */
- {
- char *data;
- uint32 data_size, data_fp;
- XP_StatStruct st;
- int nread = 0;
- XP_File file = XP_FileOpen (cd->cancel_msg_file,
- xpFileToPost, XP_FILE_READ);
- if (! file) return -1; /* "unknown error"... */
- XP_Stat (cd->cancel_msg_file, &st, xpFileToPost);
-
- data_fp = 0;
- data_size = st.st_size + 20;
- data = (char *) XP_ALLOC (data_size);
- if (! data)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
-
- while ((nread = XP_FileRead (data + data_fp, data_size - data_fp, file))
- > 0)
- data_fp += nread;
- data [data_fp] = 0;
- XP_FileClose (file);
- XP_FileRemove (cd->cancel_msg_file, xpFileToPost);
-
- XP_STRCAT (data, CRLF "." CRLF CRLF);
- status = NET_BlockingWrite(ce->socket, data, XP_STRLEN(data));
- NNTP_LOG_WRITE(data);
- XP_FREE (data);
- if (status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_WRITE_ERROR,
- status);
- goto FAIL;
- }
-
- cd->pause_for_read = TRUE;
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_SEND_POST_DATA_RESPONSE;
- }
-
- FAIL:
- FREEIF (id);
- FREEIF (from);
- FREEIF (old_from);
- FREEIF (subject);
- FREEIF (newsgroups);
- FREEIF (distribution);
- FREEIF (other_random_headers);
- FREEIF (body);
- FREEIF (cd->cancel_msg_file);
- if (fields)
- MSG_DestroyCompositionFields(fields);
-
- return status;
- }
-
-
- static int net_xpat_send (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData *) ce->con_data;
- int status = 0;
- char *thisTerm = NULL;
-
- if (cd->current_search &&
- (thisTerm = XP_STRCHR(cd->current_search, '/')) != NULL)
- {
- /* extract the XPAT encoding for one query term */
- /* char *next_search = NULL; */
- char *command = NULL;
- char *unescapedCommand = NULL;
- char *endOfTerm = NULL;
- StrAllocCopy (command, ++thisTerm);
- endOfTerm = XP_STRCHR(command, '/');
- if (endOfTerm)
- *endOfTerm = '\0';
- StrAllocCat (command, CRLF);
-
- unescapedCommand = MSG_UnEscapeSearchUrl(command);
-
- /* send one term off to the server */
- NNTP_LOG_WRITE(command);
- status = NET_BlockingWrite(ce->socket, unescapedCommand, XP_STRLEN(unescapedCommand));
- NNTP_LOG_WRITE(unescapedCommand);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_XPAT_RESPONSE;
- cd->pause_for_read = TRUE;
-
- XP_FREE(command);
- XP_FREE(unescapedCommand);
- }
- else
- {
- cd->next_state = NEWS_DONE;
- status = MK_DATA_LOADED;
- }
- return status;
- }
-
- static int net_list_pretty_names(ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "LIST PRETTYNAMES %.512s" CRLF,
- cd->group_name ? cd->group_name : "");
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
- #ifdef DEBUG_bienvenu
- XP_Trace(cd->output_buffer);
- #endif
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LIST_PRETTY_NAMES_RESPONSE;
-
- return ce->status;
- }
-
- static int net_list_pretty_names_response(ActiveEntry *ce)
- {
- char *line;
- char *prettyName;
-
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->response_code != 215)
- {
- cd->next_state = DISPLAY_NEWSGROUPS;
- /* cd->next_state = NEWS_DONE; */
- cd->pause_for_read = FALSE;
- return 0;
- }
-
- ce->status = NET_BufferedReadLine(ce->socket, &line,
- &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
- NNTP_LOG_READ(line);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if (line)
- {
- if (line[0] != '.')
- {
- int i;
- /* find whitespace seperator if it exits */
- for (i=0; line[i] != '\0' && !XP_IS_SPACE(line[i]); i++)
- ; /* null body */
-
- if(line[i] == '\0')
- prettyName = &line[i];
- else
- prettyName = &line[i+1];
-
- line[i] = 0; /* terminate group name */
- if (i > 0)
- MSG_AddPrettyName(cd->host, line, prettyName);
- #ifdef DEBUG_bienvenu
- XP_Trace("adding pretty name %s\n", prettyName);
- #endif
- }
- else
- {
- cd->next_state = DISPLAY_NEWSGROUPS; /* this assumes we were doing a list */
- /* cd->next_state = NEWS_DONE; */ /* ### dmb - don't really know */
- cd->pause_for_read = FALSE;
- return 0;
- }
- }
- return 0;
- }
-
- static int net_list_xactive(ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "LIST XACTIVE %.512s" CRLF,
- cd->group_name);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LIST_XACTIVE_RESPONSE;
-
- return ce->status;
- }
-
-
- static int net_list_xactive_response(ActiveEntry *ce)
- {
- char *line;
-
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- XP_ASSERT(cd->response_code == 215);
- if (cd->response_code != 215)
- {
- cd->next_state = DISPLAY_NEWSGROUPS;
- /* cd->next_state = NEWS_DONE; */
- cd->pause_for_read = FALSE;
- return MK_DATA_LOADED;
- }
-
- ce->status = NET_BufferedReadLine(ce->socket, &line,
- &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
- NNTP_LOG_READ(line);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- /* Bug fix (sfraser) -- show download progress here
- */
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- FE_GraphProgress(ce->window_id, ce->URL_s, ce->bytes_received, ce->status, ce->URL_s->content_length);
- }
-
- if (line)
- {
- if (line[0] != '.')
- {
- char *s = line;
- /* format is "rec.arts.movies.past-films 7302 7119 csp"
- */
- while (*s && !XP_IS_SPACE(*s))
- s++;
- if (s)
- {
- char flags[32]; /* ought to be big enough */
- *s = 0;
- sscanf(s + 1,
- #ifdef __alpha
- "%d %d %31s",
- #else
- "%ld %ld %31s",
- #endif
- &cd->first_possible_art,
- &cd->last_possible_art,
- flags);
- MSG_AddNewNewsGroup(cd->pane, cd->host, line,
- cd->first_possible_art,
- cd->last_possible_art, flags, TRUE /* xactive flags */);
- /* we're either going to list prettynames first, or list all prettynames
- every time, so we won't care so much if it gets interrupted. */
- #ifdef DEBUG_bienvenu
- XP_Trace("got xactive for %s of %s\n", line, flags);
- #endif
- MSG_SetGroupNeedsExtraInfo(cd->host, line, FALSE);
- }
- }
- else
- {
- if (cd->type_wanted == NEW_GROUPS && MSG_QueryNewsExtension(cd->host, "XACTIVE"))
- {
- char *old_group_name = cd->group_name;
- cd->group_name = MSG_GetFirstGroupNeedingExtraInfo(cd->host);
- /* make sure we're not stuck on the same group... */
- if (old_group_name && cd->group_name && XP_STRCMP(old_group_name, cd->group_name))
- {
- XP_FREE(old_group_name);
- #ifdef DEBUG_bienvenu
- XP_Trace("listing xactive for %s\n", cd->group_name);
- #endif
- cd->next_state = NNTP_LIST_XACTIVE;
- cd->pause_for_read = FALSE;
- return 0;
- }
- else
- {
- FREEIF(old_group_name);
- cd->group_name = NULL;
- }
- }
- if (MSG_QueryNewsExtension(cd->host, "LISTPNAMES"))
- cd->next_state = NNTP_LIST_PRETTY_NAMES;
- else
- cd->next_state = DISPLAY_NEWSGROUPS; /* this assumes we were doing a list - who knows? */
- /* cd->next_state = NEWS_DONE; */ /* ### dmb - don't really know */
- cd->pause_for_read = FALSE;
- return 0;
- }
- }
- return 0;
- }
-
- static int net_list_group(ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
- PR_snprintf(cd->output_buffer,
- OUTPUT_BUFFER_SIZE,
- "listgroup %.512s" CRLF,
- cd->group_name);
- MSG_InitAddArticleKeyToGroup(cd->pane, cd->host, cd->group_name,
- &cd->newsgroup_parse_state);
- ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,XP_STRLEN(cd->output_buffer));
- NNTP_LOG_WRITE(cd->output_buffer);
-
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LIST_GROUP_RESPONSE;
-
- return ce->status;
- }
-
- static int net_list_group_response(ActiveEntry *ce)
- {
- char *line;
-
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- XP_ASSERT(cd->response_code == 211);
- if (cd->response_code != 211)
- {
- cd->next_state = NEWS_DONE;
- cd->pause_for_read = FALSE;
- return MK_DATA_LOADED;
- }
-
- ce->status = NET_BufferedReadLine(ce->socket, &line,
- &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
- NNTP_LOG_READ(line);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if (line)
- {
- if (line[0] != '.')
- {
- long found_id = MSG_MESSAGEKEYNONE;
- sscanf(line, "%ld", &found_id);
- MSG_AddArticleKeyToGroup(cd->newsgroup_parse_state, (int32) found_id);
- }
- else
- {
- cd->next_state = NEWS_DONE; /* ### dmb - don't really know */
- cd->pause_for_read = FALSE;
- return 0;
- }
- }
- return 0;
- }
-
- static int net_xpat_response (ActiveEntry *ce)
- {
- char *line;
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->response_code != 221)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_ERROR_MESSAGE, cd->response_txt);
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- return MK_NNTP_SERVER_ERROR;
- }
-
- ce->status = NET_BufferedReadLine(ce->socket, &line,
- &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
- NNTP_LOG_READ(line);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if (line)
- {
- if (line[0] != '.')
- {
- long articleNumber;
- sscanf(line, "%ld", &articleNumber);
- MSG_AddNewsXpatHit (ce->window_id, (uint32) articleNumber);
- }
- else
- {
- /* set up the next term for next time around */
- char *nextTerm = XP_STRCHR(cd->current_search, '/');
- if (nextTerm)
- cd->current_search = ++nextTerm;
- else
- cd->current_search = NULL;
-
- cd->next_state = NNTP_XPAT_SEND;
- cd->pause_for_read = FALSE;
- return 0;
- }
- }
- return 0;
- }
-
-
- PRIVATE int net_nntp_search(ActiveEntry *ce)
- {
- XP_ASSERT(FALSE);
- return 0;
- }
-
- PRIVATE int net_nntp_search_response(ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->response_code >= 200 && cd->response_code <= 299)
- cd->next_state = NNTP_SEARCH_RESULTS;
- else
- cd->next_state = NEWS_DONE;
- cd->pause_for_read = FALSE;
- return 0;
- }
-
- PRIVATE int net_nntp_search_results (ActiveEntry *ce)
- {
- NewsConData *cd = (NewsConData*) ce->con_data;
-
- char *line = NULL;
- ce->status = NET_BufferedReadLine (ce->socket, &line, &cd->data_buf,
- &cd->data_buf_size, (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return MK_NNTP_SERVER_ERROR;
- }
- if (!line)
- return ce->status; /* no line yet */
- if (ce->status < 0)
- {
- ce->URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
- /* return TCP error */
- return MK_TCP_READ_ERROR;
- }
-
- if ('.' != line[0])
- MSG_AddNewsSearchHit (ce->window_id, line);
- else
- {
- /* all overview lines received */
- cd->next_state = NEWS_DONE;
- cd->pause_for_read = FALSE;
- }
-
- return ce->status;
- }
-
- /* The main news load init routine, and URL parser.
- The syntax of news URLs is:
-
- To list all hosts:
- news:
-
- To list all groups on a host, or to post a new message:
- news://HOST
-
- To list some articles in a group:
- news:GROUP
- news:/GROUP
- news://HOST/GROUP
-
- To list a particular range of articles in a group:
- news:GROUP/N1-N2
- news:/GROUP/N1-N2
- news://HOST/GROUP/N1-N2
-
- To retrieve an article:
- news:MESSAGE-ID (message-id must contain "@")
-
- To cancel an article:
- news:MESSAGE-ID?cancel
-
- (Note that message IDs may contain / before the @:)
-
- news:SOME/ID@HOST?headers=all
- news:/SOME/ID@HOST?headers=all
- news:/SOME?ID@HOST?headers=all
- are the same as
- news://HOST/SOME/ID@HOST?headers=all
- news://HOST//SOME/ID@HOST?headers=all
- news://HOST//SOME?ID@HOST?headers=all
- bug: if the ID is <//xxx@host> we will parse this correctly:
- news://non-default-host///xxx@host
- but will mis-parse it if it's on the default host:
- news://xxx@host
- whoever had the idea to leave the <> off the IDs should be flogged.
- So, we'll make sure we quote / in message IDs as %2F.
-
- */
- int
- NET_parse_news_url (const char *url,
- char **host_and_portP,
- XP_Bool *securepP,
- char **groupP,
- char **message_idP,
- char **command_specific_dataP)
- {
- int status = 0;
- XP_Bool secure_p = FALSE;
- char *host_and_port = 0;
- unsigned long port = 0;
- char *group = 0;
- char *message_id = 0;
- char *command_specific_data = 0;
- const char *path_part;
- char *s;
-
- if (url[0] == 's' || url[1] == 'S')
- {
- secure_p = TRUE;
- url++;
- }
-
- host_and_port = NET_ParseURL (url, GET_HOST_PART);
- if (!host_and_port || !*host_and_port)
- {
- char* defhost = NULL;
- int32 defport = 0;
- FREEIF(host_and_port);
- PREF_CopyCharPref("network.hosts.nntp_server", &defhost);
- if (defhost && *defhost == '\0') {
- XP_FREE(defhost);
- defhost = NULL;
- }
- if (defhost) {
- PREF_GetIntPref("news.server_port", &defport);
- if (defport == (secure_p ? SECURE_NEWS_PORT : NEWS_PORT)) {
- defport = 0;
- }
- if (defport) {
- host_and_port = PR_smprintf("%s:%ld", defhost, (long) defport);
- XP_FREE(defhost);
- } else {
- host_and_port = defhost;
- }
- if (!host_and_port) {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
- }
- }
-
- if (!host_and_port)
- {
- status = MK_NO_NEWS_SERVER;
- goto FAIL;
- }
-
- /* If a port was specified, but it was the default port, pretend
- it wasn't specified.
- */
- s = XP_STRCHR (host_and_port, ':');
- if (s && sscanf (s+1, " %lu ", &port) == 1 && port == (secure_p ? SECURE_NEWS_PORT : NEWS_PORT))
- *s = 0;
-
- path_part = XP_STRCHR (url, ':');
- XP_ASSERT (path_part);
- if (!path_part)
- {
- status = -1;
- goto FAIL;
- }
- path_part++;
- if (path_part[0] == '/' && path_part[1] == '/')
- {
- /* Skip over host name. */
- path_part = XP_STRCHR (path_part + 2, '/');
- if (path_part)
- path_part++;
- }
- if (!path_part)
- path_part = "";
-
- group = XP_STRDUP (path_part);
- if (!group)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
-
- NET_UnEscape (group);
-
- /* "group" now holds the part after the host name:
- "message@id?search" or "/group/xxx?search" or "/message?id@xx?search"
-
- If there is an @, this is a message ID; else it is a group.
- Either way, there may be search data at the end.
- */
-
- s = XP_STRCHR (group, '@');
- if (s)
- {
- message_id = group;
- group = 0;
- }
- else if (!*group)
- {
- XP_FREE (group);
- group = 0;
- }
-
- /* At this point, the search data is attached to `message_id' (if there
- is one) or `group' (if there is one) or `host_and_port' (otherwise.)
- Seperate the search data from what it is clinging to, being careful
- to interpret the "?" only if it comes after the "@" in an ID, since
- the syntax of message IDs is tricky. (There may be a ? in the
- random-characters part of the ID (before @), but not in the host part
- (after @).)
- */
- if (message_id || group || host_and_port)
- {
- char *start;
- if (message_id)
- {
- /* Move past the @. */
- XP_ASSERT (s && *s == '@');
- start = s;
- }
- else
- {
- start = group ? group : host_and_port;
- }
-
- /* Take off the "?" or "#" search data */
- for (s = start; *s; s++)
- if (*s == '?' || *s == '#')
- break;
- if (*s)
- {
- command_specific_data = XP_STRDUP (s);
- *s = 0;
- if (!command_specific_data)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
- }
-
- /* Discard any now-empty strings. */
- if (message_id && !*message_id)
- {
- XP_FREE (message_id);
- message_id = 0;
- }
- else if (group && !*group)
- {
- XP_FREE (group);
- group = 0;
- }
- }
-
- FAIL:
- XP_ASSERT (!message_id || message_id != group);
- if (status >= 0)
- {
- *host_and_portP = host_and_port;
- *securepP = secure_p;
- *groupP = group;
- *message_idP = message_id;
- *command_specific_dataP = command_specific_data;
- }
- else
- {
- FREEIF (host_and_port);
- FREEIF (group);
- FREEIF (message_id);
- FREEIF (command_specific_data);
- }
- return status;
- }
-
-
- #if 0
- static void
- test (const char *url)
- {
- char *host_and_port = 0;
- XP_Bool secure_p = FALSE;
- char *group = 0;
- char *message_id = 0;
- char *command_specific_data = 0;
- int status = NET_parse_news_url (url, &host_and_port, &secure_p,
- &group, &message_id, &command_specific_data);
- if (status < 0)
- fprintf (stderr, "%s: status %d\n", url, status);
- else
- {
- fprintf (stderr,
- "%s:\n"
- " host \"%s\", %ssecure,\n"
- " group=\"%s\",\n"
- " id=\"%s\",\n"
- " search=\"%s\"\n\n",
- url,
- (host_and_port ? host_and_port : "(none)"),
- (secure_p ? "" : "in"),
- (group ? group : "(none)"),
- (message_id ? message_id : "(none)"),
- (command_specific_data ? command_specific_data : "(none)"));
- }
- FREEIF (host_and_port);
- FREEIF (group);
- FREEIF (message_id);
- FREEIF (command_specific_data);
- }
-
- static void
- test2 (void)
- {
- test ("news:");
- test ("news:?search");
- test ("news:#anchor");
- test ("news:?search#anchor");
- test ("news:#anchor?search");
- test ("news://HOST");
- test ("news://HOST?search");
- test ("news://HOST#anchor");
- test ("news://HOST?search#anchor");
- test ("news://HOST#anchor?search");
- test ("news://HOST/");
- test ("news://HOST/?search");
- test ("news://HOST/#anchor");
- test ("news://HOST/?search#anchor");
- test ("news://HOST/#anchor?search");
- test ("news:GROUP");
- test ("news:GROUP?search");
- test ("news:GROUP#anchor");
- test ("news:GROUP?search#anchor");
- test ("news:GROUP#anchor?search");
- test ("news:/GROUP");
- test ("news:/GROUP?search");
- test ("news:/GROUP#anchor");
- test ("news:/GROUP?search#anchor");
- test ("news:/GROUP#anchor?search");
- test ("news://HOST/GROUP");
- test ("news://HOST/GROUP?search");
- test ("news://HOST/GROUP#anchor");
- test ("news://HOST/GROUP?search#anchor");
- test ("news://HOST/GROUP#anchor?search");
-
- test ("news:GROUP/N1-N2");
- test ("news:GROUP/N1-N2?search");
- test ("news:GROUP/N1-N2#anchor");
- test ("news:GROUP/N1-N2?search#anchor");
- test ("news:GROUP/N1-N2#anchor?search");
- test ("news:/GROUP/N1-N2");
- test ("news:/GROUP/N1-N2?search");
- test ("news:/GROUP/N1-N2#anchor");
- test ("news:/GROUP/N1-N2?search#anchor");
- test ("news:/GROUP/N1-N2#anchor?search");
-
- test ("news://HOST/GROUP/N1-N2");
- test ("news://HOST/GROUP/N1-N2?search");
- test ("news://HOST/GROUP/N1-N2#anchor");
- test ("news://HOST/GROUP/N1-N2?search#anchor");
- test ("news://HOST/GROUP/N1-N2#anchor?search");
- test ("news:<ID??##??ID@HOST>");
- test ("news:<ID??##??ID@HOST>?search");
- test ("news:<ID??##??ID@HOST>#anchor");
- test ("news:<ID??##??ID@HOST>?search#anchor");
- test ("news:<ID??##??ID@HOST>#anchor?search");
-
- test ("news:<ID/ID/ID??##??ID@HOST>");
- test ("news:<ID/ID/ID??##??ID@HOST>?search");
- test ("news:<ID/ID/ID??##??ID@HOST>#anchor");
- test ("news:<ID/ID/ID??##??ID@HOST>?search#anchor");
- test ("news:<ID/ID/ID??##??ID@HOST>#anchor?search");
- test ("news:</ID/ID/ID??##??ID@HOST>");
- test ("news:</ID/ID/ID??##??ID@HOST>?search");
- test ("news:</ID/ID/ID??##??ID@HOST>#anchor");
- test ("news:</ID/ID/ID??##??ID@HOST>?search#anchor");
- test ("news:</ID/ID/ID??##??ID@HOST>#anchor?search");
-
- test ("news://HOST/<ID??##??ID@HOST>");
- test ("news://HOST/<ID??##??ID@HOST>?search");
- test ("news://HOST/<ID??##??ID@HOST>#anchor");
- test ("news://HOST/<ID??##??ID@HOST>?search#anchor");
- test ("news://HOST/<ID??##??ID@HOST>#anchor?search");
- test ("news://HOST/<ID/ID/ID??##??ID@HOST>");
- test ("news://HOST/<ID/ID/ID??##??ID@HOST>?search");
- test ("news://HOST/<ID/ID/ID??##??ID@HOST>#anchor");
- test ("news://HOST/<ID/ID/ID??##??ID@HOST>?search#anchor");
- test ("news://HOST/<ID/ID/ID??##??ID@HOST>#anchor?search");
-
- test ("news:ID/ID/ID??##??ID@HOST");
- test ("news:ID/ID/ID??##??ID@HOST?search");
- test ("news:ID/ID/ID??##??ID@HOST#anchor");
- test ("news:ID/ID/ID??##??ID@HOST?search#anchor");
- test ("news:ID/ID/ID??##??ID@HOST#anchor?search");
- test ("news:/ID/ID/ID??##??ID@HOST");
- test ("news:/ID/ID/ID??##??ID@HOST?search");
- test ("news:/ID/ID/ID??##??ID@HOST#anchor");
- test ("news:/ID/ID/ID??##??ID@HOST?search#anchor");
- test ("news:/ID/ID/ID??##??ID@HOST#anchor?search");
-
- test ("news://HOST/ID??##??ID@HOST");
- test ("news://HOST/ID??##??ID@HOST?search");
- test ("news://HOST/ID??##??ID@HOST#anchor");
- test ("news://HOST/ID??##??ID@HOST?search#anchor");
- test ("news://HOST/ID??##??ID@HOST#anchor?search");
- test ("news://HOST/ID/ID/ID??##??ID@HOST");
- test ("news://HOST/ID/ID/ID??##??ID@HOST?search");
- test ("news://HOST/ID/ID/ID??##??ID@HOST#anchor");
- test ("news://HOST/ID/ID/ID??##??ID@HOST?search#anchor");
- test ("news://HOST/ID/ID/ID??##??ID@HOST#anchor?search");
- }
- #endif /* 0 */
-
-
- /* Returns true if this URL is a reference to a news message,
- that is, the kind of news URL entity that can be displayed
- in a regular browser window, and doesn't involve all kinds
- of other magic state and callbacks like listing a group.
- */
- XP_Bool
- NET_IsNewsMessageURL (const char *url)
- {
- char *host_and_port = 0;
- XP_Bool secure_p = FALSE;
- char *group = 0;
- char *message_id = 0;
- char *command_specific_data = 0;
- int status = NET_parse_news_url (url, &host_and_port, &secure_p,
- &group, &message_id, &command_specific_data);
- XP_Bool result = FALSE;
- if (status >= 0 && message_id && *message_id)
- result = TRUE;
- FREEIF (host_and_port);
- FREEIF (group);
- FREEIF (message_id);
- FREEIF (command_specific_data);
- return result;
- }
-
- static XP_Bool nntp_are_connections_available (NNTPConnection *conn)
- {
- int connCount = 0;
-
- NNTPConnection *tmpConn;
- XP_List *tmpList = nntp_connection_list;
-
- while ((tmpConn = (NNTPConnection*) XP_ListNextObject(tmpList)) != NULL)
- {
- NNTP_LOG_NOTE(("nntp_are_connections_available: comparing %08lX %s", tmpConn, tmpConn->busy ? "busy" : "available"));
-
- if (conn != tmpConn && tmpConn->busy && !strcasecomp(tmpConn->hostname, conn->hostname))
- connCount++;
- }
-
- return connCount < kMaxConnectionsPerHost;
- }
-
- static XP_Bool isOnline = TRUE;
- static XP_Bool prefInitialized = FALSE;
-
- /* fix Mac warning of missing prototype */
- MODULE_PRIVATE int PR_CALLBACK
- NET_OnlinePrefChangedFunc(const char *pref, void *data);
-
- MODULE_PRIVATE int PR_CALLBACK NET_OnlinePrefChangedFunc(const char *pref, void *data)
- {
- int status;
- int32 port=0;
- char * socksHost = NULL;
- char text[MAXHOSTNAMELEN + 8];
-
- if (!XP_STRCASECMP(pref,"network.online"))
- status = PREF_GetBoolPref("network.online", &isOnline);
-
- if ( isOnline ) {
- CACHE_CloseAllOpenSARCache();
-
- /* If the user wants to use a socks server set it up. */
- if ( (NET_GetProxyStyle() == PROXY_STYLE_MANUAL) ) {
- PREF_CopyCharPref("network.hosts.socks_server",&socksHost);
- PREF_GetIntPref("network.hosts.socks_serverport",&port);
- if (socksHost && *socksHost && port) {
- PR_snprintf(text, sizeof(text), "%s:%d", socksHost, port);
- NET_SetSocksHost(text);
- }
- else {
- NET_SetSocksHost(socksHost); /* NULL is ok */
- }
- }
- }
- else {
- CACHE_OpenAllSARCache();
- }
-
- return status;
- }
-
- /* fix Mac warning of missing prototype */
- MODULE_PRIVATE int PR_CALLBACK
- NET_NewsMaxArticlesChangedFunc(const char *pref, void *data);
-
- MODULE_PRIVATE int PR_CALLBACK NET_NewsMaxArticlesChangedFunc(const char *pref, void *data)
- {
- int status;
- if (!XP_STRCASECMP(pref,"news.max_articles"))
- {
- int32 maxArticles;
-
- status = PREF_GetIntPref("news.max_articles", &maxArticles);
- NET_SetNumberOfNewsArticlesInListing(maxArticles);
- }
- return status;
- }
-
- MODULE_PRIVATE XP_Bool
- NET_IsOffline()
- {
- /* Cache this value, and register a pref callback to
- find out when it changes.
- */
- if (!prefInitialized)
- {
- /*int status =*/ PREF_GetBoolPref("network.online", &isOnline);
- PREF_RegisterCallback("network.online",NET_OnlinePrefChangedFunc, NULL);
- /* because this routine gets called so often, we can register this callback here too. */
- PREF_RegisterCallback("news.max_articles", NET_NewsMaxArticlesChangedFunc, NULL);
- prefInitialized = TRUE;
- }
- return !isOnline;
- }
-
- PRIVATE int32
- net_NewsLoad (ActiveEntry *ce)
- {
- int status = 0;
- NewsConData *cd = XP_NEW(NewsConData);
- XP_Bool secure_p = FALSE;
- XP_Bool default_host = FALSE;
- char *url = ce->URL_s->address;
- char *host_and_port = 0;
- int32 port = 0;
- char *group = 0;
- char *message_id = 0;
- char *command_specific_data = 0;
- XP_Bool cancel_p = FALSE;
- char* colon;
- MSG_NewsHost* defhost = NULL;
- static XP_Bool collabra_enabled = TRUE;
- static XP_Bool got_enabled_pref = FALSE;
-
- if (!got_enabled_pref)
- {
- PREF_GetBoolPref("news.enabled",&collabra_enabled);
- got_enabled_pref = TRUE;
- }
-
- /* fail on protected url types */
- if(ce->protocol == INTERNAL_NEWS_TYPE_URL
- && !ce->URL_s->internal_url)
- {
- status = MK_MALFORMED_URL_ERROR;
- goto FAIL;
- }
-
- if (!collabra_enabled)
- {
- status = MK_MSG_COLLABRA_DISABLED;
- goto FAIL;
- }
-
-
- #ifndef NSPR20
- PR_LogInit (&NNTPLog);
- #endif
-
- if(!cd)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
-
- XP_MEMSET(cd, 0, sizeof(NewsConData));
- ce->URL_s->content_length = 0;
-
- if(!ce->proxy_addr)
- {
- /* look for an HTTPS proxy and use it if available,
- * but the passed in one takes precedence
- */
- StrAllocCopy(ce->proxy_addr,
- NET_FindProxyHostForUrl(SECURE_HTTP_TYPE_URL,
- ce->URL_s->address));
- }
- else
- {
- StrAllocCopy(cd->ssl_proxy_server, ce->proxy_addr);
- }
-
- cd->pane = ce->URL_s->msg_pane;
- if (!cd->pane)
- {
- NNTP_LOG_NOTE(("NET_NewsLoad: url->msg_pane NULL for URL: %s\n", ce->URL_s->address));
- cd->pane = MSG_FindPane(ce->window_id, MSG_ANYPANE);
- }
- XP_ASSERT(cd->pane && MSG_GetContext(cd->pane) == ce->window_id);
- if (!cd->pane) {
- status = -1; /* ### */
- goto FAIL;
- }
-
-
-
- NNTP_LOG_NOTE (("NET_NewsLoad: %s", ce->URL_s->address));
-
- cd->output_buffer = (char *) XP_ALLOC(OUTPUT_BUFFER_SIZE);
- if(!cd->output_buffer)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
-
- ce->con_data = cd;
- ce->socket = NULL;
- cd->article_num = -1;
-
- XP_ASSERT (url);
- if (!url)
- {
- status = -1;
- goto FAIL;
- }
-
-
- status = NET_parse_news_url (url, &host_and_port, &secure_p,
- &group, &message_id, &command_specific_data);
- if (status < 0)
- goto FAIL;
-
- colon = XP_STRCHR (host_and_port, ':');
- if (colon) {
- unsigned long naturalLong;
- *colon = '\0';
- sscanf (colon+1, " %lu ", &naturalLong); /* %l is 64 bits on OSF1 */
- port = (int32) naturalLong;
- }
- cd->host = MSG_CreateNewsHost(MSG_GetMaster(cd->pane), host_and_port,
- secure_p, port);
- if (colon) *colon = ':';
-
- XP_ASSERT(cd->host);
- if (!cd->host) {
- status = -1;
- goto FAIL;
- }
-
- if (message_id && command_specific_data && !XP_STRCMP (command_specific_data, "?cancel"))
- cancel_p = TRUE;
-
- StrAllocCopy(cd->path, message_id);
- StrAllocCopy(cd->group_name, group);
-
- /* make sure the user has a news host configured */
-
-
- defhost = MSG_GetDefaultNewsHost(MSG_GetMaster(cd->pane));
-
- if (defhost == NULL)
- {
- char* alert = NET_ExplainErrorDetails(MK_NNTP_SERVER_NOT_CONFIGURED);
- FE_Alert(ce->window_id, alert);
- #ifdef XP_MAC
- /* AFTER the alert, not before! */
- FE_EditPreference(PREF_NewsHost);
- #endif
- status = -1;
- goto FAIL;
- }
-
- default_host = (cd->host == defhost);
-
- if (cancel_p && !ce->URL_s->internal_url)
- {
- /* Don't allow manual "news:ID?cancel" URLs, only internal ones. */
- status = -1;
- goto FAIL;
- }
- else if (ce->URL_s->method == URL_POST_METHOD)
- {
- /* news://HOST done with a POST instead of a GET;
- this means a new message is being posted.
- Don't allow this unless it's an internal URL.
- */
- if (!ce->URL_s->internal_url)
- {
- status = -1;
- goto FAIL;
- }
- XP_ASSERT (!group && !message_id && !command_specific_data);
- cd->type_wanted = NEWS_POST;
- StrAllocCopy(cd->path, "");
- }
- else if (message_id)
- {
- /* news:MESSAGE_ID
- news:/GROUP/MESSAGE_ID (useless)
- news://HOST/MESSAGE_ID
- news://HOST/GROUP/MESSAGE_ID (useless)
- */
- if (cancel_p)
- cd->type_wanted = CANCEL_WANTED;
- else
- cd->type_wanted = ARTICLE_WANTED;
- }
- else if (command_specific_data)
- {
- if (XP_STRSTR (command_specific_data, "?newgroups"))
- /* news://HOST/?newsgroups
- news:/GROUP/?newsgroups (useless)
- news:?newsgroups (default host)
- */
- cd->type_wanted = NEW_GROUPS;
- else
- {
- if (XP_STRSTR(command_specific_data, "?list-pretty"))
- {
- cd->type_wanted = PRETTY_NAMES_WANTED;
- cd->command_specific_data = XP_STRDUP(command_specific_data);
- }
- else if (XP_STRSTR(command_specific_data, "?profile"))
- {
- cd->type_wanted = PROFILE_WANTED;
- cd->command_specific_data = XP_STRDUP(command_specific_data);
- }
- else if (XP_STRSTR(command_specific_data, "?list-ids"))
- {
- cd->type_wanted = IDS_WANTED;
- cd->command_specific_data = XP_STRDUP(command_specific_data);
- }
- else
- {
- cd->type_wanted = SEARCH_WANTED;
- cd->command_specific_data = XP_STRDUP(command_specific_data);
- cd->current_search = cd->command_specific_data;
- }
- }
- }
- else if (group)
- {
- /* news:GROUP
- news:/GROUP
- news://HOST/GROUP
- */
- if (ce->window_id->type != MWContextNews && ce->window_id->type != MWContextNewsMsg
- && ce->window_id->type != MWContextMail && ce->window_id->type != MWContextMailNewsProgress)
- {
- status = -1;
- goto FAIL;
- }
- if (XP_STRCHR (group, '*'))
- cd->type_wanted = LIST_WANTED;
- else
- cd->type_wanted = GROUP_WANTED;
- }
- else
- {
- /* news:
- news://HOST
- */
- cd->type_wanted = READ_NEWS_RC;
- }
-
-
- /* At this point, we're all done parsing the URL, and know exactly
- what we want to do with it.
- */
-
- #ifndef NO_ARTICLE_CACHEING
- /* Turn off caching on all news entities, except articles. */
- /* It's very important that this be turned off for CANCEL_WANTED;
- for the others, I don't know what cacheing would cause, but
- it could only do harm, not good. */
- if(cd->type_wanted != ARTICLE_WANTED)
- #endif
- ce->format_out = CLEAR_CACHE_BIT (ce->format_out);
-
- if (cd->type_wanted == ARTICLE_WANTED)
- {
- const char *group = 0;
- uint32 number = 0;
-
- if (MSG_IsOfflineArticle (cd->pane, cd->path,
- &group, &number))
- {
- ce->local_file = TRUE;
- ce->socket = NULL;
- NET_SetCallNetlibAllTheTime(ce->window_id, "mknews");
- MSG_StartOfflineRetrieval(cd->pane, group, number, &cd->offlineState);
- }
- }
- if (NET_IsOffline() && !ce->local_file)
- {
- status = MK_OFFLINE;
- goto FAIL;
- }
- if (cd->offlineState)
- goto FAIL; /* we don't need to do any of this connection stuff */
-
- /* check for established connection and use it if available
- */
- if(nntp_connection_list)
- {
- NNTPConnection * tmp_con;
- XP_List * list_entry = nntp_connection_list;
-
- while((tmp_con = (NNTPConnection *)XP_ListNextObject(list_entry))
- != NULL)
- {
- /* if the hostnames match up exactly and the connection
- * is not busy at the moment then reuse this connection.
- */
- if(!XP_STRCMP(tmp_con->hostname, host_and_port)
- && secure_p == tmp_con->secure
- &&!tmp_con->busy)
- {
- cd->control_con = tmp_con;
-
- NNTP_LOG_NOTE(("Reusing control_con %08lX for %s", tmp_con, url));
-
- /* set select on the control socket */
- ce->socket = cd->control_con->csock;
- NET_SetReadSelect(ce->window_id, cd->control_con->csock);
- cd->control_con->prev_cache = TRUE; /* this was from the cache */
- break;
- }
- }
- }
- else
- {
- /* initialize the connection list
- */
- nntp_connection_list = XP_ListNew();
- }
-
-
- if(cd->control_con)
- {
- cd->next_state = SEND_FIRST_NNTP_COMMAND;
- /* set the connection busy
- */
- cd->control_con->busy = TRUE;
- NET_TotalNumberOfOpenConnections++;
- }
- else
- {
- /* build a control connection structure so we
- * can store the data as we go along
- */
- cd->control_con = XP_NEW(NNTPConnection);
- if(!cd->control_con)
- {
- status = MK_OUT_OF_MEMORY;
- goto FAIL;
- }
- NNTP_LOG_NOTE(("Created control_con %08lX for %s", cd->control_con, ce->URL_s->address));
- XP_MEMSET(cd->control_con, 0, sizeof(NNTPConnection));
-
- cd->control_con->default_host = default_host;
- StrAllocCopy(cd->control_con->hostname, host_and_port);
- NNTP_LOG_NOTE(("Set host string: %s", cd->control_con->hostname));
-
- cd->control_con->secure = secure_p;
-
- cd->control_con->prev_cache = FALSE; /* this wasn't from the cache */
-
- cd->control_con->csock = NULL;
-
- /* define this to test support for older NNTP servers
- * that don't support the XOVER command
- */
- #ifdef TEST_NO_XOVER_SUPPORT
- cd->control_con->no_xover = TRUE;
- #endif /* TEST_NO_XOVER_SUPPORT */
-
- /* add this structure to the connection list even
- * though it's not really valid yet.
- * we will fill it in as we go and if
- * an error occurs will will remove it from the
- * list. No one else will be able to use it since
- * we will mark it busy.
- */
- XP_ListAddObject(nntp_connection_list, cd->control_con);
-
- /* set the connection busy
- */
- cd->control_con->busy = TRUE;
-
- /* gate the maximum number of cached connections
- * but don't delete busy ones.
- */
- if(XP_ListCount(nntp_connection_list) > kMaxCachedConnections)
- {
- XP_List * list_ptr = nntp_connection_list->next;
- NNTPConnection * con;
-
- while(list_ptr)
- {
- con = (NNTPConnection *) list_ptr->object;
- list_ptr = list_ptr->next;
- if(!con->busy)
- {
- XP_ListRemoveObject(nntp_connection_list, con);
- net_nntp_close (con->csock, status);
- FREEIF(con->current_group);
- FREEIF(con->hostname);
- XP_FREE(con);
- break;
- }
- }
- }
-
- cd->next_state = NNTP_CONNECT;
- }
-
- FAIL:
-
- FREEIF (host_and_port);
- FREEIF (group);
- FREEIF (message_id);
- FREEIF (command_specific_data);
-
- if (status < 0)
- {
- FREEIF (cd->output_buffer);
- FREEIF (cd);
- ce->URL_s->error_msg = NET_ExplainErrorDetails(status);
- return status;
- }
- else
- {
- return (net_ProcessNews (ce));
- }
- }
- /* process the offline news state machine, such as it is. */
-
- PRIVATE int
- NET_ProcessOfflineNews(ActiveEntry *ce, NewsConData *cd)
- {
- int32 read_size = 0;
- int status;
-
- cd->pause_for_read = TRUE;
-
- if (cd->stream)
- read_size = (*cd->stream->is_write_ready)
- (cd->stream);
- else
- ce->status = net_begin_article(ce);
-
- if(!read_size)
- return(0); /* wait until we are ready to write */
- else
- read_size = MIN(read_size, NET_Socket_Buffer_Size);
-
- status = MSG_ProcessOfflineNews(cd->offlineState, NET_Socket_Buffer, read_size);
- if(status > 0)
- {
- ce->bytes_received += status;
- PUT_STREAM(NET_Socket_Buffer, status); /* blow off error? ### dmb */
- }
-
- if (status == 0)
- {
- if (cd->stream)
- COMPLETE_STREAM;
- NET_ClearCallNetlibAllTheTime(ce->window_id, "mknews");
-
- if(cd->destroy_graph_progress)
- FE_GraphProgressDestroy(ce->window_id,
- ce->URL_s,
- cd->original_content_length,
- ce->bytes_received);
- status = -1;
-
- }
- return status;
- }
-
- /* process the state machine
- *
- * returns negative when completely done
- */
- PRIVATE int32
- net_ProcessNews (ActiveEntry *ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->offlineState != NULL)
- {
- return NET_ProcessOfflineNews(ce, cd);
- }
- cd->pause_for_read = FALSE;
-
- while(!cd->pause_for_read)
- {
-
- #if DEBUG
- NNTP_LOG_NOTE(("Next state: %s",stateLabels[cd->next_state]));
- #endif
-
- switch(cd->next_state)
- {
- case NNTP_RESPONSE:
- ce->status = net_news_response(ce);
- break;
-
- #ifdef BLOCK_UNTIL_AVAILABLE_CONNECTION
- case NNTP_BLOCK_UNTIL_CONNECTIONS_ARE_AVAILABLE:
- if (nntp_are_connections_available(cd->control_con))
- {
- /* haven't reached connection ceiling on this host; go to connect */
- cd->next_state = NNTP_CONNECTIONS_ARE_AVAILABLE;
- cd->pause_for_read = FALSE;
- }
- else
- {
- NET_SetReadSelect(ce->window_id, ce->socket);
- cd->pause_for_read = TRUE;
- }
- break;
- case NNTP_CONNECTIONS_ARE_AVAILABLE:
- /* release our hacky little lock and move on to connection */
- NET_ClearCallNetlibAllTheTime(ce->window_id, "mknews");
-
- cd->next_state = NNTP_CONNECT;
- cd->pause_for_read = FALSE;
- break;
- #endif
-
- case NNTP_CONNECT:
- if (nntp_are_connections_available(cd->control_con))
- {
- ce->status = NET_BeginConnect(
- (cd->ssl_proxy_server && cd->control_con->secure ?
- cd->ssl_proxy_server :cd->control_con->hostname),
- NULL,
- "NNTP",
- (cd->control_con->secure ? SECURE_NEWS_PORT : NEWS_PORT),
- &ce->socket,
- (cd->ssl_proxy_server ? FALSE : cd->control_con->secure),
- &cd->tcp_con_data,
- ce->window_id,
- &ce->URL_s->error_msg,
- ce->socks_host,
- ce->socks_port);
-
- if(ce->socket != NULL)
- NET_TotalNumberOfOpenConnections++;
-
- cd->pause_for_read = TRUE;
- if(ce->status == MK_CONNECTED)
- {
- HG33086
- {
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LOGIN_RESPONSE;
- }
- NET_SetReadSelect(ce->window_id, ce->socket);
- cd->control_con->csock = ce->socket;
- }
- else if(ce->status > -1)
- {
- ce->con_sock = ce->socket; /* set con_sock so we can select on it */
- cd->control_con->csock = ce->socket;
- NET_SetConnectSelect(ce->window_id, ce->con_sock);
- cd->next_state = NNTP_CONNECT_WAIT;
- }
- }
- else
- {
- #ifdef BLOCK_UNTIL_AVAILABLE_CONNECTION
- /* ###phil this doesn't work yet, but the idea is that we've
- * maxed out connections on this host; stay in this state
- */
- ce->con_sock = ce->socket; /* set con_sock so we can select on it */
- cd->control_con->csock = ce->socket;
- NET_SetConnectSelect(ce->window_id, ce->con_sock);
- cd->next_state = NNTP_BLOCK_UNTIL_CONNECTIONS_ARE_AVAILABLE;
- #else
- ce->status = -1;
- cd->next_state = NNTP_ERROR;
- ce->socket = cd->control_con->csock = NULL;
- #endif
- }
- break;
-
- case NNTP_CONNECT_WAIT:
- ce->status = NET_FinishConnect(
- (cd->ssl_proxy_server && cd->control_con->secure ?
- cd->ssl_proxy_server : cd->control_con->hostname),
- "NNTP",
- (cd->control_con->secure ? SECURE_NEWS_PORT : NEWS_PORT),
- &ce->socket,
- &cd->tcp_con_data,
- ce->window_id,
- &ce->URL_s->error_msg);
-
- cd->pause_for_read = TRUE;
- if(ce->status == MK_CONNECTED)
- {
- cd->control_con->csock = ce->socket;
- HG17928
- {
- cd->next_state = NNTP_RESPONSE;
- cd->next_state_after_response = NNTP_LOGIN_RESPONSE;
- }
-
- NET_ClearConnectSelect(ce->window_id, ce->con_sock);
- ce->con_sock = NULL; /* reset con_sock so we don't select on it */
- NET_SetReadSelect(ce->window_id, ce->socket);
- }
- else if(ce->status < 0)
- {
- NET_ClearConnectSelect(ce->window_id, ce->con_sock);
- }
- else
- {
- /* the not yet connected state */
-
- /* unregister the old ce->socket from the select list
- * and register the new value in the case that it changes
- */
- if(ce->con_sock != ce->socket)
- {
- NET_ClearConnectSelect(ce->window_id, ce->con_sock);
- ce->con_sock = ce->socket;
- NET_SetConnectSelect(ce->window_id, ce->con_sock);
- }
- }
- break;
- HG68092
- case NNTP_LOGIN_RESPONSE:
- ce->status = net_nntp_login_response(ce);
- break;
-
- case NNTP_SEND_MODE_READER:
- ce->status = net_nntp_send_mode_reader(ce);
- break;
-
- case NNTP_SEND_MODE_READER_RESPONSE:
- ce->status = net_nntp_send_mode_reader_response(ce);
- break;
-
- case SEND_LIST_EXTENSIONS:
- ce->status = net_nntp_send_list_extensions(ce);
- break;
- case SEND_LIST_EXTENSIONS_RESPONSE:
- ce->status = net_nntp_send_list_extensions_response(ce);
- break;
- case SEND_LIST_SEARCHES:
- ce->status = net_nntp_send_list_searches(ce);
- break;
- case SEND_LIST_SEARCHES_RESPONSE:
- ce->status = net_nntp_send_list_searches_response(ce);
- break;
- case NNTP_LIST_SEARCH_HEADERS:
- ce->status = net_send_list_search_headers(ce);
- break;
- case NNTP_LIST_SEARCH_HEADERS_RESPONSE:
- ce->status = net_send_list_search_headers_response(ce);
- break;
- case NNTP_GET_PROPERTIES:
- ce->status = nntp_get_properties(ce);
- break;
- case NNTP_GET_PROPERTIES_RESPONSE:
- ce->status = nntp_get_properties_response(ce);
- break;
-
- case SEND_LIST_SUBSCRIPTIONS:
- ce->status = net_send_list_subscriptions(ce);
- break;
- case SEND_LIST_SUBSCRIPTIONS_RESPONSE:
- ce->status = net_send_list_subscriptions_response(ce);
- break;
-
- case SEND_FIRST_NNTP_COMMAND:
- ce->status = net_send_first_nntp_command(ce);
- break;
-
- case SEND_FIRST_NNTP_COMMAND_RESPONSE:
- ce->status = net_send_first_nntp_command_response(ce);
- break;
-
- case NNTP_SEND_GROUP_FOR_ARTICLE:
- ce->status = net_send_group_for_article(ce);
- break;
- case NNTP_SEND_GROUP_FOR_ARTICLE_RESPONSE:
- ce->status = net_send_group_for_article_response(ce);
- break;
- case NNTP_SEND_ARTICLE_NUMBER:
- ce->status = net_send_article_number(ce);
- break;
-
- case SETUP_NEWS_STREAM:
- ce->status = net_setup_news_stream(ce);
- break;
-
- case NNTP_BEGIN_AUTHORIZE:
- ce->status = net_news_begin_authorize(ce);
- break;
-
- case NNTP_AUTHORIZE_RESPONSE:
- ce->status = net_news_authorize_response(ce);
- break;
-
- case NNTP_PASSWORD_RESPONSE:
- ce->status = net_news_password_response(ce);
- break;
-
- case NNTP_READ_LIST_BEGIN:
- ce->status = net_read_news_list_begin(ce);
- break;
-
- case NNTP_READ_LIST:
- ce->status = net_read_news_list(ce);
- break;
-
- case DISPLAY_NEWSGROUPS:
- ce->status = net_display_newsgroups(ce);
- break;
-
- case NNTP_NEWGROUPS_BEGIN:
- ce->status = net_newgroups_begin(ce);
- break;
-
- case NNTP_NEWGROUPS:
- ce->status = net_process_newgroups(ce);
- break;
-
- case NNTP_BEGIN_ARTICLE:
- ce->status = net_begin_article(ce);
- break;
-
- case NNTP_READ_ARTICLE:
- {
- char *line;
- NewsConData * cd =
- (NewsConData *)ce->con_data;
-
- ce->status = NET_BufferedReadLine(ce->socket, &line,
- &cd->data_buf,
- &cd->data_buf_size,
- (Bool*)&cd->pause_for_read);
-
- if(ce->status == 0)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- ce->URL_s->error_msg =
- NET_ExplainErrorDetails(MK_NNTP_SERVER_ERROR);
- return(MK_NNTP_SERVER_ERROR);
- }
-
- if(ce->status > 1)
- {
- ce->bytes_received += ce->status;
- /* We shouldn't graph progress if going offline - it messes
- up our go offline status msgs. ### dmb
- */
- FE_GraphProgress(ce->window_id, ce->URL_s,
- ce->bytes_received, ce->status,
- ce->URL_s->content_length);
-
- }
-
- if(!line)
- return(ce->status); /* no line yet or error */
-
- if (cd->type_wanted == CANCEL_WANTED &&
- cd->response_code != 221)
- {
- /* HEAD command failed. */
- return MK_NNTP_CANCEL_ERROR;
- }
-
- if (line[0] == '.' && line[1] == 0)
- {
- if (cd->type_wanted == CANCEL_WANTED)
- cd->next_state = NEWS_START_CANCEL;
- else
- cd->next_state = NEWS_DONE;
-
- cd->pause_for_read = FALSE;
- }
- else
- {
- if (line[0] == '.')
- XP_STRCPY (cd->output_buffer, line + 1);
- else
- XP_STRCPY (cd->output_buffer, line);
-
- /* When we're sending this line to a converter (ie,
- it's a message/rfc822) use the local line termination
- convention, not CRLF. This makes text articles get
- saved with the local line terminators. Since SMTP
- and NNTP mandate the use of CRLF, it is expected that
- the local system will convert that to the local line
- terminator as it is read.
- */
- XP_STRCAT (cd->output_buffer, LINEBREAK);
- /* Don't send content-type to mime parser if we're doing a cancel
- because it confuses mime parser into not parsing.
- */
- if (cd->type_wanted != CANCEL_WANTED || XP_STRNCMP(cd->output_buffer, "Content-Type:", 13))
- ce->status = PUTSTRING(cd->output_buffer);
- }
- break;
- }
-
- case NNTP_XOVER_BEGIN:
- NET_Progress(ce->window_id, XP_GetString(XP_PROGRESS_READ_NEWSGROUPINFO));
- ce->status = net_read_xover_begin(ce);
- break;
-
- case NNTP_FIGURE_NEXT_CHUNK:
- ce->status = net_figure_next_chunk(ce);
- break;
-
- case NNTP_XOVER_SEND:
- ce->status = net_xover_send(ce);
- break;
-
- case NNTP_XOVER:
- ce->status = net_read_xover(ce);
- break;
-
- case NNTP_XOVER_RESPONSE:
- ce->status = net_read_xover_response(ce);
- break;
-
- case NEWS_PROCESS_XOVER:
- case NEWS_PROCESS_BODIES:
- if (cd->group_name && XP_STRSTR (cd->group_name, ".emacs"))
- /* This is a joke! Don't internationalize it... */
- NET_Progress(ce->window_id, "Garbage collecting...");
- else
- NET_Progress(ce->window_id, XP_GetString(XP_PROGRESS_SORT_ARTICLES));
- ce->status = net_process_xover(ce);
- break;
-
- case NNTP_PROFILE_ADD:
- ce->status = net_profile_add (ce);
- break;
- case NNTP_PROFILE_ADD_RESPONSE:
- ce->status = net_profile_add_response(ce);
- break;
- case NNTP_PROFILE_DELETE:
- ce->status = net_profile_delete (ce);
- break;
- case NNTP_PROFILE_DELETE_RESPONSE:
- ce->status = net_profile_delete_response(ce);
- break;
-
- case NNTP_READ_GROUP:
- ce->status = net_read_news_group(ce);
- break;
-
- case NNTP_READ_GROUP_RESPONSE:
- ce->status = net_read_news_group_response(ce);
- break;
-
- case NNTP_READ_GROUP_BODY:
- ce->status = net_read_news_group_body(ce);
- break;
-
- case NNTP_SEND_POST_DATA:
- ce->status = net_send_news_post_data(ce);
- break;
-
- case NNTP_SEND_POST_DATA_RESPONSE:
- ce->status = net_send_news_post_data_response(ce);
- break;
-
- case NNTP_CHECK_FOR_MESSAGE:
- ce->status = net_check_for_message(ce);
- break;
-
- case NEWS_NEWS_RC_POST:
- ce->status = net_NewsRCProcessPost(ce);
- break;
-
- case NEWS_DISPLAY_NEWS_RC:
- ce->status = net_DisplayNewsRC(ce);
- break;
-
- case NEWS_DISPLAY_NEWS_RC_RESPONSE:
- ce->status = net_DisplayNewsRCResponse(ce);
- break;
-
- case NEWS_START_CANCEL:
- ce->status = net_start_cancel(ce);
- break;
-
- case NEWS_DO_CANCEL:
- ce->status = net_do_cancel(ce);
- break;
-
- case NNTP_XPAT_SEND:
- ce->status = net_xpat_send(ce);
- break;
- case NNTP_XPAT_RESPONSE:
- ce->status = net_xpat_response(ce);
- break;
- case NNTP_SEARCH:
- ce->status = net_nntp_search(ce);
- break;
- case NNTP_SEARCH_RESPONSE:
- ce->status = net_nntp_search_response(ce);
- break;
- case NNTP_SEARCH_RESULTS:
- ce->status = net_nntp_search_results(ce);
- break;
- case NNTP_LIST_PRETTY_NAMES:
- ce->status = net_list_pretty_names(ce);
- break;
- case NNTP_LIST_PRETTY_NAMES_RESPONSE:
- ce->status = net_list_pretty_names_response(ce);
- break;
- case NNTP_LIST_XACTIVE:
- ce->status = net_list_xactive(ce);
- break;
- case NNTP_LIST_XACTIVE_RESPONSE:
- ce->status = net_list_xactive_response(ce);
- break;
- case NNTP_LIST_GROUP:
- ce->status = net_list_group(ce);
- break;
- case NNTP_LIST_GROUP_RESPONSE:
- ce->status = net_list_group_response(ce);
- break;
- case NEWS_DONE:
- /* call into libmsg and see if the article counts
- * are up to date. If they are not then we
- * want to do a "news://host/group" URL so that we
- * can finish up the article counts.
- */
- if (cd->stream)
- COMPLETE_STREAM;
-
- cd->next_state = NEWS_FREE;
- /* set the connection unbusy
- */
- cd->control_con->busy = FALSE;
- NET_TotalNumberOfOpenConnections--;
-
- NET_ClearReadSelect(ce->window_id, cd->control_con->csock);
- NET_RefreshCacheFileExpiration(ce->URL_s);
- break;
-
- case NEWS_ERROR:
- if(cd->stream)
- ABORT_STREAM(ce->status);
- cd->next_state = NEWS_FREE;
- /* set the connection unbusy
- */
- cd->control_con->busy = FALSE;
- NET_TotalNumberOfOpenConnections--;
-
- if(cd->control_con->csock != NULL)
- {
- NET_ClearReadSelect(ce->window_id, cd->control_con->csock);
- }
- break;
-
- case NNTP_ERROR:
- if(cd->stream)
- {
- ABORT_STREAM(ce->status);
- cd->stream=0;
- }
-
- if(cd->control_con && cd->control_con->csock != NULL)
- {
- NNTP_LOG_NOTE(("Clearing read and connect select on socket %d",
- cd->control_con->csock));
- NET_ClearConnectSelect(ce->window_id, cd->control_con->csock);
- NET_ClearReadSelect(ce->window_id, cd->control_con->csock);
- #ifdef XP_WIN
- if(cd->calling_netlib_all_the_time)
- {
- cd->calling_netlib_all_the_time = FALSE;
- NET_ClearCallNetlibAllTheTime(ce->window_id, "mknews");
- }
- #endif /* XP_WIN */
- NET_ClearDNSSelect(ce->window_id, cd->control_con->csock);
- net_nntp_close (cd->control_con->csock, ce->status); /* close the socket */
- FREEIF(cd->control_con->current_group);
- NET_TotalNumberOfOpenConnections--;
- ce->socket = NULL;
- }
-
- /* check if this connection came from the cache or if it was
- * a new connection. If it was not new lets start it over
- * again. But only if we didn't have any successful protocol
- * dialog at all.
- */
- if(cd->control_con && cd->control_con->prev_cache &&
- !cd->some_protocol_succeeded)
- {
- cd->control_con->prev_cache = FALSE;
- cd->next_state = NNTP_CONNECT;
- ce->status = 0; /* keep going */
- }
- else
- {
- cd->next_state = NEWS_FREE;
-
- /* remove the connection from the cache list
- * and free the data
- */
- XP_ListRemoveObject(nntp_connection_list, cd->control_con);
- if(cd->control_con)
- {
- FREEIF(cd->control_con->hostname);
- FREE(cd->control_con);
- }
- }
- break;
-
- case NEWS_FREE:
-
- /* do we need to know if we're parsing xover to call finish xover? */
- /* If we've gotten to NEWS_FREE and there is still XOVER
- data, there was an error or we were interrupted or
- something. So, tell libmsg there was an abnormal
- exit so that it can free its data. */
- /* if (cd->xover_parse_state != NULL)*/
- {
- int status;
- /* XP_ASSERT (ce->status < 0);*/
- status = MSG_FinishXOVER (cd->pane,
- &cd->xover_parse_state,
- ce->status);
- XP_ASSERT (!cd->xover_parse_state);
- if (ce->status >= 0 && status < 0)
- ce->status = status;
- }
- if (cd->newsgroup_parse_state)
- MSG_FinishAddArticleKeyToGroup(cd->pane, &cd->newsgroup_parse_state);
-
- FREEIF(cd->path);
- FREEIF(cd->response_txt);
- FREEIF(cd->data_buf);
-
- FREEIF(cd->output_buffer);
- FREEIF(cd->ssl_proxy_server);
- FREEIF(cd->stream); /* don't forget the stream */
- if(cd->tcp_con_data)
- NET_FreeTCPConData(cd->tcp_con_data);
-
- FREEIF(cd->group_name);
-
- FREEIF (cd->cancel_id);
- FREEIF (cd->cancel_from);
- FREEIF (cd->cancel_newsgroups);
- FREEIF (cd->cancel_distribution);
-
- if(cd->destroy_graph_progress)
- FE_GraphProgressDestroy(ce->window_id,
- ce->URL_s,
- cd->original_content_length,
- ce->bytes_received);
- XP_FREE(cd);
-
- /* gate the maximum number of cached connections
- * but don't delete busy ones.
- */
- if(XP_ListCount(nntp_connection_list) > kMaxCachedConnections)
- {
- XP_List * list_ptr = nntp_connection_list->next;
- NNTPConnection * con;
-
- NNTP_LOG_NOTE(("killing cached news connection"));
-
- while(list_ptr)
- {
- con = (NNTPConnection *) list_ptr->object;
- list_ptr = list_ptr->next;
- if(!con->busy)
- {
- XP_ListRemoveObject(nntp_connection_list, con);
- net_nntp_close(con->csock, ce->status);
- FREEIF(con->current_group);
- FREEIF(con->hostname);
- XP_FREE(con);
- break;
- }
- }
- }
- return(-1); /* all done */
-
- default:
- /* big error */
- return(-1);
- }
-
- if(ce->status < 0 && cd->next_state != NEWS_ERROR &&
- cd->next_state != NNTP_ERROR && cd->next_state != NEWS_FREE)
- {
- cd->next_state = NNTP_ERROR;
- cd->pause_for_read = FALSE;
- }
- } /* end big while */
-
- return(0); /* keep going */
- }
-
- /* abort the connection in progress
- */
- PRIVATE int32
- net_InterruptNews(ActiveEntry * ce)
- {
- NewsConData * cd = (NewsConData *)ce->con_data;
-
- if (cd->offlineState != NULL)
- return MSG_InterruptOfflineNews(cd->offlineState);
-
- cd->next_state = NNTP_ERROR;
- ce->status = MK_INTERRUPTED;
-
- if (cd->control_con)
- cd->control_con->prev_cache = FALSE; /* to keep if from reconnecting */
-
- return(net_ProcessNews(ce));
- }
-
- /* Free any memory used up
- * close cached connections and
- * free newsgroup listings
- */
- PRIVATE void
- net_CleanupNews(void)
- {
- NNTP_LOG_NOTE(("NET_CleanupNews called"));
-
- /* this is a small leak but since I don't have another function to
- * clear my connections I need to call this one alot and I don't
- * want to free the newshost
- *
- * FREE_AND_CLEAR(NET_NewsHost);
- */
-
- if(nntp_connection_list)
- {
- NNTPConnection * tmp_con;
-
- while((tmp_con = (NNTPConnection *)XP_ListRemoveTopObject(nntp_connection_list)) != NULL)
- {
- if(!tmp_con->busy)
- {
- FREE(tmp_con->hostname);
- FREEIF(tmp_con->current_group);
- if(tmp_con->csock != NULL)
- {
- net_nntp_close(tmp_con->csock, 0 /* status? */);
- }
- FREE(tmp_con);
- }
- }
-
- if(XP_ListIsEmpty(nntp_connection_list))
- {
- XP_ListDestroy(nntp_connection_list);
- nntp_connection_list = 0;
- }
- }
-
- return;
- }
-
- MODULE_PRIVATE void
- NET_InitNewsProtocol(void)
- {
- static NET_ProtoImpl news_proto_impl;
-
- news_proto_impl.init = net_NewsLoad;
- news_proto_impl.process = net_ProcessNews;
- news_proto_impl.interrupt = net_InterruptNews;
- news_proto_impl.cleanup = net_CleanupNews;
-
- NET_RegisterProtocolImplementation(&news_proto_impl, NEWS_TYPE_URL);
- NET_RegisterProtocolImplementation(&news_proto_impl, INTERNAL_NEWS_TYPE_URL);
- }
-
- #ifdef PROFILE
- #pragma profile off
- #endif
-
- #endif /* MOZILLA_CLIENT */
-
-