add method for getting preview text, part of 314124, sr=mscott

This commit is contained in:
bienvenu%nventure.com 2005-11-08 02:01:08 +00:00
Родитель 8ab8375bf0
Коммит f9275712b2
8 изменённых файлов: 315 добавлений и 7 удалений

Просмотреть файл

@ -48,7 +48,6 @@
#include "nsISimpleEnumerator.idl"
%{ C++
#include "nsIMsgDatabase.h"
#include "nsMsgKeyArray.h"
%}
[ptr] native octet_ptr(PRUint8);
@ -58,7 +57,6 @@ interface nsIMsgDBHdr;
interface nsIMsgWindow;
interface nsIMsgDatabase;
interface nsIDBFolderInfo;
interface nsMsgKeyArray;
interface nsIMsgFilterList;
interface nsIMsgFolderCacheElement;
@ -72,7 +70,7 @@ typedef long nsMsgBiffState;
// enumerated type for determining if a message has been replied to, forwarded, etc.
typedef long nsMsgDispositionState;
[scriptable, uuid(853d026c-6eda-4d92-a915-8c05953284a2)]
[scriptable, uuid(28424d1c-db6f-4ac5-bc5d-418dd336120b)]
interface nsIMsgFolder : nsICollection {
const nsMsgBiffState nsMsgBiffState_NewMail = 0; // User has new mail waiting.
@ -479,4 +477,24 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne
void copyDataDone();
void setJunkScoreForMessages(in nsISupportsArray aMessages, in string aJunkScore);
void applyRetentionSettings();
/**
* Get the beginning of the message bodies for the passed in keys and store
* them in the msg hdr property "preview". This is intended for
* new mail alerts, title tips on folders with new messages, and perhaps
* titletips/message preview in the thread pane.
*
* @param aKeysToFetch keys of msgs to fetch
* @param aNumKeys number of keys to fetch
* @param aLocalOnly whether to fetch msgs from server (imap msgs might
* be in memory cache from junk filter)
* @param aUrlListener url listener to notify if we run url to fetch msgs
*
* @result aAsyncResults if true, we ran a url to fetch one or more of msg bodies
*
*/
void fetchMsgPreviewText([array, size_is (aNumKeys)] in nsMsgKey aKeysToFetch,
in unsigned long aNumKeys, in boolean aLocalOnly,
in nsIUrlListener aUrlListener, out boolean aAsyncResults);
};

Просмотреть файл

@ -86,6 +86,10 @@ REQUIRES = xpcom \
nkcache \
mimetype \
windowwatcher \
embed_base \
htmlparser \
content \
layout \
$(NULL)
CPPSRCS = \

Просмотреть файл

