summaryrefslogtreecommitdiff
path: root/mailnews/news/src/nsNNTPProtocol.h
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/news/src/nsNNTPProtocol.h')
-rw-r--r--mailnews/news/src/nsNNTPProtocol.h510
1 files changed, 510 insertions, 0 deletions
diff --git a/mailnews/news/src/nsNNTPProtocol.h b/mailnews/news/src/nsNNTPProtocol.h
new file mode 100644
index 0000000000..08db18ee8c
--- /dev/null
+++ b/mailnews/news/src/nsNNTPProtocol.h
@@ -0,0 +1,510 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsNNTPProtocol_h___
+#define nsNNTPProtocol_h___
+
+#include "nsMsgProtocol.h"
+
+#include "nsCOMPtr.h"
+#include "nsIAsyncInputStream.h"
+#include "nsIAsyncOutputStream.h"
+#include "nsINntpUrl.h"
+#include "nsINntpIncomingServer.h"
+#include "nsINNTPProtocol.h"
+
+#include "nsINNTPNewsgroupList.h"
+#include "nsINNTPArticleList.h"
+#include "nsIMsgAsyncPrompter.h"
+#include "nsIMsgNewsFolder.h"
+#include "nsIMsgWindow.h"
+
+#include "nsMsgLineBuffer.h"
+#include "nsIStringBundle.h"
+#include "nsITimer.h"
+#include "nsICacheEntryOpenCallback.h"
+
+// this is only needed as long as our libmime hack is in place
+#include "prio.h"
+
+// State Flags (Note, I use the word state in terms of storing
+// state information about the connection (authentication, have we sent
+// commands, etc. I do not intend it to refer to protocol state)
+
+#define NNTP_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
+#define NNTP_PROXY_AUTH_REQUIRED 0x00000002 /* is auth required */
+#define NNTP_SENT_PROXY_AUTH 0x00000004 /* have we sent a proxy auth? */
+#define NNTP_READER_PERFORMED 0x00000010 /* have we sent any cmds to the server yet? */
+#define NNTP_USE_FANCY_NEWSGROUP 0x00000020 /* use LIST XACTIVE or LIST */
+#define NNTP_DESTROY_PROGRESS_GRAPH 0x00000040 /* do we need to destroy graph progress */
+#define NNTP_SOME_PROTOCOL_SUCCEEDED 0x0000080 /* some protocol has suceeded so don't kill the connection */
+#define NNTP_NO_XOVER_SUPPORT 0x00000100 /* xover command is not supported here */
+
+/* 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,
+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_XHDR_SEND,
+NNTP_XHDR_RESPONSE,
+NNTP_READ_GROUP,
+NNTP_READ_GROUP_RESPONSE,
+NNTP_READ_GROUP_BODY,
+NNTP_SEND_GROUP_FOR_ARTICLE,
+NNTP_SEND_GROUP_FOR_ARTICLE_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_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_POST_DONE,
+NEWS_ERROR,
+NNTP_ERROR,
+NEWS_FREE,
+NNTP_SUSPENDED
+} StatesEnum;
+
+class nsICacheEntry;
+
+class nsNNTPProtocol : public nsMsgProtocol,
+ public nsINNTPProtocol,
+ public nsITimerCallback,
+ public nsICacheEntryOpenCallback,
+ public nsIMsgAsyncPromptListener
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSINNTPPROTOCOL
+ NS_DECL_NSICACHEENTRYOPENCALLBACK
+ NS_DECL_NSITIMERCALLBACK
+ NS_DECL_NSIMSGASYNCPROMPTLISTENER
+
+ // Creating a protocol instance requires the URL
+ // need to call Initialize after we do a new of nsNNTPProtocol
+ nsNNTPProtocol(nsINntpIncomingServer *aServer, nsIURI *aURL,
+ nsIMsgWindow *aMsgWindow);
+
+ // stop binding is a "notification" informing us that the stream associated with aURL is going away.
+ NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports * aCtxt, nsresult aStatus) override;
+
+ char * m_ProxyServer; /* proxy server hostname */
+
+ NS_IMETHOD Cancel(nsresult status) override; // handle stop button
+ NS_IMETHOD GetContentType(nsACString &aContentType) override;
+ NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) override;
+ NS_IMETHOD AsyncOpen2(nsIStreamListener *listener) override;
+ NS_IMETHOD GetOriginalURI(nsIURI* *aURI) override;
+ NS_IMETHOD SetOriginalURI(nsIURI* aURI) override;
+
+ nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer) override;
+
+private:
+ virtual ~nsNNTPProtocol();
+ /**
+ * Triggers the protocol state machine.
+ * Most of the time, this machine will read as much input as it can before
+ * closing.
+ *
+ * This method additionally handles some states not covered by other methods:
+ * NEWS_DONE: Alias for NEWS_FREE
+ * NEWS_POST_DONE: Alias for NEWS_FREE that cleans up the URL state
+ * NEWS_ERROR: An error which permits further use of the connection
+ * NNTP_ERROR: An error which does not permit further use of the connection
+ * NEWS_FREE: Cleans up from the current URL and prepares for the next one
+ * NNTP_SUSPENDED: A state where the state machine does not read input until
+ * reenabled by a non-network related callback
+ *
+ * @note Use of NNTP_SUSPENDED is dangerous: if input comes along the socket,
+ * the code will not read the input stream at all. Therefore, it is strongly
+ * advised to suspend the request before using this state.
+ */
+ virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
+ uint64_t sourceOffset, uint32_t length) override;
+ virtual nsresult CloseSocket() override;
+
+ // we have our own implementation of SendData which writes to the nntp log
+ // and then calls the base class to transmit the data
+ nsresult SendData(const char * dataBuffer, bool aSuppressLogging = false) override;
+
+ nsresult CleanupAfterRunningUrl();
+ void Cleanup(); //free char* member variables
+
+ void ParseHeaderForCancel(char *buf);
+
+ virtual const char* GetType() override { return "nntp"; }
+
+ static void CheckIfAuthor(nsIMsgIdentity *aIdentity, const nsCString &aOldFrom, nsCString &aFrom);
+
+ nsCOMPtr <nsINNTPNewsgroupList> m_newsgroupList;
+ nsCOMPtr <nsINNTPArticleList> m_articleList;
+
+ nsCOMPtr <nsIMsgNewsFolder> m_newsFolder;
+ nsCOMPtr <nsIMsgWindow> m_msgWindow;
+
+ nsCOMPtr<nsIAsyncInputStream> mDisplayInputStream;
+ nsCOMPtr<nsIAsyncOutputStream> mDisplayOutputStream;
+ nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream
+ // the nsINntpURL that is currently running
+ nsCOMPtr<nsINntpUrl> m_runningURL;
+ bool m_connectionBusy;
+ bool m_fromCache; // is this connection from the cache?
+ PRTime m_lastActiveTimeStamp;
+ nsNewsAction m_newsAction;
+
+ // Generic state information -- What state are we in? What state do we want to go to
+ // after the next response? What was the last response code? etc.
+ StatesEnum m_nextState;
+ StatesEnum m_nextStateAfterResponse;
+ int32_t m_typeWanted; /* Article, List, or Group */
+ int32_t m_responseCode; /* code returned from NNTP server */
+ int32_t m_previousResponseCode;
+ char *m_responseText; /* text returned from NNTP server */
+
+ char *m_dataBuf;
+ uint32_t m_dataBufSize;
+
+ /* for group command */
+ nsCString m_currentGroup; /* current group */
+
+ int32_t m_firstArticle;
+ int32_t m_lastArticle;
+ int32_t m_firstPossibleArticle;
+ int32_t m_lastPossibleArticle;
+
+ int32_t m_numArticlesLoaded; /* How many articles we got XOVER lines for. */
+ int32_t m_numArticlesWanted; /* How many articles we wanted to get XOVER lines for. */
+ int32_t m_maxArticles; /* max articles to get during an XOVER */
+
+ // Cancelation specific state. In particular, the headers that should be
+ // used for the cancelation message.
+ // mscott: we can probably replace this stuff with nsString
+ char *m_cancelFromHdr;
+ char *m_cancelNewsgroups;
+ char *m_cancelDistribution;
+ char *m_cancelID;
+ int32_t m_cancelStatus;
+
+ // variable for ReadNewsList
+ int32_t m_readNewsListCount;
+
+ // Per news article state information. (article number, author, subject, id, etc
+ nsCString m_messageID;
+ int32_t m_articleNumber; /* current article number */
+ nsCString m_searchData;
+
+ int32_t m_originalContentLength; /* the content length at the time of calling graph progress */
+
+ nsCOMPtr<nsIStringBundle> m_stringBundle;
+
+ nsCOMPtr<nsINntpIncomingServer> m_nntpServer;
+
+ nsresult GetNewsStringByName(const char *aName, char16_t **aString);
+ nsresult GetNewsStringByID(int32_t stringID, char16_t **aString);
+
+ nsresult PostMessageInFile(nsIFile * filePath);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Communication methods --> Reading and writing protocol
+ //////////////////////////////////////////////////////////////////////////////
+
+ int32_t ReadLine(nsIInputStream * inputStream, uint32_t length, char ** line);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Protocol Methods --> This protocol is state driven so each protocol method
+ // is designed to re-act to the current "state". I've attempted to
+ // group them together based on functionality.
+ //////////////////////////////////////////////////////////////////////////////
+
+ // gets the response code from the nntp server and the response line. Returns the TCP return code
+ // from the read.
+ nsresult NewsResponse(nsIInputStream *inputStream, uint32_t length);
+
+ // Interpret the server response after the connect.
+ // Returns negative if the server responds unexpectedly
+ nsresult LoginResponse();
+ nsresult SendModeReader();
+ nsresult SendModeReaderResponse();
+
+ nsresult SendListExtensions();
+ nsresult SendListExtensionsResponse(nsIInputStream *inputStream, uint32_t length);
+
+ nsresult SendListSearches();
+ nsresult SendListSearchesResponse(nsIInputStream *inputStream, uint32_t length);
+
+ nsresult SendListSearchHeaders();
+ nsresult SendListSearchHeadersResponse(nsIInputStream *inputStream, uint32_t length);
+
+ nsresult GetProperties();
+ nsresult GetPropertiesResponse(nsIInputStream *inputStream, uint32_t length);
+
+ nsresult SendListSubscriptions();
+ nsresult SendListSubscriptionsResponse(nsIInputStream *inputStream, uint32_t length);
+
+ // Figure out what the first command is and send it.
+ // Returns the status from the NETWrite.
+ nsresult SendFirstNNTPCommand(nsIURI *url);
+
+ // Interprets the server response from the first command sent.
+ // returns negative if the server responds unexpectedly.
+ nsresult SendFirstNNTPCommandResponse();
+
+ nsresult SetupForTransfer();
+
+ nsresult SendGroupForArticle();
+ nsresult SendGroupForArticleResponse();
+
+ nsresult SendArticleNumber();
+ nsresult BeginArticle();
+ nsresult ReadArticle(nsIInputStream *inputStream, uint32_t length);
+ nsresult DisplayArticle(nsIInputStream *inputStream, uint32_t length);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // News authentication code
+ //////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Sends the username via AUTHINFO USER, NNTP_BEGIN_AUTHORIZE.
+ * This also handles the step of getting authentication credentials; if this
+ * requires a prompt to run, the connection will be suspended and we will
+ * come back to this point.
+ * Followed by: NNTP_AUTHORIZE_RESPONSE if the username was sent
+ * NNTP_SUSPENDED if we need to wait for the password
+ */
+ nsresult BeginAuthorization();
+ /**
+ * Sends the password if necessary, the state NNTP_AUTHORIZE_RESPONSE.
+ * This also reads the result of the username.
+ * Followed by: NNTP_PASSWORD_RESPONSE if a password is sent
+ * NNTP_SEND_MODE_READER if MODE READER needed auth
+ * SEND_FIRST_NNTP_COMMAND if any other command needed auth
+ * NNTP_ERROR if the username was rejected
+ */
+ nsresult AuthorizationResponse();
+ /**
+ * This state, NNTP_PASSWORD_RESPONSE, reads the password.
+ * Followed by: NNTP_SEND_MODE_READER if MODE READER needed auth
+ * SEND_FIRST_NNTP_COMMAND if any other command needed auth
+ * NNTP_ERROR if the password was rejected
+ */
+ nsresult PasswordResponse();
+
+ nsresult BeginReadNewsList();
+ nsresult ReadNewsList(nsIInputStream *inputStream, uint32_t length);
+
+ // Newsgroup specific protocol handlers
+ nsresult DisplayNewsgroups();
+ nsresult BeginNewsgroups();
+ nsresult ProcessNewsgroups(nsIInputStream *inputStream, uint32_t length);
+
+ // Protocol handlers used for posting data
+ nsresult PostData();
+ nsresult PostDataResponse();
+
+ nsresult CheckForArticle();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // XHDR, XOVER, HEAD filtering process handlers
+ // These are ordered by the rough order of usage
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * The first step in the filtering process, the state NNTP_XOVER_BEGIN.
+ * This method sets up m_newsgroupList.
+ * Followed by: NNTP_FIGURE_NEXT_CHUNK
+ */
+ nsresult BeginReadXover();
+ /**
+ * The loop control for filtering, the state NNTP_FIGURE_NEXT_CHUNK.
+ * This method contacts the newsgroupList to figure out which articles to
+ * download and then prepares it for XOVER support.
+ * Followed by: NEWS_PROCESS_XOVER if everything is finished
+ * NNTP_READ_GROUP if XOVER doesn't work
+ * NNTP_XOVER_SEND if XOVER does work
+ */
+ nsresult FigureNextChunk();
+
+ // The XOVER process core
+ /**
+ * The state NNTP_XOVER_SEND, which actually sends the message.
+ * Followed by: NNTP_XOVER_RESPONSE
+ */
+ nsresult XoverSend();
+ /**
+ * This state, NNTP_XOVER_RESPONSE, actually checks the XOVER capabiliity.
+ * Followed by: NNTP_XOVER if XOVER is supported
+ * NNTP_READ_GROUP if it isn't
+ */
+ nsresult ReadXoverResponse();
+ /**
+ * This state, NNTP_XOVER, processes the results from the XOVER command.
+ * It asks nsNNTPNewsgroupList to process the line using ProcessXOVERLINE.
+ * Followed by: NNTP_XHDR_SEND
+ */
+ nsresult ReadXover(nsIInputStream *inputStream, uint32_t length);
+
+ // The XHDR process core
+ /**
+ * This state, NNTP_XHDR_SEND, sends the XHDR command.
+ * The headers are all managed by nsNNTPNewsgroupList, and this picks them up
+ * one by one as they are needed.
+ * Followed by: NNTP_XHDR_RESPONSE if there is a header to be sent
+ * NNTP_FIGURE_NEXT_CHUNK if all headers have been sent
+ */
+ nsresult XhdrSend();
+ /**
+ * This state, NNTP_XHDR_RESPONSE, processes the XHDR response.
+ * It mostly passes the information off to nsNNTPNewsgroupList, and only does
+ * response code checking and a bit of preprocessing. Note that if XHDR
+ * doesn't work properly, HEAD fallback is switched on and all subsequent
+ * chunks will NOT use XOVER.
+ * Followed by: NNTP_READ_GROUP if XHDR doesn't work properly
+ * NNTP_XHDR_SEND when finished processing XHR.
+ */
+ nsresult XhdrResponse(nsIInputStream *inputStream);
+
+ // HEAD processing core
+ /**
+ * This state, NNTP_READ_GROUP, is the control for the HEAD processor.
+ * It sends the HEAD command and increments the article number until it is
+ * finished. WARNING: HEAD is REALLY SLOW.
+ * Followed by: NNTP_FIGURE_NEXT_CHUNK when it is finished
+ * NNTP_READ_GROUP_RESPONSE when it is not
+ */
+ nsresult ReadHeaders();
+ /**
+ * This state, NNTP_READ_GROUP_RESPONSE, checks if the article exists.
+ * Because it is required by NNTP, if it doesn't work, the only problem would
+ * be that the article doesn't exist. Passes off article number data to
+ * nsNNTPNewsgroupList.
+ * Followed by: NNTP_READ_GROUP_BODY if the article exists
+ * NNTP_READ_GROUP if it doesn't.
+ */
+ nsresult ReadNewsgroupResponse();
+ /**
+ * This state, NNTP_READ_GROUP_BODY, reads the body of the HEAD command.
+ * Once again, it passes information off to nsNNTPNewsgroupList.
+ * Followed by: NNTP_READ_GROUP
+ */
+ nsresult ReadNewsgroupBody(nsIInputStream *inputStream, uint32_t length);
+
+ /**
+ * This state, NNTP_PROCESS_XOVER, is the final step of the filter-processing
+ * code. Currently, all it does is cleans up the unread count and calls the
+ * filters, both via nsNNTPNewsgroupList.
+ * Followed by: NEWS_DONE
+ */
+ nsresult ProcessXover();
+
+
+
+ // Canceling
+ nsresult StartCancel();
+ nsresult DoCancel();
+
+ // XPAT
+ nsresult XPATSend();
+ nsresult XPATResponse(nsIInputStream *inputStream, uint32_t length);
+ nsresult ListPrettyNames();
+ nsresult ListPrettyNamesResponse(nsIInputStream *inputStream, uint32_t length);
+
+ nsresult ListXActive();
+ nsresult ListXActiveResponse(nsIInputStream *inputStream, uint32_t length);
+
+ // for "?list-ids"
+ nsresult SendListGroup();
+ nsresult SendListGroupResponse(nsIInputStream *inputStream, uint32_t length);
+
+ // Searching Protocol....
+ nsresult Search();
+ nsresult SearchResponse();
+ nsresult SearchResults(nsIInputStream *inputStream, uint32_t length);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // End of Protocol Methods
+ //////////////////////////////////////////////////////////////////////////////
+
+ nsresult ParseURL(nsIURI *aURL, nsCString &aGroup, nsCString &aMessageID);
+
+ void SetProgressBarPercent(uint32_t aProgress, uint32_t aProgressMax);
+ nsresult SetProgressStatus(const char16_t *aMessage);
+ nsresult InitializeNewsFolderFromUri(const char *uri);
+ void TimerCallback();
+
+ void HandleAuthenticationFailure();
+ nsCOMPtr <nsIInputStream> mInputStream;
+ nsCOMPtr <nsITimer> mUpdateTimer;
+ nsresult AlertError(int32_t errorCode, const char *text);
+ int32_t mBytesReceived;
+ int32_t mBytesReceivedSinceLastStatusUpdate;
+ PRTime m_startTime;
+ int32_t mNumGroupsListed;
+ nsMsgKey m_key;
+
+ nsresult SetCurrentGroup(); /* sets m_currentGroup. should be called after doing a successful GROUP command */
+ nsresult CleanupNewsgroupList(); /* cleans up m_newsgroupList, and set it to null */
+
+ // cache related helper methods
+ void FinishMemCacheEntry(bool valid); // either mark it valid, or doom it
+ nsresult OpenCacheEntry(); // makes a request to the cache service for a cache entry for a url
+ bool ReadFromLocalCache(); // attempts to read the url out of our local (offline) cache....
+ nsresult ReadFromNewsConnection(); // creates a new news connection to read the url
+ nsresult ReadFromMemCache(nsICacheEntry *entry); // attempts to read the url out of our memory cache
+ nsresult SetupPartExtractorListener(nsIStreamListener * aConsumer);
+};
+
+
+#endif // nsNNTPProtocol_h___