Back to index

lightning-sunbird  0.9+nobinonly
nsMsgOfflineImapOperation.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifdef MOZ_LOGGING
00039 // This has to be before the pre-compiled header
00040 #define FORCE_PR_LOG /* Allow logging in the release build */
00041 #endif
00042 
00043 #include "msgCore.h"
00044 #include "nsMsgOfflineImapOperation.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsMsgUtils.h"
00047 
00048 PRLogModuleInfo *IMAPOffline;
00049 
00050 /* Implementation file */
00051 NS_IMPL_ISUPPORTS1(nsMsgOfflineImapOperation, nsIMsgOfflineImapOperation)
00052 
00053 // property names for offine imap operation fields.
00054 #define PROP_OPERATION "op"
00055 #define PROP_OPERATION_FLAGS "opFlags"
00056 #define PROP_NEW_FLAGS "newFlags"
00057 #define PROP_MESSAGE_KEY "msgKey"
00058 #define PROP_SRC_MESSAGE_KEY "srcMsgKey"
00059 #define PROP_SRC_FOLDER_URI "srcFolderURI"
00060 #define PROP_MOVE_DEST_FOLDER_URI "moveDest"
00061 #define PROP_NUM_COPY_DESTS "numCopyDests"
00062 #define PROP_COPY_DESTS "copyDests" // how to delimit these? Or should we do the "dest1","dest2" etc trick? But then we'd need to shuffle
00063                                     // them around since we delete off the front first.
00064 #define PROP_KEYWORD_ADD "addedKeywords"
00065 #define PROP_KEYWORD_REMOVE "removedKeywords"
00066 #define PROP_MSG_SIZE "msgSize"
00067 
00068 nsMsgOfflineImapOperation::nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row)
00069 {
00070   NS_ASSERTION(db, "can't have null db");
00071   NS_ASSERTION(row, "can't have null row");
00072   m_operation = 0;
00073   m_operationFlags = 0;
00074   m_messageKey = nsMsgKey_None;
00075   m_sourceMessageKey = nsMsgKey_None;
00076   m_mdb = db; 
00077   NS_ADDREF(m_mdb);
00078   m_mdbRow = row;
00079   m_newFlags = 0;
00080   m_mdb->GetUint32Property(m_mdbRow, PROP_OPERATION, (PRUint32 *) &m_operation, 0);
00081   m_mdb->GetUint32Property(m_mdbRow, PROP_MESSAGE_KEY, &m_messageKey, 0);
00082   m_mdb->GetUint32Property(m_mdbRow, PROP_OPERATION_FLAGS, &m_operationFlags, 0);
00083   m_mdb->GetUint32Property(m_mdbRow, PROP_NEW_FLAGS, (PRUint32 *) &m_newFlags, 0);
00084 }
00085 
00086 nsMsgOfflineImapOperation::~nsMsgOfflineImapOperation()
00087 {
00088   NS_IF_RELEASE(m_mdb);
00089 }
00090 
00091 /* attribute nsOfflineImapOperationType operation; */
00092 NS_IMETHODIMP nsMsgOfflineImapOperation::GetOperation(nsOfflineImapOperationType *aOperation)
00093 {
00094   NS_ENSURE_ARG(aOperation);
00095   *aOperation = m_operation;
00096   return NS_OK;
00097 }
00098 
00099 NS_IMETHODIMP nsMsgOfflineImapOperation::SetOperation(nsOfflineImapOperationType aOperation)
00100 {
00101   if (PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS))
00102     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x setOperation was %x add %x", m_messageKey, m_operation, aOperation));
00103 
00104   m_operation |= aOperation;
00105   return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION, m_operation);
00106 }
00107 
00108 /* void clearOperation (in nsOfflineImapOperationType operation); */
00109 NS_IMETHODIMP nsMsgOfflineImapOperation::ClearOperation(nsOfflineImapOperationType aOperation)
00110 {
00111   if (PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS))
00112     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x clearOperation was %x clear %x", m_messageKey, m_operation, aOperation));
00113   m_operation &= ~aOperation;
00114   switch (aOperation)
00115   {
00116   case kMsgMoved:
00117   case kAppendTemplate:
00118   case kAppendDraft:
00119     m_moveDestination.Adopt(nsCRT::strdup(""));
00120     break;
00121   case kMsgCopy:
00122     m_copyDestinations.RemoveCStringAt(0);
00123     break;
00124   }
00125   return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION, m_operation);
00126 }
00127 
00128 /* attribute nsMsgKey messageKey; */
00129 NS_IMETHODIMP nsMsgOfflineImapOperation::GetMessageKey(nsMsgKey *aMessageKey)
00130 {
00131   NS_ENSURE_ARG(aMessageKey);
00132   *aMessageKey = m_messageKey;
00133   return NS_OK;
00134 }
00135 
00136 NS_IMETHODIMP nsMsgOfflineImapOperation::SetMessageKey(nsMsgKey aMessageKey)
00137 {
00138   m_messageKey = aMessageKey;
00139   return m_mdb->SetUint32Property(m_mdbRow, PROP_MESSAGE_KEY, m_messageKey);
00140 }
00141 
00142 
00143 /* attribute imapMessageFlagsType flagOperation; */
00144 NS_IMETHODIMP nsMsgOfflineImapOperation::GetFlagOperation(imapMessageFlagsType *aFlagOperation)
00145 {
00146   NS_ENSURE_ARG(aFlagOperation);
00147   *aFlagOperation = m_operationFlags;
00148   return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP nsMsgOfflineImapOperation::SetFlagOperation(imapMessageFlagsType aFlagOperation)
00152 {
00153   if (PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS))
00154     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x setFlagOperation was %x add %x", m_messageKey, m_operationFlags, aFlagOperation));
00155   SetOperation(kFlagsChanged);
00156   nsresult rv = SetNewFlags(aFlagOperation);
00157   NS_ENSURE_SUCCESS(rv, rv);
00158   m_operationFlags |= aFlagOperation;
00159   return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION_FLAGS, m_operationFlags);
00160 }
00161 
00162 /* attribute imapMessageFlagsType flagOperation; */
00163 NS_IMETHODIMP nsMsgOfflineImapOperation::GetNewFlags(imapMessageFlagsType *aNewFlags)
00164 {
00165   NS_ENSURE_ARG(aNewFlags);
00166   PRUint32 flags;
00167   nsresult rv = m_mdb->GetUint32Property(m_mdbRow, PROP_NEW_FLAGS, &flags, 0);
00168   *aNewFlags = m_newFlags = (imapMessageFlagsType) flags;
00169   return rv;
00170 }
00171 
00172 NS_IMETHODIMP nsMsgOfflineImapOperation::SetNewFlags(imapMessageFlagsType aNewFlags)
00173 {
00174   if (PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS) && m_newFlags != aNewFlags)
00175     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x SetNewFlags was %x to %x", m_messageKey, m_newFlags, aNewFlags));
00176   m_newFlags = aNewFlags;
00177   return m_mdb->SetUint32Property(m_mdbRow, PROP_NEW_FLAGS, m_newFlags);
00178 }
00179 
00180 
00181 /* attribute string destinationFolderURI; */
00182 NS_IMETHODIMP nsMsgOfflineImapOperation::GetDestinationFolderURI(char * *aDestinationFolderURI)
00183 {
00184   NS_ENSURE_ARG(aDestinationFolderURI);
00185   (void) m_mdb->GetProperty(m_mdbRow, PROP_MOVE_DEST_FOLDER_URI, getter_Copies(m_moveDestination));
00186   *aDestinationFolderURI = nsCRT::strdup(m_moveDestination);
00187   return (*aDestinationFolderURI) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00188 }
00189 
00190 NS_IMETHODIMP nsMsgOfflineImapOperation::SetDestinationFolderURI(const char * aDestinationFolderURI)
00191 {
00192   if (PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS))
00193     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x SetDestinationFolderURI to %s", m_messageKey, aDestinationFolderURI));
00194   m_moveDestination.Adopt(aDestinationFolderURI ? nsCRT::strdup(aDestinationFolderURI) : 0);
00195   return m_mdb->SetProperty(m_mdbRow, PROP_MOVE_DEST_FOLDER_URI, aDestinationFolderURI);
00196 }
00197 
00198 /* attribute string sourceFolderURI; */
00199 NS_IMETHODIMP nsMsgOfflineImapOperation::GetSourceFolderURI(char * *aSourceFolderURI)
00200 {
00201   NS_ENSURE_ARG(aSourceFolderURI);
00202   nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, getter_Copies(m_sourceFolder));
00203   *aSourceFolderURI = nsCRT::strdup(m_sourceFolder);
00204   return rv;
00205 }
00206 
00207 NS_IMETHODIMP nsMsgOfflineImapOperation::SetSourceFolderURI(const char * aSourceFolderURI)
00208 {
00209   m_sourceFolder.Adopt(aSourceFolderURI ? nsCRT::strdup(aSourceFolderURI) : 0);
00210   SetOperation(kMoveResult);
00211 
00212   return m_mdb->SetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, aSourceFolderURI);
00213 }
00214 
00215 /* attribute string keyword; */
00216 NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToAdd(char * *aKeywords)
00217 {
00218   NS_ENSURE_ARG(aKeywords);
00219   nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_ADD, getter_Copies(m_keywordsToAdd));
00220   *aKeywords = nsCRT::strdup(m_keywordsToAdd);
00221   return rv;
00222 }
00223 
00224 NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToAdd(const char * aKeyword)
00225 {
00226   return AddKeyword(aKeyword, m_keywordsToAdd, PROP_KEYWORD_ADD, m_keywordsToRemove, PROP_KEYWORD_REMOVE);
00227   nsACString::const_iterator start, end;
00228   if (!MsgFindKeyword(nsDependentCString(aKeyword), m_keywordsToAdd, start, end))
00229   {
00230     if (!m_keywordsToAdd.IsEmpty())
00231       m_keywordsToAdd.Append(' ');
00232     m_keywordsToAdd.Append(aKeyword);
00233   }
00234   // if the keyword we're adding was in the list of keywords to remove,
00235   // cut it from that list.
00236   nsACString::const_iterator removeStart, removeEnd;
00237   if (MsgFindKeyword(nsDependentCString(aKeyword), m_keywordsToRemove, removeStart, removeEnd))
00238   {
00239     nsACString::const_iterator saveStart;
00240     m_keywordsToRemove.BeginReading(saveStart);
00241     m_keywordsToRemove.Cut(Distance(saveStart, removeStart), Distance(removeStart, removeEnd));
00242     m_mdb->SetProperty(m_mdbRow, PROP_KEYWORD_REMOVE, m_keywordsToRemove.get());
00243   }
00244   SetOperation(kAddKeywords); 
00245   return m_mdb->SetProperty(m_mdbRow, PROP_KEYWORD_ADD, m_keywordsToAdd.get());
00246 }
00247 
00248 NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToRemove(char * *aKeywords)
00249 {
00250   NS_ENSURE_ARG(aKeywords);
00251   nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_REMOVE, getter_Copies(m_keywordsToRemove));
00252   *aKeywords = nsCRT::strdup(m_keywordsToRemove);
00253   return rv;
00254 }
00255 
00256 nsresult nsMsgOfflineImapOperation::AddKeyword(const char *aKeyword, nsCString &addList, const char *addProp,
00257                                                nsCString &removeList, const char *removeProp)
00258 {
00259   nsACString::const_iterator start, end;
00260   if (!MsgFindKeyword(nsDependentCString(aKeyword), addList, start, end))
00261   {
00262     if (!addList.IsEmpty())
00263       addList.Append(' ');
00264     addList.Append(aKeyword);
00265   }
00266   // if the keyword we're removing was in the list of keywords to add,
00267   // cut it from that list.
00268   nsACString::const_iterator addStart, addEnd;
00269   if (MsgFindKeyword(nsDependentCString(aKeyword), removeList, addStart, addEnd))
00270   {
00271     nsACString::const_iterator saveStart;
00272     removeList.BeginReading(saveStart);
00273     removeList.Cut(Distance(saveStart, addStart), Distance(addStart, addEnd));
00274     m_mdb->SetProperty(m_mdbRow, removeProp, removeList.get());
00275   }
00276   SetOperation(kRemoveKeywords);
00277   return m_mdb->SetProperty(m_mdbRow, addProp, addList.get());
00278 }
00279 
00280 NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToRemove(const char * aKeyword)
00281 {
00282   return AddKeyword(aKeyword, m_keywordsToRemove, PROP_KEYWORD_REMOVE, m_keywordsToAdd, PROP_KEYWORD_ADD);
00283 }
00284 
00285 
00286 NS_IMETHODIMP nsMsgOfflineImapOperation::AddMessageCopyOperation(const char *destinationBox)
00287 {
00288   SetOperation(kMsgCopy);
00289   nsCAutoString newDest(destinationBox);
00290   nsresult rv = GetCopiesFromDB();
00291   NS_ENSURE_SUCCESS(rv, rv);
00292   m_copyDestinations.AppendCString(newDest);
00293   return SetCopiesToDB();
00294 }
00295 
00296 // we write out the folders as one string, separated by 0x1.
00297 #define FOLDER_SEP_CHAR '\001'
00298 
00299 nsresult nsMsgOfflineImapOperation::GetCopiesFromDB()
00300 {
00301   nsXPIDLCString copyDests;
00302   m_copyDestinations.Clear();
00303   nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_COPY_DESTS, getter_Copies(copyDests));
00304   nsCAutoString copyDestsCString((const char *) copyDests);
00305   // use 0x1 as the delimiter between folder names since it's not a legal character
00306   if (NS_SUCCEEDED(rv) && !copyDestsCString.IsEmpty())
00307   {
00308     PRInt32 curCopyDestStart = 0;
00309     PRInt32 nextCopyDestPos = 0;
00310 
00311     while (nextCopyDestPos != -1)
00312     {
00313       nsCString curDest;
00314       nextCopyDestPos = copyDestsCString.FindChar(FOLDER_SEP_CHAR, curCopyDestStart);
00315       if (nextCopyDestPos > 0)
00316         copyDestsCString.Mid(curDest, curCopyDestStart, nextCopyDestPos - curCopyDestStart);
00317       else
00318         copyDestsCString.Mid(curDest, curCopyDestStart, copyDestsCString.Length() - curCopyDestStart);
00319       curCopyDestStart = nextCopyDestPos + 1;
00320       m_copyDestinations.AppendCString(curDest);
00321     }
00322   }
00323   return rv;
00324 }
00325 
00326 nsresult nsMsgOfflineImapOperation::SetCopiesToDB()
00327 {
00328   nsCAutoString copyDests;
00329 
00330   // use 0x1 as the delimiter between folders
00331   for (PRInt32 i = 0; i < m_copyDestinations.Count(); i++)
00332   {
00333     if (i > 0)
00334       copyDests.Append(FOLDER_SEP_CHAR);
00335     nsCString *curDest = m_copyDestinations.CStringAt(i);
00336     copyDests.Append(curDest->get());
00337   }
00338   return m_mdb->SetProperty(m_mdbRow, PROP_COPY_DESTS, copyDests.get());
00339 }
00340 
00341 /* attribute long numberOfCopies; */
00342 NS_IMETHODIMP nsMsgOfflineImapOperation::GetNumberOfCopies(PRInt32 *aNumberOfCopies)
00343 {
00344   NS_ENSURE_ARG(aNumberOfCopies);
00345   nsresult rv = GetCopiesFromDB();
00346   NS_ENSURE_SUCCESS(rv, rv);
00347   *aNumberOfCopies = m_copyDestinations.Count();
00348   return NS_OK;
00349 }
00350 
00351 /* string getCopyDestination (in long copyIndex); */
00352 NS_IMETHODIMP nsMsgOfflineImapOperation::GetCopyDestination(PRInt32 copyIndex, char **retval)
00353 {
00354   NS_ENSURE_ARG(retval);
00355   nsresult rv = GetCopiesFromDB();
00356   NS_ENSURE_SUCCESS(rv, rv);
00357   nsCString *copyDest = m_copyDestinations.CStringAt(copyIndex);
00358   if (copyDest)
00359   {
00360     *retval = ToNewCString(*copyDest);
00361     return (*retval) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00362   }
00363   else
00364     return NS_ERROR_NULL_POINTER;
00365 }
00366 
00367 /* attribute unsigned log msgSize; */
00368 NS_IMETHODIMP nsMsgOfflineImapOperation::GetMsgSize(PRUint32 *aMsgSize)
00369 {
00370   NS_ENSURE_ARG(aMsgSize);
00371   return m_mdb->GetUint32Property(m_mdbRow, PROP_MSG_SIZE, aMsgSize, 0);
00372 }
00373 
00374 NS_IMETHODIMP nsMsgOfflineImapOperation::SetMsgSize(PRUint32 aMsgSize)
00375 {
00376   return m_mdb->SetUint32Property(m_mdbRow, PROP_MSG_SIZE, aMsgSize);
00377 }
00378 
00379 void nsMsgOfflineImapOperation::Log(PRLogModuleInfo *logFile)
00380 {
00381   if (!IMAPOffline)
00382     IMAPOffline = PR_NewLogModule("IMAPOFFLINE");
00383   if (!PR_LOG_TEST(IMAPOffline, PR_LOG_ALWAYS))
00384     return;
00385 //  const long kMoveResult                = 0x8;
00386 //  const long kAppendDraft        = 0x10;
00387 //  const long kAddedHeader        = 0x20;
00388 //  const long kDeletedMsg                = 0x40;
00389 //  const long kMsgMarkedDeleted   = 0x80;
00390 //  const long kAppendTemplate     = 0x100;
00391 //  const long kDeleteAllMsgs             = 0x200;
00392   if (m_operation & nsIMsgOfflineImapOperation::kFlagsChanged)
00393   {
00394       PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x changeFlag:%x", m_messageKey, m_newFlags));
00395   }
00396   if (m_operation & nsIMsgOfflineImapOperation::kMsgMoved)
00397   {
00398     nsXPIDLCString moveDestFolder;
00399     GetDestinationFolderURI(getter_Copies(moveDestFolder));
00400 
00401     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x moveTo:%s", m_messageKey, moveDestFolder.get()));
00402   }
00403   if (m_operation & nsIMsgOfflineImapOperation::kMsgCopy)
00404   {
00405     nsXPIDLCString copyDests;
00406     m_mdb->GetProperty(m_mdbRow, PROP_COPY_DESTS, getter_Copies(copyDests));
00407 
00408     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x moveTo:%s", m_messageKey, copyDests.get()));
00409   }
00410   if (m_operation & nsIMsgOfflineImapOperation::kAppendDraft)
00411   {
00412     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x append draft", m_messageKey));
00413   }
00414   if (m_operation & nsIMsgOfflineImapOperation::kAddKeywords)
00415   {
00416     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x add keyword:%s", m_messageKey, m_keywordsToAdd.get()));
00417   }
00418   if (m_operation & nsIMsgOfflineImapOperation::kRemoveKeywords)
00419   {
00420     PR_LOG(IMAPOffline, PR_LOG_ALWAYS, ("msg id %x remove keyword:%s", m_messageKey, m_keywordsToRemove.get()));
00421   }
00422 
00423 }