@ -77,7 +77,14 @@
#include "nsCPasswordManager.h"
#include "nsMsgDBCID.h"
#include "nsInt64.h"
#include "nsReadLine.h"
#include "nsParserCIID.h"
#include "nsIParser.h"
#include "nsIHTMLContentSink.h"
#include "nsIContentSerializer.h"
#include "nsLayoutCID.h"
#include "nsIHTMLToTextSink.h"
#include "nsIDocumentEncoder.h"
#include <time.h>
#define oneHour 3600000000U
@ -85,7 +92,6 @@
static PRTime gtimeOfLastPurgeCheck; //variable to know when to check for purge_threshhold
#define PREF_MAIL_PROMPT_PURGE_THRESHOLD "mail.prompt_purge_threshhold"
#define PREF_MAIL_PURGE_THRESHOLD "mail.purge_threshhold"
#define PREF_MAIL_WARN_FILTER_CHANGED "mail.warn_filter_changed"
@ -93,6 +99,8 @@ static PRTime gtimeOfLastPurgeCheck; //variable to know when to check for pur
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
static NS_DEFINE_CID(kCMailDB, NS_MAILDB_CID);
static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
static NS_DEFINE_CID(kNavDTDCID, NS_CNAVDTD_CID);
nsIAtom* nsMsgDBFolder::mFolderLoadedAtom=nsnull;
nsIAtom* nsMsgDBFolder::mDeleteOrMoveMsgCompletedAtom=nsnull;
@ -5068,3 +5076,143 @@ NS_IMETHODIMP nsMsgDBFolder::SetInVFEditSearchScope (PRBool aInVFEditSearchScope
NotifyBoolPropertyChanged(kInVFEditSearchScopeAtom, oldInVFEditSearchScope, mInVFEditSearchScope);
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
PRBool *aAsyncResults)
{
NS_ENSURE_ARG_POINTER(aKeysToFetch);
NS_ENSURE_ARG_POINTER(aAsyncResults);
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsMsgDBFolder::GetMsgPreviewTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream)
{
/*
1. non mime message - the message body starts after the blank line following the headers.
2. mime message, multipart/alternative - we could simply scan for the boundary line,
advance past its headers, and treat the next few lines as the text.
3. mime message, text/plain - body follows headers
4. multipart/mixed - scan past boundary, treat next part as body.
TODO need to worry about quoted printable and other encodings,
so look for content transfer encoding.
*/
PRUint32 len;
msgHdr->GetMessageSize(&len);
nsLineBuffer<char> *lineBuffer;
nsresult rv = NS_InitLineBuffer(&lineBuffer);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString boundary, msgBody;
nsCAutoString curLine;
// might want to use a state var instead of bools.
PRBool inMsgBody = PR_FALSE, msgBodyIsHtml = PR_FALSE, lookingForBoundary = PR_FALSE;
PRBool haveBoundary = PR_FALSE;
while (len > 0)
{
// might be on same line as content-type, so look before
// we read the next line.
if (lookingForBoundary)
{
PRInt32 boundaryIndex = curLine.Find("boundary=\"");
if (boundaryIndex != kNotFound)
{
boundaryIndex += 10;
PRInt32 endBoundaryIndex = curLine.RFindChar('"');
if (endBoundaryIndex != kNotFound)
{
// prepend "--" to boundary, and then boundary delimiter, minus the trailing "
boundary.Assign("--");
boundary.Append(Substring(curLine, boundaryIndex, endBoundaryIndex - boundaryIndex));
haveBoundary = PR_TRUE;
lookingForBoundary = PR_FALSE;
}
}
}
PRBool more;
rv = NS_ReadLine(stream, lineBuffer, curLine, &more);
if (NS_SUCCEEDED(rv))
{
len -= MSG_LINEBREAK_LEN;
len -= curLine.Length();
if (inMsgBody)
{
if (!boundary.IsEmpty() && boundary.Equals(curLine))
break;
msgBody.Append(curLine);
// how much html should we parse for text? 2K? 4K?
if (msgBody.Length() > 2048 || (!msgBodyIsHtml && msgBody.Length() > 255))
break;
continue;
}
if (haveBoundary)
{
// this line is the boundary; continue and fall into code that looks
// for msg body after headers
if (curLine.Equals(boundary))
haveBoundary = PR_FALSE;
continue;
}
if (curLine.IsEmpty())
{
inMsgBody = PR_TRUE;
continue;
}
if (StringBeginsWith(curLine, NS_LITERAL_CSTRING("Content-Type:")))
{
if (FindInReadable(NS_LITERAL_CSTRING("text/html"), curLine))
{
msgBodyIsHtml = PR_TRUE;
// bodyFollowsHeaders = PR_TRUE;
}
else if (FindInReadable(NS_LITERAL_CSTRING("text/plain"), curLine))
/* bodyFollowsHeaders = PR_TRUE */;
else if (FindInReadable(NS_LITERAL_CSTRING("multipart/mixed"), curLine)
|| FindInReadable(NS_LITERAL_CSTRING("multipart/alternative"), curLine))
{
lookingForBoundary = PR_TRUE;
}
}
}
}
// now we've got a msg body. If it's html, convert it to plain text.
// Then, set the previewProperty on the msg hdr to the plain text.
if (msgBodyIsHtml)
{
nsAutoString bodyText;
nsresult rv = NS_OK;
// Create a parser
nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Create the appropriate output sink
nsCOMPtr<nsIContentSink> sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID,&rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink));
NS_ENSURE_TRUE(textSink, NS_ERROR_FAILURE);
PRUint32 flags = nsIDocumentEncoder::OutputLFLineBreak
| nsIDocumentEncoder::OutputNoScriptContent
| nsIDocumentEncoder::OutputNoFramesContent
| nsIDocumentEncoder::OutputBodyOnly;
textSink->Initialize(&bodyText, flags, 80);
parser->SetContentSink(sink);
nsCOMPtr<nsIDTD> dtd = do_CreateInstance(kNavDTDCID,&rv);
NS_ENSURE_SUCCESS(rv, rv);
parser->RegisterDTD(dtd);
nsAutoString msgBodyStr;
// need to do an appropriate conversion here.
msgBodyStr.AssignWithConversion(msgBody);
rv = parser->Parse(msgBodyStr, 0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE);
CopyUTF16toUTF8(bodyText, msgBody);
}
msgHdr->SetStringProperty("preview", msgBody.get());
return rv;
}

