Back to index

lightning-sunbird  0.9+nobinonly
nsOEScanBoxes.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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) 1998
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 #include "nsOEScanBoxes.h"
00038 #include "nsIComponentManager.h"
00039 #include "nsIServiceManager.h"
00040 #include "nsIImportService.h"
00041 #include "nsIImportMailboxDescriptor.h"
00042 
00043 #include "nsOERegUtil.h"
00044 #include "nsOE5File.h"
00045 
00046 #include "OEDebugLog.h"
00047 
00048 #include "nsNativeCharsetUtils.h"
00049 
00050 /*
00051        .nch file format???
00052 
00053        offset 20 - long = offset to first record
00054 
00055 */
00056 
00057 static NS_DEFINE_IID(kISupportsIID,                     NS_ISUPPORTS_IID);
00058 
00059 nsOEScanBoxes::nsOEScanBoxes()
00060 {
00061        m_pFirst = nsnull;
00062 }
00063 
00064 nsOEScanBoxes::~nsOEScanBoxes()
00065 {
00066        int i, max;
00067   MailboxEntry *pEntry;
00068        for (i = 0, max = m_entryArray.Count(); i < max; i++) {
00069               pEntry = (MailboxEntry *) m_entryArray.ElementAt( i);
00070               delete pEntry;
00071        }
00072   // Now free the unprocessed child entries (ie, those without parents for some reason).
00073   for (i = 0, max = m_pendingChildArray.Count(); i < max; i++)
00074   {
00075     pEntry = (MailboxEntry *) m_pendingChildArray.ElementAt(i);
00076     if (!pEntry->processed)
00077       delete pEntry;
00078   }
00079 }
00080 
00081 /*
00082  3.x & 4.x registry
00083        Software/Microsoft/Outlook Express/
00084 
00085  5.0 registry
00086        Identies - value of "Default User ID" is {GUID}
00087        Identities/{GUID}/Software/Microsoft/Outlook Express/5.0/
00088 */
00089 
00090 PRBool nsOEScanBoxes::Find50Mail( nsIFileSpec *pWhere)
00091 {
00092        nsresult      rv;
00093        PRBool        success = PR_FALSE;
00094        HKEY          sKey;
00095 
00096        if (::RegOpenKeyEx( HKEY_CURRENT_USER, "Identities", 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) {
00097               BYTE * pBytes = nsOERegUtil::GetValueBytes( sKey, "Default User ID");
00098               ::RegCloseKey( sKey);
00099               if (pBytes) {
00100                      nsCString     key( "Identities\\");
00101                      key += (const char *)pBytes;
00102                      nsOERegUtil::FreeValueBytes( pBytes);
00103                      key += "\\Software\\Microsoft\\Outlook Express\\5.0";
00104                      if (::RegOpenKeyEx( HKEY_CURRENT_USER, key.get(), 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) {
00105                             pBytes = nsOERegUtil::GetValueBytes( sKey, "Store Root");
00106                             if (pBytes) {
00107                                    pWhere->SetNativePath((char *)pBytes);
00108                                    
00109                                    IMPORT_LOG1( "Setting native path: %s\n", pBytes);
00110 
00111                                    nsOERegUtil::FreeValueBytes( pBytes);
00112                                    PRBool isDir = PR_FALSE;
00113                                    rv = pWhere->IsDirectory( &isDir);
00114                                    if (isDir && NS_SUCCEEDED( rv))
00115                                           success = PR_TRUE;
00116                             }
00117                             ::RegCloseKey( sKey);
00118                      }
00119               }
00120        }
00121        
00122        return( success);
00123 }
00124 
00125 PRBool nsOEScanBoxes::FindMail( nsIFileSpec *pWhere)
00126 {
00127        nsresult      rv;
00128        PRBool        success = PR_FALSE;
00129        HKEY          sKey;
00130        
00131        if (Find50Mail( pWhere))
00132               return( PR_TRUE);
00133 
00134        if (::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\Outlook Express", 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) {
00135               LPBYTE pBytes = nsOERegUtil::GetValueBytes( sKey, "Store Root");
00136               if (pBytes) {
00137                      pWhere->SetNativePath((char *)pBytes);
00138                      pWhere->AppendRelativeUnixPath( "Mail");
00139                      PRBool isDir = PR_FALSE;
00140                      rv = pWhere->IsDirectory( &isDir);
00141                      if (isDir && NS_SUCCEEDED( rv))
00142                             success = PR_TRUE;
00143                      delete [] pBytes;
00144               }
00145               ::RegCloseKey( sKey);              
00146        }
00147        
00148        return( success);
00149 }
00150 
00151 PRBool nsOEScanBoxes::GetMailboxes( nsIFileSpec *pWhere, nsISupportsArray **pArray)
00152 {
00153        char *path = nsnull;
00154        pWhere->GetNSPRPath( &path);
00155        if (path) {
00156               IMPORT_LOG1( "Looking for mail in: %s\n", path);
00157               nsCRT::free( path);
00158        }
00159        else {
00160               pWhere->GetLeafName( &path);
00161               if (path) {
00162                      IMPORT_LOG1( "Looking for mail in: %s\n", path);
00163                      nsCRT::free( path);
00164               }
00165               else {
00166                      IMPORT_LOG0( "Unable to get info about where to look for mail\n");
00167               }
00168        }
00169        
00170        nsIFileSpec   *where;
00171        if (NS_FAILED( NS_NewFileSpec( &where)))
00172               return( PR_FALSE);
00173        where->FromFileSpec( pWhere);
00174 
00175        // 1. Look for 5.0 folders.dbx
00176        // 2. Look for 3.x & 4.x folders.nch
00177        // 3. Look for 5.0 *.dbx mailboxes
00178        // 4. Look for 3.x & 4.x *.mbx mailboxes
00179        
00180        PRBool result;
00181 
00182        where->AppendRelativeUnixPath( "folders.dbx");
00183        if (Find50MailBoxes( where)) {
00184               where->CloseStream();
00185               result = GetMailboxList( pWhere, pArray);
00186        }
00187        else {
00188               // 2. Look for 4.x mailboxes
00189               where->FromFileSpec( pWhere);
00190               where->AppendRelativeUnixPath( "folders.nch");
00191        
00192               if (FindMailBoxes( where)) {
00193                      where->CloseStream();
00194                      result = GetMailboxList( pWhere, pArray);
00195               }
00196               else {
00197                      // 3 & 4, look for the specific mailbox files.
00198                      where->CloseStream();
00199                      where->FromFileSpec( pWhere);
00200                      ScanMailboxDir( where);
00201                      result = GetMailboxList( pWhere, pArray);
00202               }
00203        }
00204               
00205        where->Release();
00206        return( result);
00207 }
00208 
00209 
00210 
00211 void nsOEScanBoxes::Reset( void)
00212 {
00213        int max = m_entryArray.Count();
00214        for (int i = 0; i < max; i++) {
00215               MailboxEntry *pEntry = (MailboxEntry *) m_entryArray.ElementAt( i);
00216               delete pEntry;
00217        }
00218        m_entryArray.Clear();
00219        m_pFirst = nsnull;
00220 }
00221 
00222 
00223 PRBool nsOEScanBoxes::FindMailBoxes( nsIFileSpec* descFile)
00224 {
00225        Reset();
00226        
00227        nsresult      rv;
00228        PRBool        isFile = PR_FALSE;
00229        
00230        rv = descFile->IsFile( &isFile);
00231        if (NS_FAILED( rv) || !isFile)
00232               return( PR_FALSE);
00233        
00234        rv = descFile->OpenStreamForReading();    
00235        if (NS_FAILED( rv))
00236               return( PR_FALSE);
00237 
00238        IMPORT_LOG0( "Reading the folders.nch file\n");
00239        
00240        PRUint32             curRec;
00241        if (!ReadLong( descFile, curRec, 20)) {
00242               return( PR_FALSE);
00243        }
00244 
00245        // Now for each record
00246        PRBool               done = PR_FALSE;
00247        PRUint32             equal;
00248        PRUint32             size;
00249        PRUint32             previous;
00250        PRUint32             next;
00251        MailboxEntry *       pEntry;
00252        PRBool               failed;
00253        nsCString            ext;
00254        nsCString            mbxExt( ".mbx");
00255        
00256        while (!done) {
00257               
00258               if (!ReadLong( descFile, equal, curRec)) return( PR_FALSE);
00259               if (curRec != equal) {
00260                      IMPORT_LOG1( "Record start invalid: %ld\n", curRec);
00261                      break;
00262               }
00263               if (!ReadLong( descFile, size, curRec + 4)) return( PR_FALSE);
00264               if (!ReadLong( descFile, previous, curRec + 8)) return( PR_FALSE);
00265               if (!ReadLong( descFile, next, curRec + 12)) return( PR_FALSE);
00266               failed = PR_FALSE;
00267               pEntry = new MailboxEntry;
00268               if (!ReadLong( descFile, pEntry->index, curRec + 16)) failed = PR_TRUE;
00269               if (!ReadString( descFile, pEntry->mailName, curRec + 20)) failed = PR_TRUE;
00270               if (!ReadString( descFile, pEntry->fileName, curRec + 279)) failed = PR_TRUE;
00271               if (!ReadLong( descFile, pEntry->parent, curRec + 539)) failed = PR_TRUE;
00272               if (!ReadLong( descFile, pEntry->child, curRec + 543)) failed = PR_TRUE;
00273               if (!ReadLong( descFile, pEntry->sibling, curRec + 547)) failed = PR_TRUE;
00274               if (!ReadLong( descFile, pEntry->type, curRec + 551)) failed = PR_TRUE;
00275               if (failed) {
00276                      delete pEntry;
00277                      return( PR_FALSE);
00278               }
00279 
00280               #ifdef _TRACE_MAILBOX_ENTRIES
00281               IMPORT_LOG0( "------------\n");
00282               IMPORT_LOG2( "    Offset: %lx, index: %ld\n", curRec, pEntry->index);
00283               IMPORT_LOG2( "      previous: %lx, next: %lx\n", previous, next);
00284               IMPORT_LOG2( "      Name: %S, File: %s\n", (PRUnichar *) pEntry->mailName, (const char *) pEntry->fileName);
00285               IMPORT_LOG3( "      Parent: %ld, Child: %ld, Sibling: %ld\n", pEntry->parent, pEntry->child, pEntry->sibling);
00286               #endif
00287               
00288               pEntry->fileName.Right( ext, 4);
00289               if (!ext.Equals(mbxExt))
00290                      pEntry->fileName.Append( ".mbx");         
00291               
00292               m_entryArray.AppendElement( pEntry);
00293 
00294               curRec = next;
00295               if (!next)
00296                      done = PR_TRUE;
00297        }
00298        
00299        MailboxEntry *pZero = GetIndexEntry( 0);
00300        if (pZero)
00301               m_pFirst = GetIndexEntry( pZero->child);
00302        
00303        IMPORT_LOG1( "Read the folders.nch file, found %ld mailboxes\n", (long) m_entryArray.Count());
00304        
00305        return( PR_TRUE);
00306 }
00307 
00308 PRBool nsOEScanBoxes::Find50MailBoxes( nsIFileSpec* descFile)
00309 {
00310        Reset();
00311        
00312        nsresult      rv;
00313        PRBool        isFile = PR_FALSE;
00314        
00315        rv = descFile->IsFile( &isFile);
00316        if (NS_FAILED( rv) || !isFile)
00317               return( PR_FALSE);
00318        
00319        rv = descFile->OpenStreamForReading();    
00320        if (NS_FAILED( rv))
00321               return( PR_FALSE);
00322 
00323        IMPORT_LOG0( "Reading the folders.dbx file\n");
00324        
00325        PRUint32 *           pIndex;
00326        PRUint32             indexSize = 0;
00327        if (!nsOE5File::ReadIndex( descFile, &pIndex, &indexSize)) {
00328               IMPORT_LOG0( "*** NOT USING FOLDERS.DBX!!!\n");
00329               return( PR_FALSE);
00330        }
00331        
00332        PRUint32      marker;
00333        PRUint32      size;
00334        char   *      pBytes;
00335        PRInt32              cntRead;
00336        PRInt32              recordId;
00337        PRInt32              strOffset;
00338 
00339        PRUint8              tag;
00340        PRUint32      data;
00341        PRInt32              dataOffset;
00342        
00343        PRUint32             id;
00344        PRUint32             parent;
00345        PRUint32             numMessages;
00346        char *               pFileName;
00347        char *               pDataSource;
00348 
00349        MailboxEntry *       pEntry;
00350        MailboxEntry *       pLastEntry = nsnull;
00351 
00352        PRUint32      localStoreId = 0;
00353 
00354        for (PRUint32 i = 0; i < indexSize; i++) {
00355               if (!ReadLong( descFile, marker, pIndex[i])) continue;
00356               if (marker != pIndex[i]) continue;
00357               if (!ReadLong( descFile, size, pIndex[i] + 4)) continue;
00358               size += 4;
00359               pBytes = new char[size];
00360               rv = descFile->Read( &pBytes, size, &cntRead);
00361               if (NS_FAILED( rv) || ((PRUint32)cntRead != size)) {
00362                      delete [] pBytes;
00363                      continue;
00364               }
00365               recordId = pBytes[2];
00366               strOffset = (recordId * 4) + 4;
00367               if (recordId == 4)
00368                      strOffset += 4;
00369               
00370               id = 0;
00371               parent = 0;
00372               numMessages = 0;
00373               pFileName = nsnull;
00374               pDataSource = nsnull;
00375               dataOffset = 4;
00376               while (dataOffset < strOffset) {
00377                      tag = (PRUint8) pBytes[dataOffset];
00378 
00379       data = 0; // make sure all bytes are 0 before copying 3 bytes over.
00380                      memcpy( &data, &(pBytes[dataOffset + 1]), 3);
00381                      switch( tag) {
00382                             case 0x80: // id record
00383                                    id = data;
00384                             break;        
00385                             case 0x81:    // parent id
00386                                    parent = data;
00387                             break;
00388                             case 0x87:    // number of messages in this mailbox
00389                                    numMessages = data;
00390                             break;
00391                             case 0x03:    // file name for this mailbox
00392                                    if (((PRUint32)strOffset + data) < size)
00393                                           pFileName = (char *)(pBytes + strOffset + data);
00394                             break;
00395                             case 0x05:    // data source for this record (this is not a mailbox!)
00396                                    if (((PRUint32)strOffset + data) < size)
00397                                           pDataSource = (char *) (pBytes + strOffset + data);
00398                             break;
00399                      }
00400                      dataOffset += 4;
00401               }
00402               
00403               // now build an entry if necessary!
00404               if (pDataSource) {
00405                      if (!nsCRT::strcasecmp( pDataSource, "LocalStore"))
00406       {
00407                             localStoreId = id;   
00408         // See if we have any child folders that need to be added/processed for this top level parent.
00409         ProcessPendingChildEntries(localStoreId, localStoreId, m_pendingChildArray);
00410         // Clean up the pending list.
00411         RemoveProcessedChildEntries();
00412       }
00413               }
00414               else if (id && localStoreId && parent) {
00415                      // veryify that this mailbox is in the local store
00416                      data = parent;
00417                      while (data && (data != localStoreId)) {
00418                             pEntry = GetIndexEntry( data);
00419                             if (pEntry)
00420                                    data = pEntry->parent;
00421                             else
00422                                    data = 0;
00423                      }
00424                      if (data == localStoreId) {
00425                             // Create an entry for this bugger
00426         pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
00427         if (pEntry)
00428         {
00429                               AddChildEntry( pEntry, localStoreId);
00430           pEntry->processed =  PR_TRUE;
00431           // See if we have any child folders that need to be added/processed.
00432           ProcessPendingChildEntries(id, localStoreId, m_pendingChildArray);
00433           // Clean up the pending list.
00434           RemoveProcessedChildEntries();
00435         }
00436                      }
00437       else
00438       {
00439         // Put this folder into child array and process it when its parent shows up.
00440         pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
00441         if (pEntry)
00442           m_pendingChildArray.AppendElement(pEntry);
00443       }
00444               }
00445     else if (pFileName)
00446     {
00447       // Put this folder into child array and process it when its parent shows up.
00448       // For some reason, it's likely that child folders come before their parents.
00449       pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
00450       if (pEntry)
00451         m_pendingChildArray.AppendElement(pEntry);
00452     }
00453 
00454               delete [] pBytes;
00455        }
00456        
00457 
00458        delete [] pIndex;
00459 
00460        if (m_entryArray.Count())
00461               return( PR_TRUE);
00462        else
00463               return( PR_FALSE);
00464 }
00465 
00466 nsOEScanBoxes::MailboxEntry *nsOEScanBoxes::NewMailboxEntry(PRUint32 id, PRUint32 parent, const char *prettyName, char *pFileName)
00467 {
00468   MailboxEntry *pEntry = new MailboxEntry();
00469   if (!pEntry)
00470     return nsnull;
00471 
00472   pEntry->index = id;
00473   pEntry->parent = parent;
00474   pEntry->child = 0;
00475   pEntry->type = 0;
00476   pEntry->sibling = -1;
00477   pEntry->processed =  PR_FALSE;
00478   NS_CopyNativeToUnicode(nsDependentCString(prettyName), pEntry->mailName);
00479   if (pFileName)
00480          pEntry->fileName = pFileName;
00481   return pEntry;
00482 }
00483 
00484 void nsOEScanBoxes::ProcessPendingChildEntries(PRUint32 parent, PRUint32 rootIndex, nsVoidArray   &childArray)
00485 {
00486   PRInt32 i, max;
00487   MailboxEntry *pEntry;
00488   for (i = 0, max = childArray.Count(); i < max; i++)
00489   {
00490     pEntry = (MailboxEntry *) childArray.ElementAt(i);
00491     if ((!pEntry->processed) && (pEntry->parent == parent))
00492     {
00493       AddChildEntry(pEntry, rootIndex);
00494       pEntry->processed =  PR_TRUE; // indicate it's been processed.
00495       // See if there are unprocessed child folders for this child in the
00496       // array as well (ie, both child and grand-child are on the list).
00497       ProcessPendingChildEntries(pEntry->index, rootIndex, childArray);
00498     }
00499   }
00500 }
00501 
00502 void nsOEScanBoxes::RemoveProcessedChildEntries()
00503 {
00504   // Remove already processed entries from the pending list. Note that these entries are also
00505   // on 'm_entryArray' list so we don't want to deallocate the space for the entries now.
00506   MailboxEntry * pEntry;
00507   PRInt32 i;
00508   for (i = m_pendingChildArray.Count()-1; i >= 0; i--)
00509   {
00510     pEntry = (MailboxEntry *) m_pendingChildArray.ElementAt(i);
00511     if (pEntry->processed)
00512       m_pendingChildArray.RemoveElementAt(i);
00513   }
00514 }
00515 
00516 void nsOEScanBoxes::AddChildEntry( MailboxEntry *pEntry, PRUint32 rootIndex)
00517 {
00518        if (!m_pFirst) {
00519               if (pEntry->parent == rootIndex) {
00520                      m_pFirst = pEntry;
00521                      m_entryArray.AppendElement( pEntry);
00522               }
00523               else {
00524                      delete pEntry;
00525               }
00526               return;
00527        }
00528        
00529        MailboxEntry *       pParent = nsnull;
00530        MailboxEntry *       pSibling = nsnull;
00531        if (pEntry->parent == rootIndex) {
00532               pSibling = m_pFirst;
00533        }
00534        else {
00535               pParent = GetIndexEntry( pEntry->parent);
00536        }
00537        
00538        if (!pParent && !pSibling) {
00539               delete pEntry;
00540               return;
00541        }
00542 
00543        if (pParent && (pParent->child == 0)) {
00544               pParent->child = pEntry->index;
00545               m_entryArray.AppendElement( pEntry);
00546               return;
00547        }
00548        
00549        if (!pSibling)
00550               pSibling = GetIndexEntry( pParent->child);
00551 
00552        while (pSibling && (pSibling->sibling != -1)) {
00553               pSibling = GetIndexEntry( pSibling->sibling);
00554        }
00555 
00556        if (!pSibling) {
00557               delete pEntry;
00558               return;
00559        }
00560 
00561        pSibling->sibling = pEntry->index;
00562        m_entryArray.AppendElement( pEntry);
00563 }
00564 
00565 PRBool nsOEScanBoxes::Scan50MailboxDir( nsIFileSpec * srcDir)
00566 {
00567        Reset();
00568 
00569        MailboxEntry *       pEntry;       
00570        PRInt32                     index = 1;
00571        char *               pLeaf;
00572        PRUint32             sLen;
00573        
00574        nsIFileSpec *               spec;
00575        nsIDirectoryIterator *      iter;
00576        
00577        if (NS_FAILED( NS_NewDirectoryIterator( &iter)))
00578               return( PR_FALSE);
00579        if (NS_FAILED( iter->Init( srcDir, PR_TRUE))) {
00580               iter->Release();
00581               return( PR_FALSE);
00582        }
00583 
00584        nsresult      rv;
00585        PRBool        exists = PR_FALSE;
00586        PRBool        isFile;
00587        
00588        rv = iter->Exists( &exists);
00589        while (NS_SUCCEEDED( rv) && exists) {
00590            // do something with i.Spec()
00591            rv = iter->GetCurrentSpec( &spec);
00592            if (NS_SUCCEEDED( rv)) {
00593               isFile = PR_FALSE;
00594               rv = spec->IsFile( &isFile);
00595                      if (NS_SUCCEEDED( rv) && isFile) {
00596                             pLeaf = nsnull;
00597                             rv = spec->GetLeafName( &pLeaf);
00598                             if (NS_SUCCEEDED( rv) && pLeaf && 
00599                                    ((sLen = strlen( pLeaf)) > 4) && 
00600                                    (!nsCRT::strcasecmp( pLeaf + sLen - 3, "dbx"))) {
00601                                    // This is a *.dbx file in the mail directory
00602                                    if (nsOE5File::IsLocalMailFile( spec)) {
00603                                           pEntry = new MailboxEntry;
00604                                           pEntry->index = index;
00605                                           index++;
00606                                           pEntry->parent = 0;
00607                                           pEntry->child = 0;
00608                                           pEntry->sibling = index;
00609                                           pEntry->type = -1;
00610                                           pEntry->fileName = pLeaf;
00611                                           pLeaf[sLen - 4] = 0;
00612                                           NS_CopyNativeToUnicode(nsDependentCString(pLeaf), pEntry->mailName);
00613                                           m_entryArray.AppendElement( pEntry);                           
00614                                    }
00615                             }
00616                             if (pLeaf)
00617                                    nsCRT::free( pLeaf);
00618                      }
00619               }
00620               rv = iter->Next();    
00621               exists = PR_FALSE;
00622               rv = iter->Exists( &exists);
00623        }
00624        
00625        if (m_entryArray.Count() > 0) {
00626               pEntry = (MailboxEntry *)m_entryArray.ElementAt( m_entryArray.Count() - 1);
00627               pEntry->sibling = -1;
00628               return( PR_TRUE);
00629        }
00630 
00631        return( PR_FALSE);
00632 }
00633 
00634 
00635 void nsOEScanBoxes::ScanMailboxDir( nsIFileSpec * srcDir)
00636 {
00637        if (Scan50MailboxDir( srcDir))
00638               return;
00639 
00640        Reset();
00641 
00642        MailboxEntry *       pEntry;       
00643        PRInt32                     index = 1;
00644        char *               pLeaf;
00645        PRUint32             sLen;
00646        
00647        nsIFileSpec *               spec;
00648        nsIDirectoryIterator *      iter;
00649        
00650        if (NS_FAILED( NS_NewDirectoryIterator( &iter)))
00651               return;
00652        if (NS_FAILED( iter->Init( srcDir, PR_TRUE))) {
00653               iter->Release();
00654               return;
00655        }
00656        nsresult      rv;
00657        PRBool        exists = PR_FALSE;
00658        PRBool        isFile;
00659        
00660        rv = iter->Exists( &exists);
00661        while (NS_SUCCEEDED( rv) && exists) {
00662            // do something with i.Spec()
00663            rv = iter->GetCurrentSpec( &spec);
00664            if (NS_SUCCEEDED( rv)) {
00665               isFile = PR_FALSE;
00666               rv = spec->IsFile( &isFile);
00667                      if (NS_SUCCEEDED( rv) && isFile) {
00668                             pLeaf = nsnull;
00669                             rv = spec->GetLeafName( &pLeaf);
00670                             if (NS_SUCCEEDED( rv) && pLeaf && 
00671                                    ((sLen = strlen( pLeaf)) > 4) && 
00672                                    (!nsCRT::strcasecmp( pLeaf + sLen - 3, "mbx"))) {
00673                                    // This is a *.mbx file in the mail directory
00674                                    pEntry = new MailboxEntry;
00675                                    pEntry->index = index;
00676                                    index++;
00677                                    pEntry->parent = 0;
00678                                    pEntry->child = 0;
00679                                    pEntry->sibling = index;
00680                                    pEntry->type = -1;
00681                                    pEntry->fileName = pLeaf;
00682                                    pLeaf[sLen - 4] = 0;
00683                                    NS_CopyNativeToUnicode(nsDependentCString(pLeaf), pEntry->mailName);
00684                                    m_entryArray.AppendElement( pEntry);                           
00685                             }
00686                             if (pLeaf)
00687                                    nsCRT::free( pLeaf);
00688                      }
00689               }
00690               rv = iter->Next();    
00691               exists = PR_FALSE;
00692               rv = iter->Exists( &exists);
00693        }
00694        
00695        if (m_entryArray.Count() > 0) {
00696               pEntry = (MailboxEntry *)m_entryArray.ElementAt( m_entryArray.Count() - 1);
00697               pEntry->sibling = -1;
00698        }
00699 }
00700 
00701 
00702 PRUint32 nsOEScanBoxes::CountMailboxes( MailboxEntry *pBox)
00703 {
00704        if (pBox == nsnull) {
00705               if (m_pFirst != nsnull)
00706                      pBox = m_pFirst;
00707               else {
00708                      if (m_entryArray.Count() > 0)
00709                             pBox = (MailboxEntry *) m_entryArray.ElementAt( 0);
00710               }
00711        }
00712        PRUint32             count = 0;
00713        
00714        MailboxEntry *       pChild;
00715        while (pBox) {
00716               count++;
00717               if (pBox->child) {
00718                      pChild = GetIndexEntry( pBox->child);
00719                      if (pChild != nsnull)
00720                             count += CountMailboxes( pChild);
00721               }
00722               if (pBox->sibling != -1) {
00723                      pBox = GetIndexEntry( pBox->sibling);
00724               }
00725               else
00726                      pBox = nsnull;
00727        }
00728        
00729        return( count);
00730 }
00731 
00732 PRBool nsOEScanBoxes::GetMailboxList( nsIFileSpec * root, nsISupportsArray **pArray)
00733 {      
00734        nsresult rv = NS_NewISupportsArray( pArray);
00735        if (NS_FAILED( rv)) {
00736               IMPORT_LOG0( "FAILED to allocate the nsISupportsArray\n");
00737               return( PR_FALSE);
00738        }
00739        
00740        BuildMailboxList( nsnull, root, 1, *pArray);
00741        
00742        return( PR_TRUE);
00743 }
00744 
00745 void nsOEScanBoxes::BuildMailboxList( MailboxEntry *pBox, nsIFileSpec * root, PRInt32 depth, nsISupportsArray *pArray)
00746 {
00747        if (pBox == nsnull) {
00748               if (m_pFirst != nsnull) {
00749                      pBox = m_pFirst;
00750                      
00751                      IMPORT_LOG0( "Assigning start of mailbox list to m_pFirst\n");
00752               }
00753               else {
00754                      if (m_entryArray.Count() > 0) {
00755                             pBox = (MailboxEntry *) m_entryArray.ElementAt( 0);
00756        
00757                             IMPORT_LOG0( "Assigning start of mailbox list to entry at index 0\n");
00758                      }
00759               }
00760               
00761               if (pBox == nsnull) {
00762                      IMPORT_LOG0( "ERROR ASSIGNING STARTING MAILBOX\n");
00763               }
00764               
00765        }
00766        
00767        nsresult                                         rv;
00768        nsIFileSpec *                             file;
00769        MailboxEntry *                                   pChild;
00770        nsIImportMailboxDescriptor *       pID;
00771        nsISupports *                             pInterface;
00772        PRUint32                                         size;
00773        
00774        nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
00775        if (NS_FAILED( rv))
00776               return;
00777        
00778        while (pBox) {
00779               rv = impSvc->CreateNewMailboxDescriptor( &pID);
00780               if (NS_SUCCEEDED( rv)) {
00781                      pID->SetDepth( depth);
00782                      pID->SetIdentifier( pBox->index);
00783                      pID->SetDisplayName( (PRUnichar *)pBox->mailName.get());
00784                      if (!pBox->fileName.IsEmpty()) {
00785                             pID->GetFileSpec( &file);
00786                             file->FromFileSpec( root);
00787                             file->AppendRelativeUnixPath( pBox->fileName.get());
00788                             size = 0;
00789                             file->GetFileSize( &size);
00790                             pID->SetSize( size);
00791                             file->Release();
00792                      }
00793                      rv = pID->QueryInterface( kISupportsIID, (void **) &pInterface);
00794                      pArray->AppendElement( pInterface);
00795                      pInterface->Release();
00796                      pID->Release();
00797               }
00798               
00799               if (pBox->child) {
00800                      pChild = GetIndexEntry( pBox->child);
00801                      if (pChild != nsnull)
00802                             BuildMailboxList( pChild, root, depth + 1, pArray);
00803               }
00804               if (pBox->sibling != -1) {
00805                      pBox = GetIndexEntry( pBox->sibling);
00806               }
00807               else
00808                      pBox = nsnull;
00809        }
00810        
00811 }
00812 
00813 
00814 
00815 nsOEScanBoxes::MailboxEntry * nsOEScanBoxes::GetIndexEntry( PRUint32 index)
00816 {
00817        PRInt32 max = m_entryArray.Count();
00818        for (PRInt32 i = 0; i < max; i++) {
00819               MailboxEntry *pEntry = (MailboxEntry *) m_entryArray.ElementAt( i);
00820               if (pEntry->index == index)
00821                      return( pEntry);
00822        }
00823 
00824        return( nsnull);
00825 }
00826 
00827 
00828 // -------------------------------------------------------
00829 // File utility routines
00830 // -------------------------------------------------------
00831 
00832 PRBool nsOEScanBoxes::ReadLong( nsIFileSpec * stream, PRInt32& val, PRUint32 offset)
00833 {
00834        nsresult      rv;
00835        rv = stream->Seek( offset);
00836        if (NS_FAILED( rv))
00837               return( PR_FALSE);
00838        
00839        PRInt32       cntRead;
00840        char * pReadTo = (char *)&val;
00841        rv = stream->Read( &pReadTo, sizeof( val), &cntRead);
00842        
00843        if (NS_FAILED( rv) || (cntRead != sizeof( val)))
00844               return( PR_FALSE);
00845        return( PR_TRUE);
00846 }
00847 
00848 PRBool nsOEScanBoxes::ReadLong( nsIFileSpec * stream, PRUint32& val, PRUint32 offset)
00849 {
00850        nsresult      rv;
00851        rv = stream->Seek( offset);
00852        if (NS_FAILED( rv))
00853               return( PR_FALSE);
00854        
00855        PRInt32       cntRead;
00856        char * pReadTo = (char *)&val;
00857        rv = stream->Read( &pReadTo, sizeof( val), &cntRead);
00858        
00859        if (NS_FAILED( rv) || (cntRead != sizeof( val)))
00860               return( PR_FALSE);
00861        return( PR_TRUE);
00862 }
00863 
00864 // It appears as though the strings for file name and mailbox
00865 // name are at least 254 chars - verified - they are probably 255
00866 // but why bother going that far!  If a file name is that long then 
00867 // the heck with it.
00868 #define       kOutlookExpressStringLength 252
00869 PRBool nsOEScanBoxes::ReadString( nsIFileSpec * stream, nsString& str, PRUint32 offset)
00870 {
00871        
00872        nsresult      rv;
00873        rv = stream->Seek( offset);
00874        if (NS_FAILED( rv))
00875               return( PR_FALSE);
00876               
00877 
00878        PRInt32       cntRead;
00879        char   buffer[kOutlookExpressStringLength];
00880        char * pReadTo = buffer;
00881        rv = stream->Read( &pReadTo, kOutlookExpressStringLength, &cntRead);
00882        
00883        if (NS_FAILED( rv) || (cntRead != kOutlookExpressStringLength))
00884               return( PR_FALSE);
00885        buffer[kOutlookExpressStringLength - 1] = 0;
00886        str.AssignWithConversion(buffer);
00887        return( PR_TRUE);
00888 }
00889 
00890 PRBool nsOEScanBoxes::ReadString( nsIFileSpec * stream, nsCString& str, PRUint32 offset)
00891 {
00892        
00893        nsresult      rv;
00894        rv = stream->Seek( offset);
00895        if (NS_FAILED( rv))
00896               return( PR_FALSE);
00897               
00898 
00899        PRInt32       cntRead;
00900        char   buffer[kOutlookExpressStringLength];
00901        char * pReadTo = buffer;
00902        rv = stream->Read( &pReadTo, kOutlookExpressStringLength, &cntRead);
00903        
00904        if (NS_FAILED( rv) || (cntRead != kOutlookExpressStringLength))
00905               return( PR_FALSE);
00906        buffer[kOutlookExpressStringLength - 1] = 0;
00907        str = buffer;
00908        return( PR_TRUE);
00909 }