mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
54f09897ee
use new XPCOM offline state fix PR_smprintf formatting
5964 lines
154 KiB
C++
5964 lines
154 KiB
C++
/* -*- 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.
|
||
*/
|
||
|
||
/*
|
||
* NNTP protocol implementation. Maintains some state and sends most
|
||
* data to messenger backend.
|
||
*/
|
||
|
||
/* Please leave outside of ifdef for windows precompiled headers */
|
||
#define FORCE_PR_LOG /* Allow logging in the release build (sorry this breaks the PCH) */
|
||
extern "C" {
|
||
#include "mkutils.h"
|
||
#include "netutils.h"
|
||
}
|
||
|
||
#ifdef MOZILLA_CLIENT
|
||
|
||
#include "merrors.h"
|
||
|
||
#include "mime.h"
|
||
#include "shist.h"
|
||
#include "glhist.h"
|
||
|
||
#include "mknews.h"
|
||
#include "mktcp.h"
|
||
#include "mkparse.h"
|
||
#include "mkformat.h"
|
||
#include "mkstream.h"
|
||
#include "mkaccess.h"
|
||
#include "mksort.h"
|
||
#include "netcache.h"
|
||
#include "libi18n.h"
|
||
#include "gui.h"
|
||
|
||
#include "rosetta.h"
|
||
#include HG40855
|
||
#include "mknews.h"
|
||
|
||
#include "msgcom.h"
|
||
#include "msgnet.h"
|
||
#include "msg_srch.h"
|
||
#include "libmime.h"
|
||
|
||
#include "prtime.h"
|
||
#include "prlog.h"
|
||
#include "prerror.h"
|
||
|
||
#include "xp_error.h"
|
||
#include HG09893
|
||
#include "prefapi.h"
|
||
#include "xplocale.h"
|
||
|
||
/* start turning on XPCOM interfaces here.
|
||
* when they are all turned on, PLEASE remove dead code */
|
||
#define XPCOM_XOVER
|
||
#define XPCOM_NEWSPARSE
|
||
#define XPCOM_NEWSHOST
|
||
#define XPCOM_NEWSGROUP
|
||
#define XPCOM_OFFLINE
|
||
|
||
#ifdef XPCOM_XOVER
|
||
#include "nsIMsgXOVERParser.h"
|
||
#endif
|
||
|
||
#ifdef XPCOM_NEWSPARSE
|
||
#include "nsIMsgNewsArticleList.h"
|
||
#endif
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
#include "nsIMsgNewsHost.h"
|
||
#endif
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
#include "nsIMsgNewsgroup.h"
|
||
#endif
|
||
|
||
#ifdef XPCOM_OFFLINE
|
||
#include "nsIMsgOfflineNewsState.h"
|
||
#endif
|
||
|
||
#include "nsIMsgRFC822Parser.h"
|
||
#include "nsMsgRFC822Parser.h" /* for the factory */
|
||
|
||
/*#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;
|
||
HG25431
|
||
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;
|
||
extern int MK_MSG_HTML_IMAP_NO_CACHED_BODY;
|
||
|
||
/* Logging stuff */
|
||
|
||
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) ;
|
||
|
||
|
||
/* end logging */
|
||
|
||
/* Forward declarations */
|
||
static int net_xpat_send (ActiveEntry*);
|
||
static int net_list_pretty_names(ActiveEntry*);
|
||
|
||
int net_ProcessNews(ActiveEntry *cur_entry);
|
||
|
||
#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 XP_List * nntp_connection_list=0;
|
||
|
||
PRIVATE XP_Bool net_news_last_username_probably_valid=FALSE;
|
||
PRIVATE int32 net_NewsChunkSize=-1; /* default */
|
||
|
||
PRIVATE int32 net_news_timeout = 170; /* seconds that an idle NNTP conn can live */
|
||
|
||
#define PUTSTRING(s) (*cd->stream->put_block) \
|
||
(cd->stream, s, PL_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,
|
||
HG07711
|
||
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",
|
||
HG25430
|
||
"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 */
|
||
HG55785
|
||
char *current_group; /* last GROUP command sent on this connection */
|
||
PRTime last_used_time; /* last time this conn was used, for conn aging purposes */
|
||
} NNTPConnection;
|
||
|
||
|
||
/* structure to hold all the state and data
|
||
* for the state machine
|
||
*/
|
||
typedef struct _NewsConData {
|
||
MSG_Pane *pane;
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsIMsgNewsHost *news_host;
|
||
#else
|
||
MSG_NewsHost *host;
|
||
#endif
|
||
|
||
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 *proxy_server; /* @#$ 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 */
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
nsIMsgNewsgroup *newsgroup;
|
||
#else
|
||
char *group_name;
|
||
#endif
|
||
|
||
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 */
|
||
#ifdef XPCOM_XOVER
|
||
nsIMsgXOVERParser *xover_parser;
|
||
#else
|
||
void *xover_parse_state;
|
||
#endif
|
||
|
||
#ifdef XPCOM_NEWSPARSE
|
||
nsIMsgNewsArticleList *article_list;
|
||
#else
|
||
void *newsgroup_parse_state;
|
||
#endif
|
||
|
||
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;
|
||
#ifdef XPCOM_OFFLINE
|
||
nsIMsgOfflineNewsState *offline_state;
|
||
#else
|
||
void *offlineState; /* offline news state machine for article retrieval */
|
||
#endif
|
||
XP_Bool articleIsOffline;
|
||
int previous_response_code;
|
||
|
||
} NewsConData;
|
||
|
||
static char * last_password = 0;
|
||
static char * last_password_hostname = 0;
|
||
static char * last_username=0;
|
||
static char * last_username_hostname=0;
|
||
|
||
/* 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)
|
||
{
|
||
}
|
||
|
||
|
||
|
||
PUBLIC void net_graceful_shutdown(PRFileDesc* sock, XP_Bool bVal)
|
||
{
|
||
static int32 int_pref = -1;
|
||
|
||
#ifdef THIS_IS_DEPRICATED
|
||
if (sock == NULL) return;
|
||
#endif
|
||
|
||
if (int_pref == -1)
|
||
PREF_GetIntPref("network.socket_shutdown", &int_pref);
|
||
if (int_pref > 0 && int_pref < 4)
|
||
{
|
||
if (bVal)
|
||
/* ??? */
|
||
NET_BlockingWrite(sock, "", 0);
|
||
else
|
||
PR_Shutdown(sock, (PRShutdownHow)(int_pref-1));
|
||
}
|
||
}
|
||
|
||
static void net_nntp_close (NNTPConnection *con, int status)
|
||
{
|
||
if (!con)
|
||
{
|
||
PR_ASSERT(FALSE);
|
||
return;
|
||
}
|
||
else if (status != MK_INTERRUPTED)
|
||
{
|
||
const char *command = "QUIT" CRLF;
|
||
status = NET_BlockingWrite (con->csock, command, PL_strlen(command));
|
||
NNTP_LOG_WRITE (command);
|
||
if (status >= 0) {
|
||
HG51966
|
||
}
|
||
PR_Close(con->csock);
|
||
}
|
||
|
||
FREEIF(con->current_group);
|
||
}
|
||
|
||
/* 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 (!(PL_strcasecmp(conn->hostname, hostName)))
|
||
{
|
||
net_nntp_close (conn, /* conn->busy ? MK_INTERRUPTED : */ 0);
|
||
|
||
list = list->prev ? list->prev : nntp_connection_list;
|
||
XP_ListRemoveObject (nntp_connection_list, conn);
|
||
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 = MK_NNTP_RESPONSE_TYPE(cd->response_code);
|
||
/* #### 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)
|
||
{
|
||
PL_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)
|
||
{
|
||
char *urlScheme;
|
||
HG72589
|
||
|
||
PR_snprintf(cd->output_buffer,
|
||
OUTPUT_BUFFER_SIZE,
|
||
"<P><%.512s>", cd->path);
|
||
if (cd->article_num > 0)
|
||
{
|
||
PR_snprintf(cd->output_buffer+PL_strlen(cd->output_buffer),
|
||
OUTPUT_BUFFER_SIZE-PL_strlen(cd->output_buffer),
|
||
" (%lu)", (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);
|
||
|
||
char *group_name;
|
||
cd->newsgroup->GetName(&group_name);
|
||
PR_snprintf(cd->output_buffer, OUTPUT_BUFFER_SIZE,
|
||
"<P> <A HREF=\"%s//%s/%s?list-ids\">%s</A> </P>\n",
|
||
urlScheme,
|
||
cd->control_con->hostname,
|
||
group_name,
|
||
XP_GetString(MK_MSG_EXPIRE_NEWS_ARTICLES));
|
||
PR_Free(group_name);
|
||
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 = PL_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 == MK_NNTP_RESPONSE_TYPE_CANNOT)
|
||
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,
|
||
PR_GetOSError());
|
||
|
||
/* 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 */
|
||
|
||
HG43574
|
||
/* 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(MK_NNTP_RESPONSE_AUTHINFO_REQUIRE == cd->response_code ||
|
||
MK_NTTP_RESPONSE_AUTHINFO_SIMPLE_REQUIRE == cd->response_code ||
|
||
MK_NNTP_RESPONSE_PERMISSION_DENIED == cd->response_code)
|
||
{
|
||
cd->next_state = NNTP_BEGIN_AUTHORIZE;
|
||
if (MK_NNTP_RESPONSE_PERMISSION_DENIED == cd->response_code) {
|
||
if (MK_NNTP_RESPONSE_TYPE_OK == MK_NNTP_RESPONSE_TYPE(cd->previous_response_code) {
|
||
if (net_news_last_username_probably_valid) {
|
||
net_news_last_username_probably_valid = FALSE;
|
||
}
|
||
else {
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(NULL);
|
||
cd->newsgroup->SetPassword(NULL);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, NULL);
|
||
MSG_SetNewsgroupPassword(cd->pane, NULL);
|
||
#endif
|
||
}
|
||
}
|
||
else {
|
||
net_news_last_username_probably_valid = FALSE;
|
||
if (NNTP_PASSWORD_RESPONSE == cd->next_state_after_response) {
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(NULL);
|
||
cd->newsgroup->SetPassword(NULL);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, NULL);
|
||
MSG_SetNewsgroupPassword(cd->pane, NULL);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
#else
|
||
if (MK_NNTP_RESPONSE_AUTHINFO_REQUIRE == cd->response_code ||
|
||
MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_REQUIRE == cd->response_code)
|
||
{
|
||
cd->next_state = NNTP_BEGIN_AUTHORIZE;
|
||
}
|
||
else if (MK_NNTP_RESPONSE_PERMISSION_DENIED == 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 */
|
||
}
|
||
|
||
HG43072
|
||
|
||
/* 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 == MK_NNTP_RESPONSE_POSTING_ALLOWED;
|
||
|
||
if(MK_NNTP_RESPONSE_TYPE(cd->response_code)!=MK_NNTP_RESPONSE_TYPE_OK)
|
||
{
|
||
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 */
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->SetPostingAllowed(postingAllowed);
|
||
#else
|
||
MSG_SetNewsHostPostingAllowed (cd->host, postingAllowed);
|
||
#endif
|
||
|
||
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;
|
||
|
||
PL_strcpy(cd->output_buffer, "MODE READER" CRLF);
|
||
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
PRBool pushAuth;
|
||
nsresult rv = cd->news_host->IsPushAuth(&pushAuth);
|
||
if (NS_SUCCEEDED(rv) && pushAuth)
|
||
#else
|
||
if (MSG_GetNewsHostPushAuth(cd->host))
|
||
#endif
|
||
/* 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;
|
||
PL_strcpy(cd->output_buffer, "LIST EXTENSIONS" CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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 (MK_NNTP_RESPONSE_TYPE(cd->response_code) == MK_NNTP_RESPONSE_TYPE_OK)
|
||
{
|
||
char *line = NULL;
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsIMsgNewsHost *news_host = cd->news_host;
|
||
#else
|
||
MSG_NewsHost *host = cd->host;
|
||
#endif
|
||
|
||
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 XPCOM_NEWSHOST
|
||
news_host->AddExtension(line);
|
||
#else
|
||
MSG_AddNewsExtension (host, line);
|
||
#endif
|
||
else
|
||
{
|
||
/* tell libmsg that it's ok to ask this news host for extensions */
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->SetSupportsExtensions(TRUE);
|
||
#else
|
||
MSG_SupportsNewsExtensions (cd->host, TRUE);
|
||
#endif
|
||
/* 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.
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->SetSupportsExtensions(FALSE);
|
||
#else
|
||
MSG_SupportsNewsExtensions (cd->host, FALSE);
|
||
#endif
|
||
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;
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool searchable=FALSE;
|
||
|
||
rv = cd->news_host->QueryExtension("SEARCH",&searchable);
|
||
if (NS_SUCCEEDED(rv) && searchable)
|
||
#else
|
||
if (MSG_QueryNewsExtension (cd->host, "SEARCH"))
|
||
#endif
|
||
{
|
||
PL_strcpy(cd->output_buffer, "LIST SEARCHES" CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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])
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddSearchableGroup(line);
|
||
#else
|
||
MSG_AddSearchableGroup (cd->host, line);
|
||
#endif
|
||
}
|
||
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;
|
||
PL_strcpy(cd->output_buffer, "LIST SRCHFIELDS" CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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;
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsIMsgNewsHost* news_host = cd->news_host;
|
||
#else
|
||
MSG_NewsHost *host = cd->host;
|
||
#endif
|
||
|
||
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 XPCOM_NEWSHOST
|
||
news_host->AddSearchableHeader(line);
|
||
#else
|
||
MSG_AddSearchableHeader (host, line);
|
||
#endif
|
||
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;
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool setget=FALSE;
|
||
|
||
rv = cd->news_host->QueryExtension("SETGET",&setget);
|
||
if (NS_SUCCEEDED(rv) && setget)
|
||
#else
|
||
if (MSG_QueryNewsExtension (cd->host, "SETGET"))
|
||
#endif
|
||
{
|
||
PL_strcpy(cd->output_buffer, "GET" CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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 = PL_strdup(line);
|
||
if (propertyName)
|
||
{
|
||
char *space = PL_strchr(propertyName, ' ');
|
||
if (space)
|
||
{
|
||
char *propertyValue = space + 1;
|
||
*space = '\0';
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddPropertyForGet(propertyName, propertyValue);
|
||
#else
|
||
MSG_AddPropertyForGet (cd->host,
|
||
propertyName, propertyValue);
|
||
#endif
|
||
}
|
||
PR_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;
|
||
|
||
#if 0
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool searchable=FALSE;
|
||
rv = cd->news_host->QueryExtension("LISTSUBSCR",&listsubscr);
|
||
if (NS_SUCCEEDED(rv) && listsubscr)
|
||
#else
|
||
if (MSG_QueryNewsExtension (cd->host, "LISTSUBSCR"))
|
||
#endif
|
||
#else
|
||
if (0)
|
||
#endif
|
||
{
|
||
PL_strcpy(cd->output_buffer, "LIST SUBSCRIPTIONS" CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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])
|
||
{
|
||
#if 0
|
||
char *urlScheme;
|
||
HG56946
|
||
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)
|
||
{
|
||
#ifdef XPCOM_NEWSGROUP
|
||
const char *group = 0;
|
||
#endif
|
||
uint32 number = 0;
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
nsresult rv;
|
||
nsIMsgNewsgroup *newsgroup;
|
||
rv = cd->news_host->GetNewsGroupAndNumberOfID(cd->path,
|
||
&newsgroup, &number);
|
||
#else
|
||
MSG_NewsGroupAndNumberOfID (cd->pane, cd->path,
|
||
&group, &number);
|
||
#endif
|
||
if (NS_SUCCEEDED(rv) && newsgroup && number)
|
||
{
|
||
cd->article_num = number;
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup = newsgroup;
|
||
#else
|
||
StrAllocCopy (cd->group_name, group);
|
||
#endif
|
||
|
||
if (cd->control_con->current_group && !PL_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)
|
||
{
|
||
PR_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 ||
|
||
PL_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)
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
PRTime last_update;
|
||
nsresult rv;
|
||
|
||
rv = cd->news_host->GetLastUpdatedTime(&last_update);
|
||
#else
|
||
time_t last_update =
|
||
MSG_NewsgroupsLastUpdatedTime(cd->host);
|
||
#endif
|
||
char small_buf[64];
|
||
PRExplodedTime expandedTime;
|
||
|
||
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);
|
||
PR_ExplodeTime(timeInUSec, PR_LocalTimeParameters, &expandedTime);
|
||
}
|
||
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;
|
||
#ifdef XPCOM_NEWSHOST
|
||
PRTime last_update;
|
||
nsresult rv = cd->news_host->GetLastUpdatedTime(&last_update);
|
||
|
||
if (NS_SUCCEEDED(rv) && last_update!=0)
|
||
#else
|
||
if (MSG_NewsgroupsLastUpdatedTime(cd->host))
|
||
#endif
|
||
{
|
||
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 */
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool xactive=FALSE;
|
||
rv = cd->news_host->QueryExtension("XACTIVE",&xactive);
|
||
if (NS_SUCCEEDED(rv) && xactive)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
|
||
#endif
|
||
{
|
||
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;
|
||
#ifdef XPCOM_NEWSGROUP
|
||
char * group_name;
|
||
nsresult rv;
|
||
#endif
|
||
|
||
StrAllocCopy(command, "GROUP ");
|
||
#ifdef XPCOM_NEWSGROUP
|
||
rv = cd->newsgroup->GetName(&group_name);
|
||
slash = PL_strchr(group_name, '/');
|
||
#else
|
||
slash = PL_strchr(cd->group_name, '/'); /* look for a slash */
|
||
#endif
|
||
cd->first_art = 0;
|
||
cd->last_art = 0;
|
||
if (slash)
|
||
{
|
||
*slash = '\0';
|
||
(void) sscanf(slash+1, "%d-%d", &cd->first_art, &cd->last_art);
|
||
}
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
StrAllocCopy (cd->control_con->current_group, group_name);
|
||
#else
|
||
StrAllocCopy (cd->control_con->current_group, cd->group_name);
|
||
#endif
|
||
StrAllocCat(command, cd->control_con->current_group);
|
||
}
|
||
else if (cd->type_wanted == SEARCH_WANTED)
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool searchable=FALSE;
|
||
rv = cd->news_host->QueryExtension("SEARCH", &searchable);
|
||
if (NS_SUCCEEDED(rv) && searchable)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "SEARCH"))
|
||
#endif
|
||
{
|
||
/* use the SEARCH extension */
|
||
char *slash = PL_strchr (cd->command_specific_data, '/');
|
||
if (slash)
|
||
{
|
||
char *allocatedCommand = MSG_UnEscapeSearchUrl (slash + 1);
|
||
if (allocatedCommand)
|
||
{
|
||
StrAllocCopy (command, allocatedCommand);
|
||
PR_Free(allocatedCommand);
|
||
}
|
||
}
|
||
cd->next_state = NNTP_RESPONSE;
|
||
cd->next_state_after_response = NNTP_SEARCH_RESPONSE;
|
||
}
|
||
else
|
||
{
|
||
nsresult rv;
|
||
char *group_name;
|
||
|
||
/* for XPAT, we have to GROUP into the group before searching */
|
||
StrAllocCopy (command, "GROUP ");
|
||
#ifdef XPCOM_NEWSGROUP
|
||
rv = cd->newsgroup->GetName(&group_name);
|
||
StrAllocCat (command, group_name);
|
||
#else
|
||
StrAllocCat (command, cd->group_name);
|
||
#endif
|
||
cd->next_state = NNTP_RESPONSE;
|
||
cd->next_state_after_response = NNTP_XPAT_SEND;
|
||
}
|
||
}
|
||
else if (cd->type_wanted == PRETTY_NAMES_WANTED)
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool listpretty=FALSE;
|
||
rv = cd->news_host->QueryExtension("LISTPRETTY",&listpretty);
|
||
if (NS_SUCCEEDED(rv) && listpretty)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "LISTPRETTY"))
|
||
#endif
|
||
{
|
||
cd->next_state = NNTP_LIST_PRETTY_NAMES;
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
PR_ASSERT(FALSE);
|
||
cd->next_state = NNTP_ERROR;
|
||
}
|
||
}
|
||
else if (cd->type_wanted == PROFILE_WANTED)
|
||
{
|
||
char *slash = PL_strchr (cd->command_specific_data, '/');
|
||
if (slash)
|
||
{
|
||
char *allocatedCommand = MSG_UnEscapeSearchUrl (slash + 1);
|
||
if (allocatedCommand)
|
||
{
|
||
StrAllocCopy (command, allocatedCommand);
|
||
PR_Free(allocatedCommand);
|
||
}
|
||
}
|
||
cd->next_state = NNTP_RESPONSE;
|
||
if (PL_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)
|
||
{
|
||
#ifndef XPCOM_NEWSGROUP
|
||
char *slash = PL_strchr(cd->group_name, '/'); /* look for a slash */
|
||
if (slash)
|
||
*slash = '\0';
|
||
#endif
|
||
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 (PL_strchr(command+8, '>')==0)
|
||
StrAllocCat(command,">");
|
||
}
|
||
|
||
StrAllocCat(command, CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket, command, PL_strlen(command));
|
||
NNTP_LOG_WRITE(command);
|
||
PR_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 = MK_NNTP_RESPONSE_TYPE(cd->response_code);
|
||
|
||
if((major_opcode == MK_NNTP_RESPONSE_TYPE_CONT &&
|
||
cd->type_wanted == NEWS_POST)
|
||
|| (major_opcode == MK_NNTP_RESPONSE_TYPE_OK &&
|
||
cd->type_wanted != NEWS_POST) )
|
||
{
|
||
|
||
cd->next_state = SETUP_NEWS_STREAM;
|
||
cd->some_protocol_succeeded = TRUE;
|
||
|
||
return(0); /* good */
|
||
}
|
||
else
|
||
{
|
||
if (cd->response_code == MK_NNTP_RESPONSE_GROUP_NO_GROUP &&
|
||
cd->type_wanted == GROUP_WANTED)
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->GroupNotFound(cd->control_con->current_group,
|
||
TRUE /* opening */);
|
||
#else
|
||
MSG_GroupNotFound(cd->pane, cd->host,
|
||
cd->control_con->current_group, TRUE /* opening group */);
|
||
#endif
|
||
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;
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
nsresult rv;
|
||
PR_FREEIF(cd->control_con->current_group);
|
||
rv = cd->newsgroup->GetName(&cd->control_con->current_group);
|
||
PR_ASSERT(NS_SUCCEEEDED(rv));
|
||
#else
|
||
StrAllocCopy (cd->control_con->current_group, cd->group_name);
|
||
#endif
|
||
|
||
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,
|
||
PL_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,
|
||
PL_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 *) PR_Malloc (PL_strlen (prefix) +
|
||
(new_dest ? PL_strlen (new_dest) : 0)
|
||
+ 40);
|
||
if (result && prefix)
|
||
{
|
||
PL_strcpy (result, prefix);
|
||
if (prefix[PL_strlen(prefix) - 1] != ':')
|
||
/* If there is a host, it must be terminated with a slash. */
|
||
PL_strcat (result, "/");
|
||
PL_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;
|
||
#if 0
|
||
/* This should be handled by NET_SetCallNetlibAllTheTime */
|
||
net_call_all_the_time_count++;
|
||
#endif
|
||
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 (PL_strstr(ce->URL_s->address, "PROFILE NEW"))
|
||
cd->next_state = NNTP_PROFILE_ADD;
|
||
else
|
||
cd->next_state = NNTP_PROFILE_DELETE;
|
||
}
|
||
else
|
||
{
|
||
PR_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;
|
||
|
||
PR_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);
|
||
}
|
||
PR_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))
|
||
{
|
||
PR_ASSERT(0);
|
||
return -1;
|
||
}
|
||
|
||
if (ce->URL_s->fe_data)
|
||
{
|
||
PR_ASSERT(0);
|
||
return -1;
|
||
}
|
||
|
||
opt = PR_NEW (MimeDisplayOptions);
|
||
if (!opt) return MK_OUT_OF_MEMORY;
|
||
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 = PL_strdup (MESSAGE_RFC822);
|
||
|
||
#ifdef NO_ARTICLE_CACHEING
|
||
ce->format_out = CLEAR_CACHE_BIT (ce->format_out);
|
||
#endif
|
||
|
||
if (cd->type_wanted == CANCEL_WANTED)
|
||
{
|
||
PR_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);
|
||
PR_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;
|
||
char * cp;
|
||
|
||
#ifdef CACHE_NEWSGRP_PASSWORD
|
||
/* reuse cached username from newsgroup folder info*/
|
||
if (cd->pane &&
|
||
(!net_news_last_username_probably_valid ||
|
||
(last_username_hostname &&
|
||
PL_strcasecmp(last_username_hostname, cd->control_con->hostname)))) {
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->GetUsername(&username);
|
||
#else
|
||
username = HG63218 (MSG_GetNewsgroupUsername(cd->pane));
|
||
#endif
|
||
if (username && last_username &&
|
||
!PL_strcmp (username, last_username) &&
|
||
(cd->previous_response_code == MK_NNTP_RESPONSE_AUTHINFO_OK ||
|
||
cd->previous_response_code == MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_OK ||
|
||
cd->previous_response_code == MK_NNTP_RESPONSE_GROUP_SELECTED)) {
|
||
FREEIF (username);
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(NULL);
|
||
cd->newsgroup->SetPassword(NULL);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, NULL);
|
||
MSG_SetNewsgroupPassword(cd->pane, NULL);
|
||
#endif
|
||
}
|
||
}
|
||
#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
|
||
*/
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->GetUsername(&username);
|
||
#else
|
||
username = HG63218 (MSG_GetNewsgroupUsername(cd->pane));
|
||
#endif
|
||
if (username && *username)
|
||
{
|
||
StrAllocCopy(last_username, username);
|
||
StrAllocCopy(last_username_hostname, cd->control_con->hostname);
|
||
/* use it for only once */
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(NULL);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, NULL);
|
||
#endif
|
||
}
|
||
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 = PL_strchr(cd->control_con->hostname, '@')) != NULL)
|
||
{
|
||
/* in this case the username and possibly
|
||
* the password are in the URL
|
||
*/
|
||
char * colon;
|
||
*cp = '\0';
|
||
|
||
colon = PL_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 &&
|
||
!PL_strcasecmp(last_username_hostname, cd->control_con->hostname) )
|
||
StrAllocCopy(username, last_username);
|
||
else
|
||
net_news_last_username_probably_valid = FALSE;
|
||
}
|
||
|
||
|
||
if (!username) {
|
||
#if defined(CookiesAndSignons)
|
||
username = SI_Prompt(ce->window_id,
|
||
XP_GetString(XP_PROMPT_ENTER_USERNAME),
|
||
"",
|
||
cd->control_con->hostname);
|
||
|
||
#else
|
||
username = FE_Prompt(ce->window_id,
|
||
XP_GetString(XP_PROMPT_ENTER_USERNAME),
|
||
username ? username : "");
|
||
#endif
|
||
|
||
/* 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
|
||
#ifdef XPCOM_NEWSGROUP
|
||
if (NS_SUCCEEDED(cd->newsgroup->GetUsername(&username)) {
|
||
#else
|
||
if (cd->pane && !MSG_GetNewsgroupUsername(cd->pane)) {
|
||
#endif
|
||
munged_username = HG64643 (username);
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(munged_username);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, munged_username);
|
||
#endif
|
||
PR_FreeIF(munged_username);
|
||
}
|
||
#endif
|
||
|
||
StrAllocCopy(command, "AUTHINFO user ");
|
||
StrAllocCat(command, username);
|
||
StrAllocCat(command, CRLF);
|
||
|
||
ce->status = (int) NET_BlockingWrite(ce->socket, command, PL_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;
|
||
|
||
if (MK_NNTP_RESPONSE_AUTHINFO_OK == cd->response_code ||
|
||
MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_OK == cd->response_code)
|
||
{
|
||
/* successful login */
|
||
nsresult rv;
|
||
PRBool pushAuth;
|
||
/* If we're here because the host demanded authentication before we
|
||
* even sent a single command, then jump back to the beginning of everything
|
||
*/
|
||
rv = cd->news_host->IsPushAuth(&pushAuth);
|
||
|
||
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
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
else if (NS_SUCCEEDED(rv) && pushAuth)
|
||
#else
|
||
else if (MSG_GetNewsHostPushAuth(cd->host))
|
||
#endif
|
||
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 (MK_NNTP_RESPONSE_AUTHINFO_CONT == cd->response_code)
|
||
{
|
||
/* password required
|
||
*/
|
||
char * command = 0;
|
||
char * password = 0;
|
||
char * cp;
|
||
|
||
if (cd->pane)
|
||
{
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->GetPassword(&password);
|
||
password = HG63218 (password);
|
||
cd->newsgroup->SetPassword(NULL);
|
||
#else
|
||
password = HG63218 (MSG_GetNewsgroupPassword(cd->pane));
|
||
/* use it only once */
|
||
MSG_SetNewsgroupPassword(cd->pane, NULL);
|
||
#endif
|
||
}
|
||
|
||
if (net_news_last_username_probably_valid
|
||
&& last_password
|
||
&& last_password_hostname
|
||
&& !PL_strcasecmp(last_password_hostname, cd->control_con->hostname))
|
||
{
|
||
#ifdef CACHE_NEWSGRP_PASSWORD
|
||
if (cd->pane)
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->GetPassword(&password);
|
||
password = HG63218 (password);
|
||
#else
|
||
password = HG63218(MSG_GetNewsgroupPassword(cd->pane));
|
||
#endif
|
||
#else
|
||
StrAllocCopy(password, last_password);
|
||
#endif
|
||
}
|
||
else if ((cp = PL_strchr(cd->control_con->hostname, '@')) != NULL)
|
||
{
|
||
/* in this case the username and possibly
|
||
* the password are in the URL
|
||
*/
|
||
char * colon;
|
||
*cp = '\0';
|
||
|
||
colon = PL_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 =
|
||
#if defined(CookiesAndSignons)
|
||
password = SI_PromptPassword
|
||
(ce->window_id,
|
||
XP_GetString
|
||
(XP_PLEASE_ENTER_A_PASSWORD_FOR_NEWS_SERVER_ACCESS),
|
||
cd->control_con->hostname,
|
||
TRUE, TRUE);
|
||
#else
|
||
FE_PromptPassword(ce->window_id, XP_GetString(
|
||
XP_PLEASE_ENTER_A_PASSWORD_FOR_NEWS_SERVER_ACCESS ) );
|
||
#endif
|
||
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
|
||
#ifdef XPCOM_NEWSGROUP
|
||
char *garbage_password;
|
||
nsresult rv;
|
||
rv = cd->newsgroup->GetPassword(&garbage_password);
|
||
if (!NS_SUCCEEDED(rv)) {
|
||
PR_Free(garbage_password);
|
||
munged_password = HG64643(password);
|
||
cd->newsgroup->SetPassword(munged_password);
|
||
#else
|
||
if (cd->pane && !MSG_GetNewsgroupPassword(cd->pane)) {
|
||
munged_password = HG64643(password);
|
||
MSG_SetNewsgroupPassword(cd->pane, munged_password);
|
||
#endif
|
||
PR_FreeIF(munged_password);
|
||
}
|
||
#endif
|
||
|
||
StrAllocCopy(command, "AUTHINFO pass ");
|
||
StrAllocCat(command, password);
|
||
StrAllocCat(command, CRLF);
|
||
|
||
ce->status = (int) NET_BlockingWrite(ce->socket, command, PL_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)
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(NULL);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, NULL);
|
||
#endif
|
||
#endif
|
||
net_news_last_username_probably_valid = FALSE;
|
||
|
||
return(MK_NNTP_AUTH_FAILED);
|
||
}
|
||
|
||
PR_ASSERT(0); /* should never get here */
|
||
return(-1);
|
||
|
||
}
|
||
|
||
PRIVATE int
|
||
net_news_password_response(ActiveEntry * ce)
|
||
{
|
||
NewsConData * cd = (NewsConData *)ce->con_data;
|
||
|
||
if (MK_NNTP_RESPONSE_AUTHINFO_OK == cd->response_code ||
|
||
MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_OK == cd->response_code)
|
||
{
|
||
/* successful login */
|
||
nsresult rv = NS_OK;
|
||
PRBool pushAuth;
|
||
/* If we're here because the host demanded authentication before we
|
||
* even sent a single command, then jump back to the beginning of everything
|
||
*/
|
||
rv = cd->news_host->IsPushAuth(&pushAuth);
|
||
|
||
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
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
else if (NS_SUCCEEDED(rv) && pushAuth)
|
||
#else
|
||
else if (MSG_GetNewsHostPushAuth(cd->host))
|
||
#endif
|
||
cd->next_state = SEND_LIST_EXTENSIONS;
|
||
else
|
||
/* Normal authentication */
|
||
cd->next_state = SEND_FIRST_NNTP_COMMAND;
|
||
|
||
net_news_last_username_probably_valid = TRUE;
|
||
#ifdef XPCOM_XOVER
|
||
rv = cd->xover_parser->Reset();
|
||
#else
|
||
MSG_ResetXOVER( ce->URL_s->msg_pane, &cd->xover_parse_state );
|
||
#endif
|
||
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)
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetPassword(NULL);
|
||
#else
|
||
MSG_SetNewsgroupPassword(cd->pane, NULL);
|
||
#endif
|
||
#endif
|
||
return(MK_NNTP_AUTH_FAILED);
|
||
}
|
||
|
||
PR_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=NULL, *s2=NULL, *flag=NULL;
|
||
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;
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool xactive=FALSE;
|
||
rv = cd->news_host->QueryExtension("XACTIVE",&xactive);
|
||
if (NS_SUCCEEDED(rv) && xactive)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
|
||
#endif
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
rv = cd->news_host->GetFirstGroupNeedingExtraInfo(&cd->newsgroup);
|
||
#else
|
||
cd->group_name = MSG_GetFirstGroupNeedingExtraInfo(cd->host);
|
||
#endif
|
||
if (NS_SUCCEEDED(rv) && cd->newsgroup)
|
||
{
|
||
cd->next_state = NNTP_LIST_XACTIVE;
|
||
#ifdef DEBUG_bienvenu1
|
||
PR_LogPrint("listing xactive for %s\n", cd->group_name);
|
||
#endif
|
||
return 0;
|
||
}
|
||
}
|
||
cd->next_state = NEWS_DONE;
|
||
|
||
if(ce->bytes_received == 0)
|
||
{
|
||
/* #### no new groups */
|
||
}
|
||
|
||
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 = PL_strchr (line, ' ');
|
||
if (s)
|
||
{
|
||
*s = 0;
|
||
s1 = s+1;
|
||
s = PL_strchr (s1, ' ');
|
||
if (s)
|
||
{
|
||
*s = 0;
|
||
s2 = s+1;
|
||
s = PL_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
|
||
*/
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddNewNewsgroup(line, oldest, youngest, flag, PR_FALSE);
|
||
#else
|
||
MSG_AddNewNewsGroup(ce->URL_s->msg_pane, cd->host,
|
||
line, oldest, youngest, flag, FALSE);
|
||
#endif
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool xactive=FALSE;
|
||
rv = cd->news_host->QueryExtension("XACTIVE",&xactive);
|
||
if (NS_SUCCEEDED(rv) && xactive)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "XACTIVE"))
|
||
#endif
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->SetGroupNeedsExtraInfo(line, TRUE);
|
||
#else
|
||
MSG_SetGroupNeedsExtraInfo(cd->host, line, TRUE);
|
||
#endif
|
||
}
|
||
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')
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool listpnames=FALSE;
|
||
rv = cd->news_host->QueryExtension("LISTPNAMES",&listpnames);
|
||
if (NS_SUCCEEDED(rv) && listpnames)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "LISTPNAMES"))
|
||
#endif
|
||
{
|
||
cd->next_state = NNTP_LIST_PRETTY_NAMES;
|
||
}
|
||
else
|
||
{
|
||
cd->next_state = DISPLAY_NEWSGROUPS;
|
||
}
|
||
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);
|
||
}
|
||
|
||
/* find whitespace seperator if it exits */
|
||
for(i=0; line[i] != '\0' && !NET_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
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddNewNewsgroup(line, 0, 0, "", FALSE);
|
||
#else
|
||
MSG_AddNewNewsGroup(ce->URL_s->msg_pane, cd->host,
|
||
line, 0, 0, "", FALSE);
|
||
#endif
|
||
|
||
|
||
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,
|
||
"%d %d %d",
|
||
&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. */
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
char *group_name;
|
||
cd->newsgroup->GetName(&group_name);
|
||
|
||
cd->news_host->DisplaySubscribedGroup(group_name,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art,
|
||
count, TRUE);
|
||
PR_Free(group_name);
|
||
#else
|
||
ce->status = MSG_DisplaySubscribedGroup(cd->pane,
|
||
cd->host,
|
||
cd->group_name,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art,
|
||
count, TRUE);
|
||
#endif
|
||
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;
|
||
nsresult rv;
|
||
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) {
|
||
#ifdef XPCOM_NEWSPARSE
|
||
nsresult rv;
|
||
/* XXX - parse state stored in MSG_Pane cd->pane */
|
||
rv = cd->article_list->AddToKnownArticles(cd->first_art,
|
||
cd->last_art);
|
||
|
||
#else
|
||
ce->status = MSG_AddToKnownArticles(cd->pane, cd->news_host,
|
||
cd->group_name,
|
||
cd->first_art, cd->last_art);
|
||
#endif
|
||
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;
|
||
}
|
||
|
||
|
||
#ifdef XPCOM_NEWSPARSE
|
||
/* XXX - parse state stored in MSG_Pane cd->pane */
|
||
rv =
|
||
cd->article_list->GetRangeOfArtsToDownload(&ce->status,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art,
|
||
cd->num_wanted -
|
||
cd->num_loaded,
|
||
&(cd->first_art),
|
||
&(cd->last_art));
|
||
#else
|
||
ce->status = MSG_GetRangeOfArtsToDownload(cd->pane,
|
||
(void **)&cd->xover_parser,
|
||
cd->news_host,
|
||
cd->group_name,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art,
|
||
cd->num_wanted - cd->num_loaded,
|
||
&(cd->first_art),
|
||
&(cd->last_art));
|
||
#endif
|
||
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;
|
||
#ifdef XPCOM_XOVER
|
||
rv = NS_NewMsgXOVERParser(&cd->xover_parser,
|
||
cd->news_host, cd->newsgroup,
|
||
cd->first_art, cd->last_art,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art);
|
||
/* convert nsresult->status */
|
||
ce->status = !NS_SUCCEEDED(rv);
|
||
#else
|
||
ce->status = MSG_InitXOVER (cd->pane,
|
||
cd->news_host, cd->group_name,
|
||
cd->first_art, cd->last_art,
|
||
cd->first_possible_art, cd->last_possible_art,
|
||
&cd->xover_parse_state);
|
||
#endif
|
||
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,
|
||
PL_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 = MK_NNTP_RESPONSE_CHECK_ERROR; /* pretend XOVER generated an error */
|
||
#endif
|
||
|
||
if(cd->response_code != MK_NNTP_RESPONSE_XOVER_OK)
|
||
{
|
||
/* 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.
|
||
*/
|
||
/*PR_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;
|
||
nsresult rv;
|
||
|
||
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);
|
||
}
|
||
|
||
#ifdef XPCOM_XOVER
|
||
rv = cd->xover_parser->Process(line, &ce->status);
|
||
PR_ASSERT(NS_SUCCEEDED(rv));
|
||
#else
|
||
ce->status = MSG_ProcessXOVER (cd->pane, line, &cd->xover_parse_state);
|
||
#endif
|
||
|
||
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;
|
||
nsresult rv;
|
||
|
||
#ifdef XPCOM_XOVER
|
||
/* xover_parse_state stored in MSG_Pane cd->pane */
|
||
rv = cd->xover_parser->Finish(0,&ce->status);
|
||
#else
|
||
/* if (cd->xover_parse_state) { ### dmb - we need a different check */
|
||
ce->status = MSG_FinishXOVER (cd->pane, &cd->xover_parse_state, 0);
|
||
PR_ASSERT (!cd->xover_parse_state);
|
||
#endif
|
||
if (NS_SUCCEEDED(rv) && 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 = PL_strrchr(ce->URL_s->address, '/');
|
||
if (slash)
|
||
{
|
||
PL_strcpy (cd->output_buffer, slash + 1);
|
||
PL_strcat (cd->output_buffer, CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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
|
||
PR_ASSERT(FALSE);
|
||
return -1;
|
||
#endif
|
||
}
|
||
|
||
PRIVATE int net_profile_add_response (ActiveEntry *ce)
|
||
{
|
||
NewsConData *cd = (NewsConData*) ce->con_data;
|
||
|
||
if (MK_NNTP_RESPONSE_TYPE(cd->response_code) == MK_NNTP_RESPONSE_TYPE_OK)
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddProfileGroup(cd->response_txt);
|
||
#else
|
||
MSG_AddProfileGroup (cd->pane, cd->host, cd->response_txt);
|
||
#endif
|
||
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 = PL_strrchr(ce->URL_s->address, '/');
|
||
if (slash)
|
||
{
|
||
PL_strcpy (cd->output_buffer, slash + 1);
|
||
PL_strcat (cd->output_buffer, CRLF);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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
|
||
PR_ASSERT(FALSE);
|
||
return -1;
|
||
#endif
|
||
}
|
||
|
||
PRIVATE int net_profile_delete_response (ActiveEntry *ce)
|
||
{
|
||
NewsConData *cd = (NewsConData*) ce->con_data;
|
||
|
||
if (MK_NNTP_RESPONSE_TYPE(cd->response_code) == MK_NNTP_RESPONSE_TYPE_OK)
|
||
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, PL_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;
|
||
nsresult rv;
|
||
|
||
if (cd->response_code == MK_NNTP_RESPONSE_ARTICLE_HEAD)
|
||
{ /* 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. */
|
||
#ifdef XPCOM_XOVER
|
||
rv = cd->xover_parser->ProcessNonXOVER(cd->response_txt);
|
||
/* convert nsresult->status */
|
||
return !NS_SUCCEEDED(rv);
|
||
#else
|
||
return MSG_ProcessNonXOVER (cd->pane, cd->response_txt,
|
||
&cd->xover_parse_state);
|
||
#endif
|
||
}
|
||
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;
|
||
nsresult rv;
|
||
|
||
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++;
|
||
|
||
#ifdef XPCOM_XOVER
|
||
rv = cd->xover_parser->ProcessNonXOVER(line);
|
||
/* convert nsresult->status */
|
||
return !NS_SUCCEEDED(rv);
|
||
#else
|
||
return MSG_ProcessNonXOVER (cd->pane, line, &cd->xover_parse_state);
|
||
#endif
|
||
}
|
||
|
||
|
||
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
|
||
*/
|
||
PL_strcpy(cd->output_buffer, CRLF "." CRLF);
|
||
NNTP_LOG_WRITE(cd->output_buffer);
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,
|
||
cd->output_buffer,
|
||
PL_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;
|
||
#if 0
|
||
/* this should be handled by NET_ClearCallNetlibAllTheTime */
|
||
net_call_all_the_time_count--;
|
||
if(net_call_all_the_time_count == 0)
|
||
#endif
|
||
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 != MK_NNTP_RESPONSE_POST_OK) {
|
||
ce->URL_s->error_msg =
|
||
NET_ExplainErrorDetails(MK_NNTP_ERROR_MESSAGE,
|
||
cd->response_txt ? cd->response_txt : "");
|
||
if (cd->response_code == MK_NNTP_RESPONSE_POST_FAILED
|
||
&& 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,
|
||
PL_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;
|
||
}
|
||
}
|
||
|
||
#define NEWS_GROUP_DISPLAY_FREQ 20
|
||
|
||
PRIVATE int
|
||
net_DisplayNewsRC(ActiveEntry * ce)
|
||
{
|
||
NewsConData * cd = (NewsConData *) ce->con_data;
|
||
nsresult rv;
|
||
if(!cd->newsrc_performed)
|
||
{
|
||
cd->newsrc_performed = TRUE;
|
||
#ifdef XPCOM_NEWSHOST
|
||
rv = cd->news_host->GetNumGroupsNeedingCounts(&cd->newsrc_list_count);
|
||
#else
|
||
cd->newsrc_list_count = MSG_GetNewsRCCount(cd->pane, cd->news_host);
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
FREEIF(cd->control_con->current_group);
|
||
#ifdef XPCOM_NEWSHOST
|
||
rv =
|
||
cd->news_host->GetFirstGroupNeedingCounts(&cd->control_con->current_group);
|
||
#else
|
||
cd->control_con->current_group = MSG_GetNewsRCGroup(cd->pane, cd->host);
|
||
#endif
|
||
|
||
|
||
if(NS_SUCCEEDED(rv) && cd->control_con->current_group)
|
||
{
|
||
/* send group command to server
|
||
*/
|
||
int32 percent;
|
||
|
||
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,
|
||
PL_strlen(NET_Socket_Buffer));
|
||
NNTP_LOG_WRITE(NET_Socket_Buffer);
|
||
|
||
percent = (cd->newsrc_list_count) ?
|
||
(int32) (100.0 * ( (double)cd->newsrc_list_index / (double)cd->newsrc_list_count )) :
|
||
0;
|
||
FE_SetProgressBarPercent (ce->window_id, percent);
|
||
|
||
/* only update every 20 groups for speed */
|
||
if ((cd->newsrc_list_count <= NEWS_GROUP_DISPLAY_FREQ) || (cd->newsrc_list_index % NEWS_GROUP_DISPLAY_FREQ) == 0 ||
|
||
(cd->newsrc_list_index == cd->newsrc_list_count))
|
||
{
|
||
char thisGroup[20];
|
||
char totalGroups[20];
|
||
char *statusText;
|
||
|
||
PR_snprintf (thisGroup, sizeof(thisGroup), "%ld", (long) cd->newsrc_list_index);
|
||
PR_snprintf (totalGroups, sizeof(totalGroups), "%ld", (long) cd->newsrc_list_count);
|
||
statusText = PR_smprintf (XP_GetString(XP_THERMO_PERCENT_FORM), thisGroup, totalGroups);
|
||
if (statusText)
|
||
{
|
||
FE_Progress (ce->window_id, statusText);
|
||
PR_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 == MK_NNTP_RESPONSE_LIST_OK)
|
||
{
|
||
/*
|
||
* 5-9-96 jefft
|
||
* If for some reason the news server returns an empty
|
||
* newsgroups list with a nntp response code MK_NNTP_RESPONSE_LIST_OK -- 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 == MK_NNTP_RESPONSE_GROUP_SELECTED)
|
||
{
|
||
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 = PL_strchr(num_arts, ' ');
|
||
|
||
if(low)
|
||
{
|
||
first_art = atol(low);
|
||
*low++ = '\0';
|
||
high= PL_strchr(low, ' ');
|
||
}
|
||
if(high)
|
||
{
|
||
*high++ = '\0';
|
||
group = PL_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. */
|
||
strtok(group, " ");
|
||
last_art = atol(high);
|
||
}
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->DisplaySubscribedGroup(group,
|
||
low ? atol(low) : 0,
|
||
high ? atol(high) : 0,
|
||
atol(num_arts), FALSE);
|
||
#else
|
||
ce->status = MSG_DisplaySubscribedGroup(cd->pane,
|
||
cd->host,
|
||
group,
|
||
low ? atol(low) : 0,
|
||
high ? atol(high) : 0,
|
||
atol(num_arts), FALSE);
|
||
#endif
|
||
if (ce->status < 0)
|
||
return ce->status;
|
||
}
|
||
else if (cd->response_code == MK_NNTP_RESPONSE_GROUP_NO_GROUP)
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->GroupNotFound(cd->control_con->current_group, FALSE);
|
||
#else
|
||
MSG_GroupNotFound(cd->pane, cd->host, cd->control_con->current_group, FALSE);
|
||
#endif
|
||
}
|
||
/* it turns out subscribe ui depends on getting this displaysubscribedgroup call,
|
||
even if there was an error.
|
||
*/
|
||
if(cd->response_code != MK_NNTP_RESPONSE_GROUP_SELECTED)
|
||
{
|
||
/* only on news server error or when zero articles
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->DisplaySubscribedGroup(cd->control_con->current_group,
|
||
0, 0, 0, FALSE);
|
||
#else
|
||
ce->status = MSG_DisplaySubscribedGroup(cd->pane,
|
||
cd->host,
|
||
cd->control_con->current_group,
|
||
0, 0, 0, FALSE);
|
||
#endif
|
||
|
||
}
|
||
|
||
cd->next_state = NEWS_DISPLAY_NEWS_RC;
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
PRIVATE int
|
||
net_NewsRCProcessPost(ActiveEntry *ce)
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
|
||
#ifdef USE_LIBMSG
|
||
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;
|
||
PR_ASSERT(status < 0 || file_name);
|
||
cd->cancel_msg_file = (status < 0 ? 0 : PL_strdup(file_name));
|
||
}
|
||
#endif
|
||
|
||
|
||
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, PL_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;
|
||
#ifdef USE_LIBMSG
|
||
MSG_CompositionFields *fields = NULL;
|
||
#endif
|
||
|
||
|
||
/* #### Should we do a more real check than this? If the POST command
|
||
didn't respond with "MK_NNTP_RESPONSE_POST_SEND_NOW 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?
|
||
*/
|
||
PR_ASSERT (cd->response_code == MK_NNTP_RESPONSE_POST_SEND_NOW);
|
||
|
||
/* These shouldn't be set yet, since the headers haven't been "flushed" */
|
||
PR_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.
|
||
*/
|
||
PL_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;
|
||
|
||
PR_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 = PL_strlen (id);
|
||
|
||
from = MIME_MakeFromField ();
|
||
subject = (char *) PR_Malloc (L + 20);
|
||
other_random_headers = (char *) PR_Malloc (L + 20);
|
||
body = (char *) PR_Malloc (PL_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
|
||
*/
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool cancelchk=FALSE;
|
||
rv = cd->news_host->QueryExtension("CANCELCHK",&cancelchk);
|
||
if (NS_SUCCEEDED(rv) && cancelchk)
|
||
#else
|
||
if (!MSG_QueryNewsExtension(cd->host, "CANCELCHK"))
|
||
#endif
|
||
{
|
||
nsIMsgRFC822Parser *parser;
|
||
nsresult rv;
|
||
PRBool ok = FALSE;
|
||
|
||
rv = NS_NewRFC822Parser(&parser);
|
||
if (NS_SUCCEEDED(rv)) {
|
||
char *us, *them;
|
||
nsresult rv1 = parser->ExtractRFC822AddressMailboxes(from, &us);
|
||
nsresult rv2 = parser->ExtractRFC822AddressMailboxes(old_from, &them);
|
||
ok = (NS_SUCCEEDED(rv1) &&
|
||
NS_SUCCEEDED(rv2) &&
|
||
!PL_strcasecmp(us, them));
|
||
if (NS_SUCCEEDED(rv1)) PR_Free(us);
|
||
if (NS_SUCCEEDED(rv2)) PR_Free(them);
|
||
NS_RELEASE(parser);
|
||
}
|
||
if (!ok)
|
||
{
|
||
status = MK_NNTP_CANCEL_DISALLOWED;
|
||
ce->URL_s->error_msg = PL_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;
|
||
}
|
||
|
||
PL_strcpy (subject, "cancel ");
|
||
PL_strcat (subject, id);
|
||
|
||
PL_strcpy (other_random_headers, "Control: cancel ");
|
||
PL_strcat (other_random_headers, id);
|
||
PL_strcat (other_random_headers, CRLF);
|
||
if (distribution)
|
||
{
|
||
PL_strcat (other_random_headers, "Distribution: ");
|
||
PL_strcat (other_random_headers, distribution);
|
||
PL_strcat (other_random_headers, CRLF);
|
||
}
|
||
|
||
PL_strcpy (body, "This message was cancelled from within ");
|
||
PL_strcat (body, XP_AppCodeName);
|
||
PL_strcat (body, "." CRLF);
|
||
|
||
#ifdef USE_LIBMSG
|
||
fields = MSG_CreateCompositionFields(from, 0, 0, 0, 0, 0, newsgroups,
|
||
0, 0, subject, id, other_random_headers,
|
||
0, 0, news_url);
|
||
#endif
|
||
|
||
/* so that this would compile - will probably change later */
|
||
#if 0
|
||
FALSE,
|
||
FALSE
|
||
);
|
||
#endif
|
||
|
||
#ifdef USE_LIBMSG
|
||
if (!fields)
|
||
{
|
||
status = MK_OUT_OF_MEMORY;
|
||
goto FAIL;
|
||
}
|
||
HG38712
|
||
#endif
|
||
|
||
cd->cancel_status = 0;
|
||
|
||
#ifdef USE_LIBMSG
|
||
MSG_StartMessageDelivery (cd->pane, (void *) ce,
|
||
fields,
|
||
FALSE, /* digest_p */
|
||
TRUE, /* dont_deliver_p */
|
||
TEXT_PLAIN, body, PL_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;
|
||
PR_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 *) PR_Malloc (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);
|
||
|
||
PL_strcat (data, CRLF "." CRLF CRLF);
|
||
status = NET_BlockingWrite(ce->socket, data, PL_strlen(data));
|
||
NNTP_LOG_WRITE(data);
|
||
PR_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;
|
||
}
|
||
#else
|
||
|
||
{
|
||
/* NET_BlockingWrite() should go away soon? I think. */
|
||
/* The following are what we really need to cancel a posted message */
|
||
char *data;
|
||
data = PR_smprintf("From: %s" CRLF
|
||
"Newsgroups: %s" CRLF
|
||
"Subject: %s" CRLF
|
||
"References: %s" CRLF
|
||
"%s" CRLF /* other_random_headers */
|
||
"%s" /* body */
|
||
CRLF "." CRLF CRLF, /* trailing SMTP "." */
|
||
from, newsgroups, subject, id,
|
||
other_random_headers, body);
|
||
|
||
status = NET_BlockingWrite(ce->socket, data, PL_strlen(data));
|
||
NNTP_LOG_WRITE(data);
|
||
PR_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;
|
||
}
|
||
|
||
#endif
|
||
|
||
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);
|
||
|
||
#ifdef USE_LIBMSG
|
||
if (fields)
|
||
MSG_DestroyCompositionFields(fields);
|
||
#endif
|
||
|
||
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 = PL_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 = PL_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, PL_strlen(unescapedCommand));
|
||
NNTP_LOG_WRITE(unescapedCommand);
|
||
|
||
cd->next_state = NNTP_RESPONSE;
|
||
cd->next_state_after_response = NNTP_XPAT_RESPONSE;
|
||
cd->pause_for_read = TRUE;
|
||
|
||
PR_Free(command);
|
||
PR_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;
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
char *group_name;
|
||
nsresult rv = cd->newsgroup->GetName(&group_name);
|
||
#endif
|
||
PR_snprintf(cd->output_buffer,
|
||
OUTPUT_BUFFER_SIZE,
|
||
"LIST PRETTYNAMES %.512s" CRLF,
|
||
#ifdef XPCOM_NEWSGROUP
|
||
NS_SUCCEEDED(rv) ? group_name : "");
|
||
#else
|
||
cd->group_name ? cd->group_name : "");
|
||
#endif
|
||
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_strlen(cd->output_buffer));
|
||
NNTP_LOG_WRITE(cd->output_buffer);
|
||
#ifdef DEBUG_bienvenu1
|
||
PR_LogPrint(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 != MK_NNTP_RESPONSE_LIST_OK)
|
||
{
|
||
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' && !NET_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)
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddPrettyName(line,prettyName);
|
||
#else
|
||
MSG_AddPrettyName(cd->host, line, prettyName);
|
||
#endif
|
||
#ifdef DEBUG_bienvenu1
|
||
PR_LogPrint("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;
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
char *group_name;
|
||
nsresult rv = cd->newsgroup->GetName(&group_name);
|
||
#endif
|
||
|
||
PR_snprintf(cd->output_buffer,
|
||
OUTPUT_BUFFER_SIZE,
|
||
"LIST XACTIVE %.512s" CRLF,
|
||
#ifdef XPCOM_NEWSGROUP
|
||
group_name);
|
||
#else
|
||
cd->group_name);
|
||
#endif
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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;
|
||
|
||
PR_ASSERT(cd->response_code == MK_NNTP_RESPONSE_LIST_OK);
|
||
if (cd->response_code != MK_NNTP_RESPONSE_LIST_OK)
|
||
{
|
||
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);
|
||
}
|
||
|
||
/* 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);
|
||
}
|
||
|
||
if (line)
|
||
{
|
||
if (line[0] != '.')
|
||
{
|
||
char *s = line;
|
||
/* format is "rec.arts.movies.past-films 7302 7119 csp"
|
||
*/
|
||
while (*s && !NET_IS_SPACE(*s))
|
||
s++;
|
||
if (s)
|
||
{
|
||
char flags[32]; /* ought to be big enough */
|
||
*s = 0;
|
||
sscanf(s + 1,
|
||
"%d %d %31s",
|
||
&cd->first_possible_art,
|
||
&cd->last_possible_art,
|
||
flags);
|
||
#ifdef XPCOM_NEWSHOST
|
||
cd->news_host->AddNewNewsgroup(line,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art, flags, TRUE);
|
||
#else
|
||
MSG_AddNewNewsGroup(cd->pane, cd->host, line,
|
||
cd->first_possible_art,
|
||
cd->last_possible_art, flags, TRUE /* xactive flags */);
|
||
#endif
|
||
/* 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_bienvenu1
|
||
PR_LogPrint("got xactive for %s of %s\n", line, flags);
|
||
#endif
|
||
/* This isn't required, because the extra info is
|
||
initialized to false for new groups. And it's
|
||
an expensive call.
|
||
*/
|
||
/* MSG_SetGroupNeedsExtraInfo(cd->host, line, FALSE); */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
#ifdef XPCOM_NEWSHOST
|
||
nsresult rv;
|
||
PRBool xactive=FALSE;
|
||
rv = cd->news_host->QueryExtension("XACTIVE",&xactive);
|
||
if (cd->type_wanted == NEW_GROUPS &&
|
||
NS_SUCCEEDED(rv) && xactive)
|
||
#else
|
||
if (cd->type_wanted == NEW_GROUPS && MSG_QueryNewsExtension(cd->host, "XACTIVE"))
|
||
#endif
|
||
{
|
||
#ifdef XPCOM_NEWSGROUP
|
||
nsIMsgNewsgroup* old_newsgroup = cd->newsgroup;
|
||
cd->news_host->GetFirstGroupNeedingExtraInfo(&cd->newsgroup);
|
||
if (old_newsgroup && cd->newsgroup &&
|
||
old_newsgroup != cd->newsgroup)
|
||
/* make sure we're not stuck on the same group */
|
||
{
|
||
NS_RELEASE(old_newsgroup);
|
||
#else
|
||
char *old_group_name = cd->group_name;
|
||
cd->group_name = MSG_GetFirstGroupNeedingExtraInfo(cd->host);
|
||
if (old_group_name && cd->group_name && PL_strcmp(old_group_name, cd->group_name))
|
||
/* make sure we're not stuck on the same group... */
|
||
{
|
||
PR_Free(old_group_name);
|
||
#endif
|
||
#ifdef DEBUG_bienvenu1
|
||
PR_LogPrint("listing xactive for %s\n", cd->group_name);
|
||
#endif
|
||
cd->next_state = NNTP_LIST_XACTIVE;
|
||
cd->pause_for_read = FALSE;
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
#ifdef XPCOM_NEWSGROUP
|
||
NS_RELEASE(old_newsgroup);
|
||
cd->newsgroup = NULL;
|
||
#else
|
||
FREEIF(old_group_name);
|
||
cd->group_name = NULL;
|
||
#endif
|
||
}
|
||
}
|
||
#ifdef XPCOM_NEWSHOST
|
||
PRBool listpname;
|
||
rv = cd->news_host->QueryExtension("LISTPNAME",&listpname);
|
||
if (NS_SUCCEEDED(rv) && listpname)
|
||
#else
|
||
if (MSG_QueryNewsExtension(cd->host, "LISTPNAMES"))
|
||
#endif
|
||
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;
|
||
nsresult rv;
|
||
#ifdef XPCOM_NEWSGROUP
|
||
char *group_name;
|
||
rv = cd->newsgroup->GetName(&group_name);
|
||
#endif
|
||
|
||
PR_snprintf(cd->output_buffer,
|
||
OUTPUT_BUFFER_SIZE,
|
||
"listgroup %.512s" CRLF,
|
||
#ifdef XPCOM_NEWSGROUP
|
||
group_name);
|
||
#else
|
||
cd->group_name);
|
||
#endif
|
||
|
||
#ifdef XPCOM_NEWSPARSE
|
||
rv = NS_NewMsgNewsArticleList(&cd->article_list,
|
||
cd->news_host, cd->newsgroup);
|
||
#else
|
||
MSG_InitAddArticleKeyToGroup(cd->pane, cd->host, cd->group_name,
|
||
&cd->newsgroup_parse_state);
|
||
#endif
|
||
ce->status = (int) NET_BlockingWrite(ce->socket,cd->output_buffer,PL_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;
|
||
|
||
PR_ASSERT(cd->response_code == MK_NNTP_RESPONSE_GROUP_SELECTED);
|
||
if (cd->response_code != MK_NNTP_RESPONSE_GROUP_SELECTED)
|
||
{
|
||
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;
|
||
nsresult rv;
|
||
sscanf(line, "%ld", &found_id);
|
||
|
||
#ifdef XPCOM_NEWSPARSE
|
||
rv = cd->article_list->AddArticleKeyToGroup(found_id);
|
||
#else
|
||
MSG_AddArticleKeyToGroup(cd->newsgroup_parse_state, (int32) found_id);
|
||
#endif
|
||
}
|
||
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 != MK_NNTP_RESPONSE_XPAT_OK)
|
||
{
|
||
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 = PL_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)
|
||
{
|
||
PR_ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
|
||
PRIVATE int net_nntp_search_response(ActiveEntry *ce)
|
||
{
|
||
NewsConData * cd = (NewsConData *)ce->con_data;
|
||
|
||
if (MK_NNTP_RESPONSE_TYPE(cd->response_code) == MK_NNTP_RESPONSE_TYPE_OK)
|
||
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 *bValP,
|
||
char **groupP,
|
||
char **message_idP,
|
||
char **command_specific_dataP)
|
||
{
|
||
int status = 0;
|
||
HG43575
|
||
char *host_and_port = 0;
|
||
int32 port = 0;
|
||
char *group = 0;
|
||
char *message_id = 0;
|
||
char *command_specific_data = 0;
|
||
const char *path_part;
|
||
char *s;
|
||
|
||
HG66376
|
||
|
||
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') {
|
||
PR_Free(defhost);
|
||
defhost = NULL;
|
||
}
|
||
if (defhost) {
|
||
PREF_GetIntPref("news.server_port", &defport);
|
||
HG05417
|
||
|
||
if (defport) {
|
||
host_and_port = PR_smprintf("%s:%ld", defhost, (long) defport);
|
||
PR_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 = PL_strchr (host_and_port, ':');
|
||
if (s && sscanf (s+1, " %u ", &port) == 1 &&
|
||
HG05998)
|
||
*s = 0;
|
||
|
||
path_part = PL_strchr (url, ':');
|
||
PR_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 = PL_strchr (path_part + 2, '/');
|
||
if (path_part)
|
||
path_part++;
|
||
}
|
||
if (!path_part)
|
||
path_part = "";
|
||
|
||
group = PL_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 = PL_strchr (group, '@');
|
||
if (s)
|
||
{
|
||
message_id = group;
|
||
group = 0;
|
||
}
|
||
else if (!*group)
|
||
{
|
||
PR_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 @. */
|
||
PR_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 = PL_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)
|
||
{
|
||
PR_Free (message_id);
|
||
message_id = 0;
|
||
}
|
||
else if (group && !*group)
|
||
{
|
||
PR_Free (group);
|
||
group = 0;
|
||
}
|
||
}
|
||
|
||
FAIL:
|
||
PR_ASSERT (!message_id || message_id != group);
|
||
if (status >= 0)
|
||
{
|
||
*host_and_portP = host_and_port;
|
||
HG45873
|
||
*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;
|
||
}
|
||
|
||
|
||
/* 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 bVal = FALSE;
|
||
char *group = 0;
|
||
char *message_id = 0;
|
||
char *command_specific_data = 0;
|
||
int status = NET_parse_news_url (url, &host_and_port, &bVal,
|
||
&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;
|
||
}
|
||
|
||
XP_Bool
|
||
NET_IsNewsServerURL( const char *url)
|
||
{
|
||
char *host_and_port = 0;
|
||
XP_Bool bVal = FALSE;
|
||
char *group = 0;
|
||
char *message_id = 0;
|
||
char *command_specific_data = 0;
|
||
int status = NET_parse_news_url (url, &host_and_port, &bVal,
|
||
&group, &message_id, &command_specific_data);
|
||
XP_Bool result = FALSE;
|
||
if (status >= 0 && host_and_port && !group && !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 && !PL_strcasecmp(tmpConn->hostname, conn->hostname))
|
||
connCount++;
|
||
}
|
||
|
||
return connCount < kMaxConnectionsPerHost;
|
||
}
|
||
|
||
static XP_Bool isOnline = TRUE;
|
||
static XP_Bool prefInitialized = FALSE;
|
||
|
||
#ifndef MAXHOSTNAMELEN
|
||
#define MAXHOSTNAMELEN 64
|
||
#endif
|
||
|
||
MODULE_PRIVATE int PR_CALLBACK NET_OnlinePrefChangedFunc(const char *pref, void *data)
|
||
{
|
||
int status=0;
|
||
int32 port=0;
|
||
char * socksHost = NULL;
|
||
char text[MAXHOSTNAMELEN + 8];
|
||
extern void NET_MaybeDownloadAutoAdminCfgFile(void);
|
||
|
||
if (!PL_strcasecmp(pref,"network.online"))
|
||
status = PREF_GetBoolPref("network.online", &isOnline);
|
||
|
||
if ( isOnline ) {
|
||
CACHE_CloseAllOpenSARCache();
|
||
|
||
NET_MaybeDownloadAutoAdminCfgFile();
|
||
|
||
/* 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;
|
||
}
|
||
|
||
MODULE_PRIVATE int PR_CALLBACK NET_NewsMaxArticlesChangedFunc(const char *pref, void *data)
|
||
{
|
||
int status=0;
|
||
if (!PL_strcasecmp(pref,"news.max_articles"))
|
||
{
|
||
int32 maxArticles;
|
||
|
||
status = PREF_GetIntPref("news.max_articles", &maxArticles);
|
||
NET_SetNumberOfNewsArticlesInListing(maxArticles);
|
||
}
|
||
return status;
|
||
}
|
||
|
||
MODULE_PRIVATE int PR_CALLBACK net_news_timeout_changed (const char *pref, void *data)
|
||
{
|
||
return PREF_GetIntPref ("news.timeout", &net_news_timeout);
|
||
}
|
||
|
||
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);
|
||
|
||
PREF_GetIntPref ("news.timeout", &net_news_timeout);
|
||
PREF_RegisterCallback ("news.timeout", net_news_timeout_changed, NULL);
|
||
|
||
prefInitialized = TRUE;
|
||
}
|
||
return !isOnline;
|
||
}
|
||
|
||
MODULE_PRIVATE int
|
||
NET_NewsLoad (ActiveEntry *ce, char *proxy_server)
|
||
{
|
||
int status = 0;
|
||
NewsConData *cd = PR_NEW(NewsConData);
|
||
XP_Bool bVal = 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;
|
||
nsresult rv;
|
||
|
||
if(!cd)
|
||
{
|
||
status = MK_OUT_OF_MEMORY;
|
||
goto FAIL;
|
||
}
|
||
|
||
memset(cd, 0, sizeof(NewsConData));
|
||
ce->URL_s->content_length = 0;
|
||
StrAllocCopy(cd->proxy_server, proxy_server);
|
||
|
||
#ifdef USE_PANES
|
||
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));
|
||
if (NET_IsNewsMessageURL(ce->URL_s->address))
|
||
cd->pane = MSG_FindPane(ce->window_id, MSG_MESSAGEPANE);
|
||
else
|
||
cd->pane = MSG_FindPane(ce->window_id, MSG_ANYPANE);
|
||
}
|
||
PR_ASSERT(cd->pane && MSG_GetContext(cd->pane) == ce->window_id);
|
||
if (!cd->pane)
|
||
{
|
||
PR_ASSERT(FALSE);
|
||
status = -1; /* ### */
|
||
goto FAIL;
|
||
}
|
||
#endif
|
||
|
||
#ifdef DEBUG
|
||
{
|
||
char urlDate[64];
|
||
PRTime now = PR_Now();
|
||
XP_StrfTime(ce->window_id, urlDate, sizeof(urlDate), XP_DATE_TIME_FORMAT, localtime(&now));
|
||
NNTP_LOG_NOTE (("******** Begin loading news URL [ %s ] at %s", ce->URL_s->address, urlDate));
|
||
}
|
||
#endif
|
||
|
||
cd->output_buffer = (char *) PR_Malloc(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;
|
||
|
||
PR_ASSERT (url);
|
||
if (!url)
|
||
{
|
||
status = -1;
|
||
goto FAIL;
|
||
}
|
||
|
||
|
||
status = NET_parse_news_url (url, &host_and_port, &bVal,
|
||
&group, &message_id, &command_specific_data);
|
||
if (status < 0)
|
||
goto FAIL;
|
||
|
||
colon = PL_strchr (host_and_port, ':');
|
||
if (colon) {
|
||
*colon = '\0';
|
||
sscanf (colon+1, " %u ", &port);
|
||
}
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
rv = NS_NewMsgNewsHost(&cd->news_host, host_and_port, bVal, port);
|
||
#else
|
||
cd->host = MSG_CreateNewsHost(MSG_GetMaster(cd->pane), host_and_port,
|
||
bVal, port);
|
||
#endif
|
||
if (colon) *colon = ':';
|
||
|
||
#ifdef XPCOM_NEWSHOST
|
||
PR_ASSERT(NS_SUCCEEDED(rv));
|
||
if (!NS_SUCCEEDED(rv)) {
|
||
#else
|
||
PR_ASSERT(cd->host);
|
||
if (!cd->host) {
|
||
#endif
|
||
status = -1;
|
||
goto FAIL;
|
||
}
|
||
|
||
if (message_id && command_specific_data && !PL_strcmp (command_specific_data, "?cancel"))
|
||
cancel_p = TRUE;
|
||
|
||
StrAllocCopy(cd->path, message_id);
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetName(group);
|
||
#else
|
||
StrAllocCopy(cd->group_name, group);
|
||
#endif
|
||
|
||
/* make sure the user has a news host configured */
|
||
|
||
#ifndef XPCOM_NEWSHOST
|
||
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);
|
||
#endif
|
||
|
||
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;
|
||
}
|
||
PR_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 (PL_strstr (command_specific_data, "?newgroups"))
|
||
/* news://HOST/?newsgroups
|
||
news:/GROUP/?newsgroups (useless)
|
||
news:?newsgroups (default host)
|
||
*/
|
||
cd->type_wanted = NEW_GROUPS;
|
||
else
|
||
{
|
||
if (PL_strstr(command_specific_data, "?list-pretty"))
|
||
{
|
||
cd->type_wanted = PRETTY_NAMES_WANTED;
|
||
cd->command_specific_data = PL_strdup(command_specific_data);
|
||
}
|
||
else if (PL_strstr(command_specific_data, "?profile"))
|
||
{
|
||
cd->type_wanted = PROFILE_WANTED;
|
||
cd->command_specific_data = PL_strdup(command_specific_data);
|
||
}
|
||
else if (PL_strstr(command_specific_data, "?list-ids"))
|
||
{
|
||
cd->type_wanted = IDS_WANTED;
|
||
cd->command_specific_data = PL_strdup(command_specific_data);
|
||
}
|
||
else
|
||
{
|
||
cd->type_wanted = SEARCH_WANTED;
|
||
cd->command_specific_data = PL_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 != MWContextMailMsg
|
||
&& ce->window_id->type != MWContextMail && ce->window_id->type != MWContextMailNewsProgress)
|
||
{
|
||
status = -1;
|
||
goto FAIL;
|
||
}
|
||
if (PL_strchr (group, '*'))
|
||
cd->type_wanted = LIST_WANTED;
|
||
else
|
||
cd->type_wanted = GROUP_WANTED;
|
||
}
|
||
else
|
||
{
|
||
/* news:
|
||
news://HOST
|
||
*/
|
||
cd->type_wanted = READ_NEWS_RC;
|
||
}
|
||
|
||
|
||
/* let's look for the user name and password in the url */
|
||
{
|
||
char * unamePwd = NET_ParseURL(url, GET_USERNAME_PART | GET_PASSWORD_PART);
|
||
char *userName,*colon,*password=NULL;
|
||
|
||
/* get the username & password out of the combo string */
|
||
if( (colon = PL_strchr(unamePwd, ':')) != NULL )
|
||
{
|
||
*colon = '\0';
|
||
userName = PL_strdup(unamePwd);
|
||
password = PL_strdup(colon+1);
|
||
*colon = ':';
|
||
PR_Free(unamePwd);
|
||
}
|
||
else
|
||
{
|
||
userName = unamePwd;
|
||
}
|
||
if (userName)
|
||
{
|
||
char *mungedUsername = HG64643(userName);
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetUsername(mungedUsername);
|
||
#else
|
||
MSG_SetNewsgroupUsername(cd->pane, mungedUsername);
|
||
#endif
|
||
PR_FREEIF(mungedUsername);
|
||
PR_Free(userName);
|
||
}
|
||
if (password)
|
||
{
|
||
char *mungedPassword = HG64643(password);
|
||
#ifdef XPCOM_NEWSGROUP
|
||
cd->newsgroup->SetPassword(mungedPassword);
|
||
#else
|
||
MSG_SetNewsgroupPassword(cd->pane, mungedPassword);
|
||
#endif
|
||
PR_FREEIF(mungedPassword);
|
||
PR_Free(password);
|
||
}
|
||
|
||
}
|
||
/* 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)
|
||
{
|
||
uint32 number = 0;
|
||
#ifdef XPCOM_NEWSGROUP
|
||
nsresult rv;
|
||
PRBool articleIsOffline;
|
||
rv =cd->newsgroup->IsOfflineArticle(number,&articleIsOffline);
|
||
#else
|
||
const char *group = 0;
|
||
XP_Bool articleIsOffline = MSG_IsOfflineArticle (cd->pane, cd->path, &group, &number);
|
||
#endif
|
||
if (NET_IsOffline() || (NS_SUCCEEDED(rv) && articleIsOffline))
|
||
{
|
||
ce->local_file = TRUE;
|
||
cd->articleIsOffline = articleIsOffline;
|
||
ce->socket = NULL;
|
||
|
||
#if 0
|
||
/* this should be handled by NET_SetCallNetlibAllTheTime */
|
||
net_call_all_the_time_count++;
|
||
#endif
|
||
if (!articleIsOffline)
|
||
ce->format_out = CLEAR_CACHE_BIT(ce->format_out);
|
||
NET_SetCallNetlibAllTheTime(ce->window_id,"mknews");
|
||
#ifdef XPCOM_OFFLINE
|
||
rv = NS_NewOfflineNewState(&cd->offline_state,
|
||
cd->newsgroup, number);
|
||
#else
|
||
MSG_StartOfflineRetrieval(cd->pane, group, number, &cd->offlineState);
|
||
#endif
|
||
}
|
||
}
|
||
#ifdef XPCOM_OFFLINE
|
||
if (cd->offline_state)
|
||
#else
|
||
if (cd->offlineState)
|
||
#endif
|
||
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(!PL_strcmp(tmp_con->hostname, host_and_port)
|
||
&& HG78293
|
||
&&!tmp_con->busy)
|
||
{
|
||
/* check to see if this connection can be reused, or if it should be aged away */
|
||
int32 con_age = XP_TIME() - tmp_con->last_used_time;
|
||
if (con_age <= net_news_timeout)
|
||
{
|
||
cd->control_con = tmp_con;
|
||
|
||
NNTP_LOG_NOTE(("Reusing control_con %08lX (age %ld secs) for %s", tmp_con, con_age, 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
|
||
{
|
||
NNTP_LOG_NOTE(("Aging away control_con %08lX (age %ld secs)", tmp_con, con_age));
|
||
|
||
/* kill idle conn which has lived too long */
|
||
list_entry = list_entry->prev ? list_entry->prev : nntp_connection_list;
|
||
XP_ListRemoveObject(nntp_connection_list, tmp_con);
|
||
net_nntp_close(tmp_con, ce->status);
|
||
FREEIF(tmp_con->hostname);
|
||
PR_Free(tmp_con);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
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 = PR_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));
|
||
memset(cd->control_con, 0, sizeof(NNTPConnection));
|
||
|
||
#ifndef XPCOM_NEWSHOST
|
||
cd->control_con->default_host = default_host;
|
||
#endif
|
||
StrAllocCopy(cd->control_con->hostname, host_and_port);
|
||
NNTP_LOG_NOTE(("Set host string: %s", cd->control_con->hostname));
|
||
|
||
HG01869
|
||
|
||
cd->control_con->prev_cache = FALSE; /* this wasn't from the cache */
|
||
|
||
cd->control_con->csock = NULL;
|
||
|
||
cd->control_con->last_used_time = XP_TIME();
|
||
|
||
/* 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, status);
|
||
FREEIF(con->hostname);
|
||
PR_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;
|
||
nsresult rv;
|
||
|
||
cd->pause_for_read = TRUE;
|
||
|
||
if (cd->stream)
|
||
read_size = (*cd->stream->is_write_ready)
|
||
(cd->stream);
|
||
else
|
||
{
|
||
StrAllocCopy(ce->URL_s->content_type, cd->articleIsOffline ? MESSAGE_RFC822 : TEXT_HTML);
|
||
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);
|
||
if (!cd->stream)
|
||
ce->status = -1;
|
||
}
|
||
if(!read_size)
|
||
return(0); /* wait until we are ready to write */
|
||
else
|
||
read_size = MIN(read_size, NET_Socket_Buffer_Size);
|
||
#ifdef XPCOM_OFFLINE
|
||
rv = cd->offline_state->Process(&NET_Socket_Buffer, read_size, &status);
|
||
if (NS_SUCCEEDED(rv) && status > 0)
|
||
#else
|
||
status = MSG_ProcessOfflineNews(cd->offlineState, NET_Socket_Buffer, read_size);
|
||
if(status > 0)
|
||
#endif
|
||
{
|
||
ce->bytes_received += status;
|
||
FE_GraphProgress(ce->window_id, ce->URL_s,
|
||
ce->bytes_received, status,
|
||
ce->URL_s->content_length);
|
||
PUT_STREAM(NET_Socket_Buffer, status); /* blow off error? ### dmb */
|
||
}
|
||
|
||
if (status == 0)
|
||
{
|
||
if (cd->stream)
|
||
COMPLETE_STREAM;
|
||
#if 0
|
||
/* this should be handled by NET_ClearCallNetlibAllTheTime()*/
|
||
net_call_all_the_time_count--;
|
||
if(net_call_all_the_time_count < 1)
|
||
#endif
|
||
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
|
||
*/
|
||
MODULE_PRIVATE int
|
||
net_ProcessNews (ActiveEntry *ce)
|
||
{
|
||
NewsConData * cd = (NewsConData *)ce->con_data;
|
||
|
||
#ifdef XPCOM_OFFLINE
|
||
if (cd->offline_state != NULL)
|
||
#else
|
||
if (cd->offlineState != NULL)
|
||
#endif
|
||
{
|
||
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 */
|
||
#if 0
|
||
/* this should be handled by NET_ClearCallNetlibAllTheTime()*/
|
||
net_call_all_the_time_count--;
|
||
if (net_call_all_the_time_count == 0)
|
||
#endif
|
||
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(
|
||
HG51154,
|
||
NULL,
|
||
"NNTP",
|
||
HG28465,
|
||
&ce->socket,
|
||
HG42817,
|
||
&cd->tcp_con_data,
|
||
ce->window_id,
|
||
&ce->URL_s->error_msg,
|
||
ce->socks_host,
|
||
ce->socks_port,
|
||
ce->URL_s->localIP);
|
||
|
||
if(ce->socket != NULL)
|
||
NET_TotalNumberOfOpenConnections++;
|
||
|
||
cd->pause_for_read = TRUE;
|
||
if(ce->status == MK_CONNECTED)
|
||
{
|
||
HG51514
|
||
{
|
||
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(
|
||
HG65321,
|
||
"NNTP",
|
||
HG28465,
|
||
&ce->socket,
|
||
&cd->tcp_con_data,
|
||
ce->window_id,
|
||
&ce->URL_s->error_msg,
|
||
ce->URL_s->localIP);
|
||
|
||
cd->pause_for_read = TRUE;
|
||
if(ce->status == MK_CONNECTED)
|
||
{
|
||
cd->control_con->csock = ce->socket;
|
||
HG28477
|
||
{
|
||
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;
|
||
|
||
HG42871
|
||
|
||
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;
|
||
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 != MK_NNTP_RESPONSE_ARTICLE_HEAD)
|
||
{
|
||
/* 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] == '.')
|
||
PL_strcpy (cd->output_buffer, line + 1);
|
||
else
|
||
PL_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.
|
||
*/
|
||
PL_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:
|
||
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);
|
||
#if 0
|
||
/* this is probably depricated/merged into
|
||
NET_ClearReadSelect */
|
||
NET_ClearFileReadSelect(ce->window_id,
|
||
cd->control_con->csock);
|
||
#endif
|
||
#ifdef XP_WIN
|
||
if(cd->calling_netlib_all_the_time)
|
||
{
|
||
cd->calling_netlib_all_the_time = FALSE;
|
||
#if 0
|
||
/* this should be handled by NET_ClearCallNetlibAllTheTime()*/
|
||
net_call_all_the_time_count--;
|
||
if(net_call_all_the_time_count == 0)
|
||
#endif
|
||
NET_ClearCallNetlibAllTheTime(ce->window_id,"mknews");
|
||
}
|
||
#endif /* XP_WIN */
|
||
#if defined(XP_WIN) || (defined(XP_UNIX)&&defined(UNIX_ASYNC_DNS))
|
||
NET_ClearDNSSelect(ce->window_id, cd->control_con->csock);
|
||
#endif /* XP_WIN || XP_UNIX */
|
||
net_nntp_close (cd->control_con, ce->status); /* close the
|
||
socket */
|
||
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);
|
||
cd->control_con = NULL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case NEWS_FREE:
|
||
|
||
/* do we need to know if we're parsing xover to call finish xover? */
|
||
/* yes, I think we do! Why did I think we should??? */
|
||
/* 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. */
|
||
#ifdef XPCOM_XOVER
|
||
if (cd->xover_parser != NULL)
|
||
#else
|
||
if (cd->xover_parse_state != NULL)
|
||
#endif
|
||
{
|
||
int status;
|
||
nsresult rv;
|
||
/* PR_ASSERT (ce->status < 0);*/
|
||
#ifdef XPCOM_XOVER
|
||
/* XXX - how/when to Release() this? */
|
||
rv = cd->xover_parser->Finish(ce->status,&status);
|
||
PR_ASSERT(NS_SUCCEEDED(rv));
|
||
|
||
if (NS_SUCCEEDED(rv))
|
||
NS_RELEASE(cd->xover_parser);
|
||
|
||
#else
|
||
status = MSG_FinishXOVER (cd->pane,
|
||
&cd->xover_parse_state,
|
||
ce->status);
|
||
PR_ASSERT (!cd->xover_parse_state);
|
||
#endif
|
||
if (NS_SUCCEEDED(rv) &&
|
||
ce->status >= 0 && status < 0)
|
||
ce->status = status;
|
||
}
|
||
else
|
||
{
|
||
#ifdef XPCOM_NEWSPARSE
|
||
/* XXX - state is stored in the MSG_Pane cd->pane */
|
||
NS_RELEASE(cd->article_list);
|
||
#else
|
||
MSG_ClearListNewsgroupState(cd->pane, cd->host, cd->group_name, ce->status);
|
||
#endif
|
||
}
|
||
|
||
if (cd->control_con)
|
||
cd->control_con->last_used_time = XP_TIME();
|
||
|
||
FREEIF(cd->path);
|
||
FREEIF(cd->response_txt);
|
||
FREEIF(cd->data_buf);
|
||
|
||
FREEIF(cd->output_buffer);
|
||
FREEIF(cd->proxy_server);
|
||
FREEIF(cd->stream); /* don't forget the stream */
|
||
if(cd->tcp_con_data)
|
||
NET_FreeTCPConData(cd->tcp_con_data);
|
||
|
||
#ifdef XPCOM_NEWSGROUP
|
||
NS_RELEASE(cd->newsgroup);
|
||
#else
|
||
FREEIF(cd->group_name);
|
||
#endif
|
||
|
||
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);
|
||
PR_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, ce->status);
|
||
FREEIF(con->hostname);
|
||
PR_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
|
||
*/
|
||
MODULE_PRIVATE int
|
||
NET_InterruptNews(ActiveEntry * ce)
|
||
{
|
||
NewsConData * cd = (NewsConData *)ce->con_data;
|
||
nsresult rv;
|
||
#ifdef XPCOM_OFFLINE
|
||
if (cd->offline_state != NULL) {
|
||
int status;
|
||
rv = cd->offline_state->Interrupt(&status);
|
||
if (NS_SUCCEEDED(rv))
|
||
return status;
|
||
else
|
||
return -1; /* ??? */
|
||
}
|
||
#else
|
||
if (cd->offlineState != NULL)
|
||
return MSG_InterruptOfflineNews(cd->offlineState);
|
||
#endif
|
||
|
||
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
|
||
*/
|
||
MODULE_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, 0 /* status? */);
|
||
}
|
||
FREE(tmp_con);
|
||
}
|
||
}
|
||
|
||
if(XP_ListIsEmpty(nntp_connection_list))
|
||
{
|
||
XP_ListDestroy(nntp_connection_list);
|
||
nntp_connection_list = 0;
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
#ifdef PROFILE
|
||
#pragma profile off
|
||
#endif
|
||
|
||
#endif /* MOZILLA_CLIENT */
|