зеркало из https://github.com/mozilla/pjs.git
262 строки
6.4 KiB
C++
262 строки
6.4 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.
|
|
*/
|
|
//
|
|
|
|
#include "msg.h"
|
|
#include "msgfcach.h"
|
|
#include "msgfinfo.h"
|
|
|
|
extern "C"
|
|
{
|
|
extern int MK_OUT_OF_MEMORY;
|
|
extern int MK_UNABLE_TO_OPEN_FILE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// MSG_FolderCacheElement
|
|
//
|
|
// MSG_FolderCacheElement is like a light FolderInfo. It holds as much
|
|
// folder info stuff as we want to put in the folder cache
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class MSG_FolderCacheElement
|
|
{
|
|
public:
|
|
MSG_FolderCacheElement ();
|
|
virtual ~MSG_FolderCacheElement ();
|
|
|
|
void Init (const char *);
|
|
|
|
// XP_Bool IsCacheOf (MSG_FolderInfo *);
|
|
|
|
static int CompareWithFolder(const void*, const void*); // asymmetric (for searching)
|
|
static int CompareElements(const void* pElem1, const void* pElem2); // symmetric (for insertion)
|
|
|
|
char *m_name;
|
|
char *m_folderSpecificStuff;
|
|
};
|
|
|
|
|
|
MSG_FolderCacheElement::MSG_FolderCacheElement ()
|
|
{
|
|
m_name = NULL;
|
|
m_folderSpecificStuff = NULL;
|
|
}
|
|
|
|
|
|
MSG_FolderCacheElement::~MSG_FolderCacheElement ()
|
|
{
|
|
XP_FREEIF(m_name);
|
|
XP_FREEIF(m_folderSpecificStuff);
|
|
}
|
|
|
|
|
|
void MSG_FolderCacheElement::Init (const char *buf)
|
|
{
|
|
int i;
|
|
for (i = 0; buf[i] != '\t'; i++)
|
|
; // do nothing; just count 'em up
|
|
|
|
m_name = (char*) XP_ALLOC(i + 1);
|
|
|
|
// Get the minimum stuff out of the line to uniquely identify
|
|
// a folder. We're using the pathname now, hopefully the relative path later.
|
|
XP_STRNCPY_SAFE(m_name, buf, i + 1);
|
|
|
|
// Pull out the rest of the stuff from the line. Since different
|
|
// folderInfo classes can have different stuff in the file, we'll
|
|
// virtualize reading/writing this in MSG_FolderInfo
|
|
m_folderSpecificStuff = XP_STRDUP(&buf[i] + 1);
|
|
}
|
|
|
|
#if 0
|
|
XP_Bool MSG_FolderCacheElement::IsCacheOf (MSG_FolderInfo *folder)
|
|
{
|
|
const char *relPath = folder->GetRelativePathName();
|
|
if (relPath && !XP_FILENAMECMP(relPath, m_name))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
int MSG_FolderCacheElement::CompareWithFolder(const void* pElemPtr, const void* pFolderPtr)
|
|
{
|
|
MSG_FolderCacheElement* elem = *(MSG_FolderCacheElement**)pElemPtr;
|
|
MSG_FolderInfo* folder = *(MSG_FolderInfo**)pFolderPtr;
|
|
const char *relPath = folder->GetRelativePathName();
|
|
if (!relPath)
|
|
{
|
|
XP_ASSERT(FALSE);
|
|
return -1; // sort folders with no name at the end?
|
|
}
|
|
return XP_FILENAMECMP(elem->m_name, relPath);
|
|
}
|
|
|
|
int MSG_FolderCacheElement::CompareElements(const void* pElem1, const void* pElem2)
|
|
{
|
|
MSG_FolderCacheElement* elem1 = *(MSG_FolderCacheElement**)pElem1;
|
|
MSG_FolderCacheElement* elem2 = *(MSG_FolderCacheElement**)pElem2;
|
|
return XP_FILENAMECMP(elem1->m_name, elem2->m_name);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// MSG_FolderCache
|
|
//
|
|
// Apparently, it's too slow to allow the folder tree to open all of its
|
|
// databases at initialization time. So this object is a persistent way
|
|
// to store the same stuff as the DBFolderInfo in just one file so it's
|
|
// faster to load
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
MSG_FolderCache::MSG_FolderCache ()
|
|
: XPSortedPtrArray(MSG_FolderCacheElement::CompareElements)
|
|
{
|
|
}
|
|
|
|
|
|
MSG_FolderCache::~MSG_FolderCache ()
|
|
{
|
|
Depopulate(); // probably done already, but just make sure
|
|
}
|
|
|
|
|
|
int MSG_FolderCache::ReadFromDisk ()
|
|
{
|
|
int ret = 0;
|
|
XP_File f = XP_FileOpen ("", xpFolderCache, XP_FILE_READ_BIN);
|
|
if (f)
|
|
{
|
|
const int bufSize = 1024; // big enough?
|
|
char *buf = (char*) XP_ALLOC(bufSize);
|
|
if (buf)
|
|
{
|
|
while (XP_FileReadLine (buf, bufSize, f))
|
|
{
|
|
MSG_FolderCacheElement *elem = new MSG_FolderCacheElement;
|
|
if (elem)
|
|
{
|
|
elem->Init (buf);
|
|
Add(elem);
|
|
}
|
|
else
|
|
ret = MK_OUT_OF_MEMORY;
|
|
}
|
|
XP_FREE(buf);
|
|
}
|
|
else
|
|
ret = MK_OUT_OF_MEMORY;
|
|
|
|
XP_FileClose (f);
|
|
|
|
// Delete folder cache once we've read it. This way, if we use the DBs, then crash,
|
|
// we won't be trusting a folder cache which contains out-of-date information.
|
|
XP_FileRemove ("", xpFolderCache);
|
|
|
|
}
|
|
else
|
|
ret = MK_UNABLE_TO_OPEN_FILE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int MSG_FolderCache::WriteToDisk (MSG_FolderInfo *root) const
|
|
{
|
|
XP_File f = 0;
|
|
int32 len = 0, count = 0;
|
|
|
|
if (root)
|
|
{
|
|
f = XP_FileOpen ("", xpFolderCache, XP_FILE_TRUNCATE_BIN);
|
|
if (f)
|
|
{
|
|
MSG_FolderIterator iter(root);
|
|
MSG_FolderInfo *folder = NULL;
|
|
count = XP_STRLEN(LINEBREAK);
|
|
while ((folder = iter.Next()) != NULL)
|
|
{
|
|
if ((folder->IsMail() || folder->IsNews()) && folder->IsCachable())
|
|
{
|
|
// Write in the mimimal amount of stuff we need to match a cache line
|
|
// with a folderInfo, then ask the folderInfo to add whatever it wants.
|
|
const char *relPath = folder->GetRelativePathName();
|
|
if (relPath)
|
|
{
|
|
XP_FilePrintf (f, "%s\t", relPath);
|
|
folder->WriteToCache (f);
|
|
len = XP_FileWrite (LINEBREAK, count, f);
|
|
if (len != count)
|
|
{
|
|
XP_FileClose(f);
|
|
return len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
XP_FileClose (f);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
XP_Bool MSG_FolderCache::InitializeFolder (MSG_FolderInfo *folder) const
|
|
{
|
|
#if 1
|
|
int index = FindIndexUsing(0, folder, MSG_FolderCacheElement::CompareWithFolder);
|
|
if (index < 0)
|
|
return FALSE;
|
|
MSG_FolderCacheElement *elem = GetAt(index);
|
|
folder->ReadFromCache(elem->m_folderSpecificStuff);
|
|
return TRUE;
|
|
#else
|
|
MSG_FolderCacheElement *elem;
|
|
for (int i = 0; i < GetSize(); i++)
|
|
{
|
|
elem = GetAt(i);
|
|
if (elem->IsCacheOf (folder))
|
|
{
|
|
folder->ReadFromCache (elem->m_folderSpecificStuff);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
#endif // 1
|
|
}
|
|
|
|
|
|
void MSG_FolderCache::Depopulate ()
|
|
{
|
|
MSG_FolderCacheElement *elem;
|
|
for (int i = 0; i < GetSize(); i++)
|
|
{
|
|
elem = GetAt(i);
|
|
delete elem;
|
|
}
|
|
}
|
|
|
|
|
|
MSG_FolderCacheElement *MSG_FolderCache::GetAt (int i) const
|
|
{
|
|
return (MSG_FolderCacheElement*) XPPtrArray::GetAt(i);
|
|
}
|