Просмотреть файл

@ -104,6 +104,7 @@ public:
NS_IMETHOD MatchName(nsString *name, PRBool *matches);
nsresult CreateDirectoryForFolder(nsFileSpec &path);
nsresult GetMsgPreviewTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream);
protected:
// this is a little helper function that is not part of the public interface.

Просмотреть файл

@ -113,6 +113,7 @@
#include "nsEmbedCID.h"
#include "nsIMsgComposeService.h"
#include "nsMsgCompCID.h"
#include "nsICacheEntryDescriptor.h"
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kCMailDB, NS_MAILDB_CID);
@ -602,7 +603,7 @@ nsresult nsImapMailFolder::CreateSubFolders(nsFileSpec &path)
// automatically computed from the URI, which is in utf7 form.
if (!currentFolderNameStr.IsEmpty())
child->SetPrettyName(currentFolderNameStr.get());
child->SetMsgDatabase(nsnull);
}
}
return rv;
@ -996,6 +997,8 @@ NS_IMETHODIMP nsImapMailFolder::CreateClientSubfolderInfo(const char *folderName
unusedDB->SetSummaryValid(PR_TRUE);
unusedDB->Commit(nsMsgDBCommitType::kLargeCommit);
unusedDB->Close(PR_TRUE);
// don't want to hold onto this newly created db.
child->SetMsgDatabase(nsnull);
}
}
if (!suppressNotification)
@ -2624,6 +2627,7 @@ NS_IMETHODIMP nsImapMailFolder::UpdateImapMailboxInfo(
if ((imapUIDValidity != folderValidity) /* && // if UIDVALIDITY Changed
!NET_IsOffline() */)
{
NS_ASSERTION(PR_FALSE, "uid validity seems to have changed, blowing away db");
nsCOMPtr<nsIFileSpec> pathSpec;
rv = GetPath(getter_AddRefs(pathSpec));
if (NS_FAILED(rv)) return rv;
@ -8306,3 +8310,84 @@ void nsImapMailFolder::GetTrashFolderName(nsAString &aFolderName)
}
}
}
NS_IMETHODIMP nsImapMailFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
PRBool *aAsyncResults)
{
NS_ENSURE_ARG_POINTER(aKeysToFetch);
NS_ENSURE_ARG_POINTER(aAsyncResults);
*aAsyncResults = PR_FALSE;
nsresult rv = NS_OK;
for (PRUint32 i = 0; i < aNumKeys; i++)
{
nsCOMPtr <nsIMsgDBHdr> msgHdr;
nsXPIDLCString prevBody;
rv = GetMessageHeader(aKeysToFetch[i], getter_AddRefs(msgHdr));
NS_ENSURE_SUCCESS(rv, rv);
// ignore messages that already have a preview body.
msgHdr->GetStringProperty("preview", getter_Copies(prevBody));
if (!prevBody.IsEmpty())
continue;
/* check if message is in memory cache or offline store. */
nsCOMPtr<nsIImapService> imapService = do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIMsgMessageService> msgService = do_QueryInterface(imapService);
nsCOMPtr <nsIURI> url;
nsCOMPtr<nsIInputStream> inputStream;
nsXPIDLCString messageUri;
rv = GetUriForMsg(msgHdr, getter_Copies(messageUri));
NS_ENSURE_SUCCESS(rv,rv);
rv = msgService->GetUrlForUri(messageUri, getter_AddRefs(url), nsnull);
NS_ENSURE_SUCCESS(rv,rv);
nsCAutoString urlSpec;
url->GetAsciiSpec(urlSpec);
nsCOMPtr<nsICacheSession> cacheSession;
rv = imapService->GetCacheSession(getter_AddRefs(cacheSession));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 uidValidity;
GetUidValidity(&uidValidity);
// stick the uid validity in front of the url, so that if the uid validity
// changes, we won't re-use the wrong cache entries.
nsCAutoString cacheKey;
cacheKey.AppendInt(uidValidity, 16);
cacheKey.Append(urlSpec);
nsCOMPtr <nsICacheEntryDescriptor> cacheEntry;
// if mem cache entry is broken or empty, go to next message.
rv = cacheSession->OpenCacheEntry(cacheKey, nsICache::ACCESS_READ, PR_TRUE, getter_AddRefs(cacheEntry));
if (cacheEntry)
{
rv = cacheEntry->OpenInputStream(0, getter_AddRefs(inputStream));
if (NS_SUCCEEDED(rv))
{
PRUint32 bytesAvailable = 0;
rv = inputStream->Available(&bytesAvailable);
if (!bytesAvailable)
continue;
rv = GetMsgPreviewTextFromStream(msgHdr, inputStream);
}
}
else // lets look in the offline store
{
PRUint32 msgFlags;
msgHdr->GetFlags(&msgFlags);
if (msgFlags & MSG_FLAG_OFFLINE)
{
nsMsgKey msgKey;
msgHdr->GetMessageKey(&msgKey);
nsMsgKey messageOffset;
PRUint32 messageSize;
GetOfflineFileStream(msgKey, &messageOffset, &messageSize, getter_AddRefs(inputStream));
if (inputStream)
rv = GetMsgPreviewTextFromStream(msgHdr, inputStream);
}
}
}
return rv;
}

