/* 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 COMM_MAILNEWS_PROTOCOLS_COMMON_SRC_OFFLINESTORAGE_H_ #define COMM_MAILNEWS_PROTOCOLS_COMMON_SRC_OFFLINESTORAGE_H_ #include "nsIChannel.h" #include "nsIMsgFolder.h" #include "nsIStreamListener.h" /** * A stream listener that forwards method calls to another stream listener, * while substituting the request argument with the provided channel. * * Consumers are expected to call `OnStartRequest` themselves, so that their own * consumers are informed of the entire operation (which might involve e.g. * downloading the message from a remote server). Any call to `OnStartRequest` * after the first one is silently ignored. * * `ReadMessageFromStore` can be called from a channel ran within an * `nsIDocShell` to render the message. The stream listener that `nsIDocShell` * calls `AsyncOpen` with expects the request used in method calls to be * channel-like (i.e. it can be QI'd as an `nsIChannel`). Additionally, we want * to use `nsIInputStreamPump` to pump the data from the message content's input * stream (which we get from the message store) into the provided stream * listener. However, the default `nsIInputStreamPump` implementation calls the * stream listener methods with itself as the request argument, but only * implements `nsIRequest` (and not `nsIChannel`), causing the operation to * fail. * * Therefore we need this "proxy" listener to forward the method calls to the * listener `AsyncOpen` is originally provided with, while substituting the * request arguments with an actual channel. * * Additionally, it's a good place to check for read errors when streaming a * message to the destination, and clearing malformed messages from the offline * storage (so they can be downloaded again). */ class OfflineMessageReadListener : public nsIStreamListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER OfflineMessageReadListener(nsIStreamListener* destination, nsIChannel* channel, nsMsgKey msgKey, nsIMsgFolder* folder) : mShouldStart(true), mDestination(destination), mChannel(channel), mMsgKey(msgKey), mFolder(folder) {}; // Disable the default and copy constructors. OfflineMessageReadListener() = delete; OfflineMessageReadListener(const OfflineMessageReadListener&) = delete; protected: virtual ~OfflineMessageReadListener(); private: // Whether `OnStartRequest` should be called. // // This boolean is set to `false` after the first `OnStartRequest` call to // avoid calling it more than once. bool mShouldStart; // The listener to which to forward any method call. nsCOMPtr mDestination; // The channel to use (instead of the original `nsIRequest`) when forwarding // method calls. nsCOMPtr mChannel; // The database key for the message we're currently reading, used to discard // the message in case of a read failure. nsMsgKey mMsgKey; // The folder in which the message we're currently reading resides, used to // discard the message in case of a read failure. nsCOMPtr mFolder; }; /** * A protocol-agnostic helper for reading a message from an offline store. * * This function is intended to be called from within a channel (and for this * channel to be passed as `srcChannel`). It looks up the content of the message * it's given, and streams its content to the given listener. * * If `convertData` is `true`, the message will be passed through our * `message/rfc822` converter, which output will be streamed to the listener * (instead of the raw RFC822 message). Depending on the query parameters in the * channel's URI, the converter will either output HTML for display, plain text * for showing the message's source, or, if the URI is for a specific part of * the message (specified via the `part=` parameter), serve the raw data for * that section. * * If an error arises from the process of reading the message, it is discarded * from the offline store (and the failure is propagated to any consumer) so it * can be downloaded again later. * * It returns an `nsIRequest` representing the read operation, that can be * cancelled or suspended as the consumer requests it. */ nsresult AsyncReadMessageFromStore(nsIMsgDBHdr* message, nsIStreamListener* streamListener, bool convertData, nsIChannel* srcChannel, nsIRequest** readRequest); /** * A protocol-agnostic helper for locally renaming or reparenting a folder. * * This function recursively moves the folder specified by `sourceFolder` held * in the local data store to the parent specified by `newParentFolder` with the * name specified by `name`. The folder specified by `newParentFolder` may be * the same as `sourceFolder`'s current parent, and the name specified by `name` * may be the same as `sourceFolder`'s current name. If both the parent and the * name are unchanged, then this function will do nothing and return `NS_OK`. If * the operation cannot be completed because a child with the specified name * already exists within the parent, then this function will return * `NS_MSG_FOLDER_EXISTS`. The specified `msgWindow` will be used for * notifications. * * This implementation also moves the database storage, maintaining properties * and metadata associated with the folder through the rename/reparent * operation. * * Returns an `nsresult` to indicate whether or not the operation succeeded. */ nsresult LocalRenameOrReparentFolder(nsIMsgFolder* sourceFolder, nsIMsgFolder* newParentFolder, const nsACString& name, nsIMsgWindow* msgWindow); /** * A protocol-agnostic helper for locally deleting messages within a folder. * * This function will delete the messages identified by their headers in the * `messageHeaders` parameter. The messages are assumed to be located in the * given `folder`. If the message includes content that has been downloaded * locally, that content will be deleted as well. * * @returns an `nsresult` to indicate whether or not the operation succeeded. */ nsresult LocalDeleteMessages( nsIMsgFolder* folder, const nsTArray>& messageHeaders); /** * A protocol-agnostic helper for locally copying messages between folders. * * This function copies the messages identified by `sourceHeaders` from the * given `sourceFolder` into the given `destinationFolder`. The newly created * headers are returned in `newHeaders`. The ordering of the returned headers * is guaranteed to be stable with respect to the ordering of the source * headers. In addition, if a message in the collection of messages to be * copied includes content that has been downloaded locally, that content will * be copied into the destination as well. * * @returns an `nsresult to indicate whether or not the operation succeeded. */ nsresult LocalCopyMessages(nsIMsgFolder* sourceFolder, nsIMsgFolder* destinationFolder, const nsTArray>& sourceHeaders, nsTArray>& newHeaders); /** * A protocol-agnostic helper for creating a header in the local database. * * This function creates a new message header in the given `destinationFolder`. * The resulting header is returned in `newHeader`. * * @returns an `nsresult to indicate whether or not the operation succeeded. */ nsresult LocalCreateHeader(nsIMsgFolder* destinationFolder, nsIMsgDBHdr** newHeader); /** * A protocol-agnostic helper for copying offline message content. * * This function copies the downloaded content for a message accessed by the * given `inputStream` to the given `destinationFolder`. Once complete, it sets * the required properties and flags on `messageHeader` to indicate the * existence and size of the downloaded content. * * @returns an `nsresult to indicate whether or not the operation succeeded. */ nsresult LocalCopyOfflineMessageContent(nsIMsgFolder* destinationFolder, nsIInputStream* msgInputStream, nsIMsgDBHdr* messageHeader); /** * A protocol-agnostic helper for making a complete copy of a message locally. * * This function takes the message content within the given `msgInputStream` * and copies it to the given `destinationFolder`. In addition, this function * creates a header for the newly copied message in the message database * for the given folder. * * @returns an `nsresult to indicate whether or not the operation succeeded. */ nsresult LocalCopyMessage(nsIMsgFolder* destinationFolder, nsIInputStream* msgInputStream, nsIMsgDBHdr** newHeader); /** * A protocol-agnostic helper for copying headers from one message to another. * * This function copies the header data stored in `sourceHeader` to * `destinationHeader`. The `excludeProperties` parameter is a list of property * names to exclude from the copy operation. The `isMove` parameter is used to * check preferences for which properties should be maintained on a move versus * a copy operation to determine additional properties to exclude. * * @returns an `nsresult to indicate whether or not the operation succeeded. */ nsresult LocalCopyHeaders(nsIMsgDBHdr* sourceHeader, nsIMsgDBHdr* destinationHeader, const nsTArray& excludeProperties, bool isMove); /** * Determine whether or not two folders are on the same server. * * This function queries the servers for `folder1` and `folder2` and returns a * value in `isSameServer` to indicate whether or not the underlying server for * those folders is the same server. * * @returns an `nsresult` to indicate whether or not the operation succeeded. */ nsresult FoldersOnSameServer(nsIMsgFolder* folder1, nsIMsgFolder* folder2, bool* isSameServer); #endif // COMM_MAILNEWS_PROTOCOLS_COMMON_SRC_OFFLINESTORAGE_H_