1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsMsgProtocol_h__
7 #define nsMsgProtocol_h__
8 
9 #include "mozilla/Attributes.h"
10 #include "nsIStreamListener.h"
11 #include "nsIInputStream.h"
12 #include "nsIOutputStream.h"
13 #include "nsIChannel.h"
14 #include "nsIURL.h"
15 #include "nsIThread.h"
16 #include "nsILoadGroup.h"
17 #include "nsIFile.h"
18 #include "nsCOMPtr.h"
19 #include "nsIInterfaceRequestor.h"
20 #include "nsIInterfaceRequestorUtils.h"
21 #include "nsIProgressEventSink.h"
22 #include "nsITransport.h"
23 #include "nsIAsyncOutputStream.h"
24 #include "nsIAuthModule.h"
25 #include "nsString.h"
26 #include "nsWeakReference.h"
27 #include "nsHashPropertyBag.h"
28 
29 class nsIMsgWindow;
30 class nsIPrompt;
31 class nsIMsgMailNewsUrl;
32 class nsMsgFilePostHelper;
33 class nsIProxyInfo;
34 class nsICancelable;
35 
36 // This is a helper class used to encapsulate code shared between all of the
37 // mailnews protocol objects (imap, news, pop, smtp, etc.) In particular,
38 // it unifies the core networking code for the protocols. My hope is that
39 // this will make unification with Necko easier as we'll only have to change
40 // this class and not all of the mailnews protocols.
41 class nsMsgProtocol : public nsIStreamListener,
42                       public nsIChannel,
43                       public nsITransportEventSink,
44                       public nsHashPropertyBag {
45  public:
46   nsMsgProtocol(nsIURI* aURL);
47 
48   NS_DECL_ISUPPORTS_INHERITED
49   // nsIChannel support
50   NS_DECL_NSICHANNEL
51   NS_DECL_NSIREQUEST
52 
53   NS_DECL_NSISTREAMLISTENER
54   NS_DECL_NSIREQUESTOBSERVER
55   NS_DECL_NSITRANSPORTEVENTSINK
56 
57   // LoadUrl -- A protocol typically overrides this function, sets up any local
58   // state for the url and then calls the base class which opens the socket if
59   // it needs opened. If the socket is already opened then we just call
60   // ProcessProtocolState to start the churning process. aConsumer is the
61   // consumer for the url. It can be null if this argument is not appropriate
62   virtual nsresult LoadUrl(nsIURI* aURL, nsISupports* aConsumer = nullptr);
63 
64   virtual nsresult SetUrl(
65       nsIURI* aURL);  // sometimes we want to set the url before we load it
66   void ShowAlertMessage(nsIMsgMailNewsUrl* aMsgUrl, nsresult aStatus);
67 
68   // Flag manipulators
TestFlag(uint32_t flag)69   virtual bool TestFlag(uint32_t flag) { return flag & m_flags; }
SetFlag(uint32_t flag)70   virtual void SetFlag(uint32_t flag) { m_flags |= flag; }
ClearFlag(uint32_t flag)71   virtual void ClearFlag(uint32_t flag) { m_flags &= ~flag; }
72 
73  protected:
74   virtual ~nsMsgProtocol();
75 
76   // methods for opening and closing a socket with core netlib....
77   // mscott -okay this is lame. I should break this up into a file protocol and
78   // a socket based protocool class instead of cheating and putting both methods
79   // here...
80 
81   // open a connection with a specific host and port
82   // aHostName must be UTF-8 encoded.
83   virtual nsresult OpenNetworkSocketWithInfo(const char* aHostName,
84                                              int32_t aGetPort,
85                                              const char* connectionType,
86                                              nsIProxyInfo* aProxyInfo,
87                                              nsIInterfaceRequestor* callbacks);
88   // helper routine
89   nsresult GetFileFromURL(nsIURI* aURL, nsIFile** aResult);
90   virtual nsresult OpenFileSocket(
91       nsIURI* aURL, uint64_t aStartPosition,
92       int64_t aReadCount);  // used to open a file socket connection
93 
94   nsresult GetTopmostMsgWindow(nsIMsgWindow** aWindow);
95 
GetType()96   virtual const char* GetType() { return nullptr; }
97   nsresult GetQoSBits(uint8_t* aQoSBits);
98 
99   // a Protocol typically overrides this method. They free any of their own
100   // connection state and then they call up into the base class to free the
101   // generic connection objects
102   virtual nsresult CloseSocket();
103 
104   virtual nsresult
105   SetupTransportState();  // private method used by OpenNetworkSocket and
106                           // OpenFileSocket
107 
108   // ProcessProtocolState - This is the function that gets churned by calls to
109   // OnDataAvailable. As data arrives on the socket, OnDataAvailable calls
110   // ProcessProtocolState.
111 
112   virtual nsresult ProcessProtocolState(nsIURI* url,
113                                         nsIInputStream* inputStream,
114                                         uint64_t sourceOffset,
115                                         uint32_t length) = 0;
116 
117   // SendData -- Writes the data contained in dataBuffer into the current output
118   // stream. It also informs the transport layer that this data is now available
119   // for transmission. Returns a positive number for success, 0 for failure (not
120   // all the bytes were written to the stream, etc). aSuppressLogging is a hint
121   // that sensitive data is being sent and should not be logged
122   virtual nsresult SendData(const char* dataBuffer,
123                             bool aSuppressLogging = false);
124 
125   virtual nsresult PostMessage(nsIURI* url, nsIFile* aPostFile);
126 
127   virtual nsresult InitFromURI(nsIURI* aUrl);
128 
129   nsresult DoNtlmStep1(const nsACString& username, const nsAString& password,
130                        nsCString& response);
131   nsresult DoNtlmStep2(nsCString& commandResponse, nsCString& response);
132 
133   nsresult DoGSSAPIStep1(const char* service, const char* username,
134                          nsCString& response);
135   nsresult DoGSSAPIStep2(nsCString& commandResponse, nsCString& response);
136   // Output stream for writing commands to the socket
137   nsCOMPtr<nsIOutputStream>
138       m_outputStream;  // this will be obtained from the transport interface
139 
140   // Output stream for writing commands to the socket
141   nsCOMPtr<nsITransport> m_transport;
142   nsCOMPtr<nsIRequest> m_request;
143   nsCOMPtr<nsICancelable> m_proxyRequest;
144 
145   bool m_socketIsOpen;  // mscott: we should look into keeping this state in the
146                         // nsSocketTransport... I'm using it to make sure I open
147                         // the socket the first time a URL is loaded into the
148                         // connection
149   uint32_t m_flags;     // used to store flag information
150   // uint32_t  m_startPosition;
151   int64_t m_readCount;
152 
153   nsCOMPtr<nsIFile>
154       m_tempMsgFile;  // we currently have a hack where displaying a msg
155                       // involves writing it to a temp file first
156 
157   // auth module for access to NTLM functions
158   nsCOMPtr<nsIAuthModule> m_authModule;
159 
160   // the following is a catch all for nsIChannel related data
161   nsCOMPtr<nsIURI> m_originalUrl;  // the original url
162   nsCOMPtr<nsIURI> m_url;          // the running url
163   nsCOMPtr<nsISupports> m_consumer;
164   nsCOMPtr<nsIStreamListener> m_channelListener;
165   bool m_isChannel;
166   nsCOMPtr<nsILoadGroup> m_loadGroup;
167   nsLoadFlags mLoadFlags;
168   nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
169   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
170   nsCOMPtr<nsISupports> mOwner;
171   nsCString mContentType;
172   nsCString mCharset;
173   int64_t mContentLength;
174   nsCOMPtr<nsILoadInfo> m_loadInfo;
175 
176   nsString m_lastPasswordSent;  // used to prefill the password prompt
177 
178   // private helper routine used by subclasses to quickly get a reference to the
179   // correct prompt dialog for a mailnews url.
180   nsresult GetPromptDialogFromUrl(nsIMsgMailNewsUrl* aMsgUrl,
181                                   nsIPrompt** aPromptDialog);
182 
183   // if a url isn't going to result in any content then we want to suppress
184   // calls to OnStartRequest, OnDataAvailable and OnStopRequest
185   bool mSuppressListenerNotifications;
186 
187   uint32_t mContentDisposition;
188 };
189 
190 // This is is a subclass of nsMsgProtocol extends the parent class with
191 // AsyncWrite support. Protocols like smtp and news want to leverage async
192 // write. We don't want everyone who inherits from nsMsgProtocol to have to pick
193 // up the extra overhead.
194 class nsMsgAsyncWriteProtocol : public nsMsgProtocol,
195                                 public nsSupportsWeakReference {
196  public:
197   NS_DECL_ISUPPORTS_INHERITED
198 
199   NS_IMETHOD Cancel(nsresult status) override;
200 
201   nsMsgAsyncWriteProtocol(nsIURI* aURL);
202 
203   // temporary over ride...
204   virtual nsresult PostMessage(nsIURI* url, nsIFile* postFile) override;
205 
206   // over ride the following methods from the base class
207   virtual nsresult SetupTransportState() override;
208   virtual nsresult SendData(const char* dataBuffer,
209                             bool aSuppressLogging = false) override;
210   nsCString mAsyncBuffer;
211 
212   // if we suspended the asynch write while waiting for more data to write then
213   // this will be TRUE
214   bool mSuspendedWrite;
215   nsCOMPtr<nsIRequest> m_WriteRequest;
216   nsCOMPtr<nsIAsyncOutputStream> mAsyncOutStream;
217   nsCOMPtr<nsIOutputStreamCallback> mProvider;
218   nsCOMPtr<nsIThread> mProviderThread;
219 
220   // because we are reading the post data in asynchronously, it's possible that
221   // we aren't sending it out fast enough and the reading gets blocked. The
222   // following set of state variables are used to track this.
223   bool mSuspendedRead;
224   bool mInsertPeriodRequired;  // do we need to insert a '.' as part of the
225                                // unblocking process
226 
227   nsresult ProcessIncomingPostData(nsIInputStream* inStr, uint32_t count);
228   nsresult UnblockPostReader();
229   nsresult UpdateSuspendedReadBytes(uint32_t aNewBytes,
230                                     bool aAddToPostPeriodByteCount);
231   nsresult PostDataFinished();  // this is so we'll send out a closing '.' and
232                                 // release any state related to the post
233 
234   // these two routines are used to pause and resume our loading of the file
235   // containing the contents we are trying to post. We call these routines when
236   // we aren't sending the bits out fast enough to keep up with the file read.
237   nsresult SuspendPostFileRead();
238   nsresult ResumePostFileRead();
239   nsresult UpdateSuspendedReadBytes(uint32_t aNewBytes);
240   void UpdateProgress(uint32_t aNewBytes);
241   nsMsgFilePostHelper* mFilePostHelper;  // needs to be a weak reference
242  protected:
243   virtual ~nsMsgAsyncWriteProtocol();
244 
245   // the streams for the pipe used to queue up data for the async write calls to
246   // the server. we actually re-use the same mOutStream variable in our parent
247   // class for the output stream to the socket channel. So no need for a new
248   // variable here.
249   nsCOMPtr<nsIInputStream> mInStream;
250   nsCOMPtr<nsIInputStream> mPostDataStream;
251   uint32_t mSuspendedReadBytes;  // remaining # of bytes we need to read before
252                                  // the input stream becomes unblocked
253   uint32_t mSuspendedReadBytesPostPeriod;  // # of bytes which need processed
254                                            // after we insert a '.' before the
255                                            // input stream becomes unblocked.
256   int64_t
257       mFilePostSize;  // used for file size, we post a single message in a file
258   uint32_t mNumBytesPosted;  // used for determining progress on posting files
259   bool
260       mGenerateProgressNotifications;  // set during a post operation after
261                                        // we've started sending the post data...
262 
263   virtual nsresult CloseSocket() override;
264 };
265 
266 #endif /* nsMsgProtocol_h__ */
267