Просмотреть файл

@ -284,6 +284,10 @@ public:
NS_IMETHOD DownloadAllForOffline(nsIUrlListener *listener, nsIMsgWindow *msgWindow);
NS_IMETHOD GetCanFileMessages(PRBool *aCanFileMessages);
NS_IMETHOD GetCanDeleteMessages(PRBool *aCanDeleteMessages);
NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
PRBool *aAsyncResults);
// nsIMsgImapMailFolder methods
NS_DECL_NSIMSGIMAPMAILFOLDER

Просмотреть файл

@ -109,6 +109,7 @@
#include "nsIFileStreams.h"
#include "nsAutoPtr.h"
#include "nsIRssIncomingServer.h"
#include "nsNetUtil.h"
static NS_DEFINE_CID(kMailboxServiceCID, NS_MAILBOXSERVICE_CID);
@ -3712,6 +3713,7 @@ nsMsgLocalMailFolder::GetUidlFromFolder(nsLocalFolderScanState *aState,
size = aState->m_header.Length();
if (!size)
break;
// this isn't quite right - need to account for line endings
len -= size;
// account key header will always be before X_UIDL header
if (!accountKey)
@ -3722,7 +3724,8 @@ nsMsgLocalMailFolder::GetUidlFromFolder(nsLocalFolderScanState *aState,
accountKey += strlen(HEADER_X_MOZILLA_ACCOUNT_KEY) + 2;
aState->m_accountKey = accountKey;
}
} else
}
else
{
aState->m_uidl = strstr(aState->m_header.get(), X_UIDL);
if (aState->m_uidl)
@ -3813,3 +3816,45 @@ nsMsgLocalMailFolder::WarnIfLocalFileTooBig(nsIMsgWindow *aWindow, PRBool *aTooB
return NS_OK;
}
NS_IMETHODIMP nsMsgLocalMailFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
PRBool *aAsyncResults)
{
NS_ENSURE_ARG_POINTER(aKeysToFetch);
NS_ENSURE_ARG_POINTER(aAsyncResults);
*aAsyncResults = PR_FALSE;
nsXPIDLCString nativePath;
mPath->GetNativePath(getter_Copies(nativePath));
nsCOMPtr <nsILocalFile> localStore;
nsCOMPtr <nsIInputStream> inputStream;
nsresult rv = NS_NewNativeLocalFile(nativePath, PR_TRUE, getter_AddRefs(localStore));
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), localStore);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < aNumKeys; i++)
{
nsCOMPtr <nsIMsgDBHdr> msgHdr;
nsXPIDLCString prevBody;
rv = GetMessageHeader(aKeysToFetch[i], getter_AddRefs(msgHdr));
NS_ENSURE_SUCCESS(rv, rv);
// ignore messages that already have a preview body.
msgHdr->GetStringProperty("preview", getter_Copies(prevBody));
if (!prevBody.IsEmpty())
continue;
PRUint32 messageOffset;
msgHdr->GetMessageOffset(&messageOffset);
nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream);
if (seekableStream)
rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, messageOffset);
NS_ENSURE_SUCCESS(rv,rv);
rv = GetMsgPreviewTextFromStream(msgHdr, inputStream);
}
return rv;
}

Просмотреть файл

@ -196,6 +196,9 @@ public:
// Used when headers_only is TRUE
NS_IMETHOD DownloadMessagesForOffline(nsISupportsArray *aMessages, nsIMsgWindow *aWindow);
NS_IMETHOD FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint32 aNumKeys,
PRBool aLocalOnly, nsIUrlListener *aUrlListener,
PRBool *aAsyncResults);
protected: