Back to index

lightning-sunbird  0.9+nobinonly
nsEudoraAddress.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsCOMPtr.h"
00040 #include "nsEudoraAddress.h"
00041 
00042 #include "nsIAddrDatabase.h"
00043 #include "mdb.h"
00044 #include "nsAbBaseCID.h"
00045 #include "nsIAbCard.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsEudoraImport.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsMsgI18N.h"
00050 #include "nsNativeCharsetUtils.h"
00051 
00052 #include "EudoraDebugLog.h"
00053 
00054 #define       kWhitespace   " \t\b\r\n"
00055 
00056 #define ADD_FIELD_TO_DB_ROW(pdb, func, dbRow, val, uniStr)    \
00057   if (!val.IsEmpty())                                         \
00058   {                                                           \
00059         NS_CopyNativeToUnicode(val, uniStr);                  \
00060         pdb->func(dbRow, NS_ConvertUTF16toUTF8(uniStr).get());\
00061   }
00062 
00063 
00064 // If we get a line longer than 16K it's just toooooo bad!
00065 #define kEudoraAddressBufferSz     (16 * 1024)
00066 
00067 
00068 #ifdef IMPORT_DEBUG
00069 void DumpAliasArray( nsVoidArray& a);
00070 #endif
00071 
00072 class CAliasData {
00073 public:
00074        CAliasData() {}
00075        ~CAliasData() {}
00076        
00077        PRBool Process( const char *pLine, PRInt32 len);
00078        
00079 public:
00080        nsCString     m_nickName;
00081        nsCString     m_realName;
00082        nsCString     m_email;
00083 };
00084 
00085 class CAliasEntry {
00086 public:
00087        CAliasEntry( nsCString& name) { m_name = name;}
00088        ~CAliasEntry() { EmptyList();}
00089        
00090        void EmptyList( void) {
00091               CAliasData *pData;
00092               for (PRInt32 i = 0; i < m_list.Count(); i++) {
00093                      pData = (CAliasData *)m_list.ElementAt( i);
00094                      delete pData;
00095               }
00096               m_list.Clear();
00097        }
00098 
00099 public:
00100        nsCString     m_name;
00101        nsVoidArray   m_list;
00102        nsCString     m_notes;
00103 };
00104 
00105 nsEudoraAddress::nsEudoraAddress()
00106 {
00107 }
00108 
00109 nsEudoraAddress::~nsEudoraAddress()
00110 {
00111        EmptyAliases();
00112 }
00113 
00114 
00115 nsresult nsEudoraAddress::ImportAddresses( PRUint32 *pBytes, PRBool *pAbort, const PRUnichar *pName, nsIFileSpec *pSrc, nsIAddrDatabase *pDb, nsString& errors)
00116 {
00117        // Open the source file for reading, read each line and process it!
00118        
00119        EmptyAliases();
00120        
00121        nsresult rv = pSrc->OpenStreamForReading();
00122        if (NS_FAILED( rv)) {
00123               IMPORT_LOG0( "*** Error opening address file for reading\n");
00124               return( rv);
00125        }
00126        
00127        char *pLine = new char[kEudoraAddressBufferSz];
00128        PRBool wasTruncated;
00129        PRBool eof = PR_FALSE;
00130        rv = pSrc->Eof( &eof);
00131        if (NS_FAILED( rv)) {
00132               IMPORT_LOG0( "*** Error checking address file for eof\n");
00133               pSrc->CloseStream();
00134               return( rv);
00135        }
00136        
00137        while (!(*pAbort) && !eof && NS_SUCCEEDED( rv)) {
00138               wasTruncated = PR_FALSE;
00139               rv = pSrc->ReadLine( &pLine, kEudoraAddressBufferSz, &wasTruncated);
00140               if (wasTruncated)
00141                      pLine[kEudoraAddressBufferSz - 1] = 0;
00142               if (NS_SUCCEEDED( rv)) {
00143                      PRInt32       len = strlen( pLine);
00144                      ProcessLine( pLine, len, errors);
00145                      rv = pSrc->Eof( &eof);
00146                      if (pBytes)
00147                             *pBytes += (len / 2);
00148               }
00149        }
00150        
00151        rv = pSrc->CloseStream();
00152        
00153        delete [] pLine;
00154 
00155        if (!eof) {
00156               IMPORT_LOG0( "*** Error reading the address book, didn't reach the end\n");
00157               return( NS_ERROR_FAILURE);
00158        }
00159        
00160        // Run through the alias array and make address book entries...
00161        #ifdef IMPORT_DEBUG
00162        DumpAliasArray( m_alias);
00163        #endif
00164        
00165        BuildABCards( pBytes, pDb);
00166        
00167   rv = pDb->Commit(nsAddrDBCommitType::kLargeCommit);
00168        return rv;
00169 }
00170 
00171 
00172 PRInt32 nsEudoraAddress::CountWhiteSpace( const char *pLine, PRInt32 len)
00173 {
00174        PRInt32              cnt = 0;
00175        while (len && ((*pLine == ' ') || (*pLine == '\t'))) {
00176               len--;
00177               pLine++;
00178               cnt++;
00179        }
00180        
00181        return( cnt);
00182 }
00183 
00184 void nsEudoraAddress::EmptyAliases( void)
00185 {
00186        CAliasEntry *pData;
00187        for (PRInt32 i = 0; i < m_alias.Count(); i++) {
00188               pData = (CAliasEntry *)m_alias.ElementAt( i);
00189               delete pData;
00190        }
00191        m_alias.Clear();
00192 }
00193 
00194 void nsEudoraAddress::ProcessLine( const char *pLine, PRInt32 len, nsString& errors)
00195 {
00196        if (len < 6)
00197               return;
00198        
00199        PRInt32       cnt;
00200        CAliasEntry   *pEntry;
00201        
00202        if (!nsCRT::strncmp( pLine, "alias", 5)) {
00203               pLine += 5;
00204               len -= 5;
00205               cnt = CountWhiteSpace( pLine, len);
00206               if (cnt) {
00207                      pLine += cnt;
00208                      len -= cnt;
00209                      if ((pEntry = ProcessAlias( pLine, len, errors)) != nsnull) {
00210                             m_alias.AppendElement( pEntry);
00211                      }
00212               }
00213        }
00214        else if (!nsCRT::strncmp( pLine, "note", 4)) {
00215               pLine += 4;
00216               len -= 4;
00217               cnt = CountWhiteSpace( pLine, len);
00218               if (cnt) {
00219                      pLine += cnt;
00220                      len -= cnt;
00221                      ProcessNote( pLine, len, errors);
00222               }
00223        }
00224               
00225        // as far as I know everything must be on one line
00226        // if not, then I need to add a state variable.
00227 }
00228 
00229 PRInt32 nsEudoraAddress::GetAliasName( const char *pLine, PRInt32 len, nsCString& name)
00230 {
00231        name.Truncate();
00232        if (!len)
00233               return( 0);
00234        const char *pStart = pLine;
00235        char   end[2] = {' ', '\t'};
00236        if (*pLine == '"') {
00237               pLine++;
00238               pStart++;
00239               len--;
00240               end[0] = '"';
00241               end[1] = 0;
00242        }
00243        
00244        PRInt32 cnt = 0;
00245        while (len) {
00246               if ((*pLine == end[0]) || (*pLine == end[1]))
00247                      break;
00248               len--;
00249               pLine++;
00250               cnt++;
00251        }
00252        
00253        if (cnt)
00254               name.Append( pStart, cnt);
00255        
00256        if (end[0] == '"') {
00257               cnt++;
00258               if (len && (*pLine == '"')) {
00259                      cnt++;
00260                      pLine++;
00261                      len--;
00262               }
00263        }
00264        
00265        cnt += CountWhiteSpace( pLine, len);
00266        
00267        return( cnt);
00268 }
00269 
00270 
00271 CAliasEntry *nsEudoraAddress::ProcessAlias( const char *pLine, PRInt32 len, nsString& errors)
00272 {
00273        nsCString     name;
00274        PRInt32              cnt = GetAliasName( pLine, len, name);
00275        pLine += cnt;
00276        len -= cnt;
00277 
00278        // we have 3 known forms of addresses in Eudora
00279        // 1) real name <email@address>
00280        // 2) email@address
00281        // 3) <email@address>
00282        // 4) real name email@address
00283        // 5) <email@address> (Real name)
00284        
00285        CAliasEntry *pEntry = new CAliasEntry( name);
00286        if (!cnt || !len)
00287               return(pEntry);
00288        
00289        // Theoretically, an alias is just an RFC822 email adress, but it may contain
00290        // an alias to another alias as the email!  I general, it appears close
00291        // but unfortunately not exact so we can't use the nsIMsgHeaderParser to do
00292        // the work for us!
00293        
00294        // Very big bummer!
00295        
00296        const char *pStart;  
00297        PRInt32              tLen;
00298        nsCString     alias;
00299        
00300        while ( len) {
00301               pStart = pLine;
00302               cnt = 0;
00303               while (len && (*pLine != ',')) {
00304                      if (*pLine == '"') {
00305                             tLen = CountQuote( pLine, len);
00306                             pLine += tLen;
00307                             len -= tLen;
00308                             cnt += tLen;
00309                      }
00310                      else if (*pLine == '(') {
00311                             tLen = CountComment( pLine, len);
00312                             pLine += tLen;
00313                             len -= tLen;
00314                             cnt += tLen;
00315                      }
00316                      else if (*pLine == '<') {
00317                             tLen = CountAngle( pLine, len);
00318                             pLine += tLen;
00319                             len -= tLen;
00320                             cnt += tLen;
00321                      }
00322                      else {
00323                             cnt++;
00324                             pLine++;
00325                             len--;
00326                      }
00327               }
00328               if (cnt) {
00329                      CAliasData *pData = new CAliasData();
00330                      if (pData->Process( pStart, cnt)) {
00331                             pEntry->m_list.AppendElement( pData);
00332                      }
00333                      else
00334                             delete pData;
00335               }
00336               
00337               if (len && (*pLine == ',')) {
00338                      pLine++;
00339                      len--;
00340               }
00341        }
00342        
00343   // Always return the entry even if there's no other attribute associated with the contact.
00344   return( pEntry);   
00345 }
00346 
00347 
00348 void nsEudoraAddress::ProcessNote( const char *pLine, PRInt32 len, nsString& errors)
00349 {
00350        nsCString     name;
00351        PRInt32              cnt = GetAliasName( pLine, len, name);
00352        pLine += cnt;
00353        len -= cnt;
00354        if (!cnt || !len)
00355               return;
00356        
00357        // Find the alias for this note and store the note data there!
00358        CAliasEntry *pEntry = nsnull;
00359        PRInt32       idx = FindAlias( name);     
00360        if (idx == -1)
00361               return;
00362 
00363        pEntry = (CAliasEntry *) m_alias.ElementAt( idx);
00364        pEntry->m_notes.Append( pLine, len);
00365        pEntry->m_notes.Trim( kWhitespace);
00366 }
00367 
00368 
00369 
00370 PRInt32 nsEudoraAddress::CountQuote( const char *pLine, PRInt32 len)
00371 {
00372        if (!len)
00373               return( 0);
00374               
00375        PRInt32 cnt = 1;
00376        pLine++;
00377        len--;
00378        
00379        while (len && (*pLine != '"')) {
00380               cnt++;
00381               len--;
00382               pLine++;
00383        }
00384        
00385        if (len)
00386               cnt++;
00387        return( cnt);
00388 }
00389 
00390 
00391 PRInt32 nsEudoraAddress::CountAngle( const char *pLine, PRInt32 len)
00392 {
00393        if (!len)
00394               return( 0);
00395               
00396        PRInt32 cnt = 1;
00397        pLine++;
00398        len--;
00399        
00400        while (len && (*pLine != '>')) {
00401               cnt++;
00402               len--;
00403               pLine++;
00404        }
00405        
00406        if (len)
00407               cnt++;
00408        return( cnt);
00409 }
00410 
00411 PRInt32 nsEudoraAddress::CountComment( const char *pLine, PRInt32 len)
00412 {
00413        if (!len)
00414               return( 0);
00415        
00416        PRInt32       cCnt;
00417        PRInt32 cnt = 1;
00418        pLine++;
00419        len--;
00420        
00421        while (len && (*pLine != ')')) {
00422               if (*pLine == '(') {
00423                      cCnt = CountComment( pLine, len);  
00424                      cnt += cCnt;
00425                      pLine += cCnt;
00426                      len -= cCnt;
00427               }
00428               else {
00429                      cnt++;
00430                      len--;
00431                      pLine++;
00432               }
00433        }
00434        
00435        if (len)
00436               cnt++;
00437        return( cnt);
00438 }
00439 
00440 /*
00441        nsCString     m_nickName;
00442        nsCString     m_realName;
00443        nsCString     m_email;
00444 */
00445 
00446 PRBool CAliasData::Process( const char *pLine, PRInt32 len)
00447 {
00448        // Extract any comments first!
00449        nsCString     str;
00450        
00451        const char *pStart = pLine;
00452        PRInt32              tCnt = 0;
00453        PRInt32              cnt = 0;
00454        PRInt32              max = len;
00455        PRBool        endCollect = PR_FALSE;
00456        
00457        while (max) {
00458               if (*pLine == '"') {
00459                      if (tCnt && !endCollect) {
00460                             str.Trim( kWhitespace);
00461                             if (!str.IsEmpty())
00462                                    str.Append( " ", 1);
00463                             str.Append( pStart, tCnt);
00464                      }
00465                      cnt = nsEudoraAddress::CountQuote( pLine, max);
00466                      if ((cnt > 2) && m_realName.IsEmpty()) {
00467                             m_realName.Append( pLine + 1, cnt - 2);
00468                      }
00469                      pLine += cnt;
00470                      max -= cnt;
00471                      pStart = pLine;
00472                      tCnt = 0;
00473               }
00474               else if (*pLine == '<') {
00475                      if (tCnt && !endCollect) {
00476                             str.Trim( kWhitespace);
00477                             if (!str.IsEmpty())
00478                                    str.Append( " ", 1);
00479                             str.Append( pStart, tCnt);
00480                      }
00481                      cnt = nsEudoraAddress::CountAngle( pLine, max);
00482                      if ((cnt > 2) && m_email.IsEmpty()) {
00483                             m_email.Append( pLine + 1, cnt - 2);
00484                      }
00485                      pLine += cnt;
00486                      max -= cnt;
00487                      pStart = pLine;
00488                      tCnt = 0;
00489                      endCollect = PR_TRUE;
00490               }
00491               else if (*pLine == '(') {
00492                      if (tCnt && !endCollect) {
00493                             str.Trim( kWhitespace);
00494                             if (!str.IsEmpty())
00495                                    str.Append( " ", 1);
00496                             str.Append( pStart, tCnt);
00497                      }
00498                      cnt = nsEudoraAddress::CountComment( pLine, max);
00499                      if (cnt > 2) {
00500                             if (!m_realName.IsEmpty() && m_nickName.IsEmpty())
00501                                    m_nickName = m_realName;
00502                             m_realName.Truncate();
00503                             m_realName.Append( pLine + 1, cnt - 2);
00504                      }
00505                      pLine += cnt;
00506                      max -= cnt;
00507                      pStart = pLine;
00508                      tCnt = 0;
00509               }
00510               else {
00511                      tCnt++;
00512                      pLine++;
00513                      max--;
00514               }
00515        }
00516        
00517        if (tCnt) {
00518               str.Trim( kWhitespace);
00519               if (!str.IsEmpty())
00520                      str.Append( " ", 1);
00521               str.Append( pStart, tCnt);
00522        }
00523        
00524        str.Trim( kWhitespace);
00525        
00526        if (!m_realName.IsEmpty() && !m_email.IsEmpty())
00527               return( PR_TRUE);
00528        
00529        // now we should have a string with any remaining non-delimitted text
00530        // we assume that the last token is the email
00531        // anything before that is realName
00532        if (!m_email.IsEmpty()) {
00533               m_realName = str;
00534               return( PR_TRUE);
00535        }
00536        
00537        tCnt = str.RFindChar( ' ');
00538        if (tCnt == -1) {
00539               if (!str.IsEmpty()) {
00540                      m_email = str;
00541                      return( PR_TRUE);
00542               }
00543               return( PR_FALSE);
00544        }
00545        
00546        str.Right( m_email, str.Length() - tCnt - 1);
00547        str.Left( m_realName, tCnt);
00548        m_realName.Trim( kWhitespace);
00549        m_email.Trim( kWhitespace);
00550        
00551        return( !m_email.IsEmpty());
00552 }
00553 
00554 #ifdef IMPORT_DEBUG
00555 void DumpAliasArray( nsVoidArray& a)
00556 {
00557        CAliasEntry *pEntry;
00558        CAliasData *pData;
00559        
00560        PRInt32 cnt = a.Count();
00561        IMPORT_LOG1( "Alias list size: %ld\n", cnt);
00562        for (PRInt32 i = 0; i < cnt; i++) {
00563               pEntry = (CAliasEntry *)a.ElementAt( i);
00564               IMPORT_LOG1( "\tAlias: %s\n", pEntry->m_name.get());
00565     if (pEntry->m_list.Count() > 1) {
00566                      IMPORT_LOG1( "\tList count #%ld\n", pEntry->m_list.Count());
00567                      for (PRInt32 j = 0; j < pEntry->m_list.Count(); j++) {
00568                             pData = (CAliasData *) pEntry->m_list.ElementAt( j);
00569                             IMPORT_LOG0( "\t\t--------\n");
00570                             IMPORT_LOG1( "\t\temail: %s\n", pData->m_email.get());
00571                             IMPORT_LOG1( "\t\trealName: %s\n", pData->m_realName.get());
00572                             IMPORT_LOG1( "\t\tnickName: %s\n", pData->m_nickName.get());
00573                      }
00574               }
00575               else if (pEntry->m_list.Count()) {
00576                      pData = (CAliasData *) pEntry->m_list.ElementAt( 0);
00577                      IMPORT_LOG1( "\t\temail: %s\n", pData->m_email.get());
00578                      IMPORT_LOG1( "\t\trealName: %s\n", pData->m_realName.get());
00579                      IMPORT_LOG1( "\t\tnickName: %s\n", pData->m_nickName.get());
00580               }      
00581        }
00582 }
00583 #endif
00584 
00585 CAliasEntry *nsEudoraAddress::ResolveAlias( nsCString& name)
00586 {
00587        PRInt32       max = m_alias.Count();
00588        CAliasEntry *pEntry;
00589        for (PRInt32 i = 0; i < max; i++) {
00590               pEntry = (CAliasEntry *) m_alias.ElementAt( i);
00591               if (name.Equals( pEntry->m_name, nsCaseInsensitiveCStringComparator()))
00592                      return( pEntry);
00593        }
00594        
00595        return( nsnull);
00596 }
00597 
00598 void nsEudoraAddress::ResolveEntries( nsCString& name, nsVoidArray& list, nsVoidArray& result)
00599 {
00600        /* a safe-guard against recursive entries */
00601        if (result.Count() > m_alias.Count())
00602               return;
00603               
00604        PRInt32                     max = list.Count();
00605        PRInt32                     i;
00606        CAliasData *  pData;
00607        CAliasEntry * pEntry;
00608        for (i = 0; i < max; i++) {
00609               pData = (CAliasData *)list.ElementAt( i);
00610               // resolve the email to an existing alias!
00611               if (!name.Equals( pData->m_email,
00612                           nsCaseInsensitiveCStringComparator()) &&
00613             ((pEntry = ResolveAlias( pData->m_email)) != nsnull)) {
00614                      // This new entry has all of the entries for this puppie.
00615                      // Resolve all of it's entries!
00616                      ResolveEntries( pEntry->m_name, pEntry->m_list, result);
00617               }
00618               else {
00619                      result.AppendElement( pData);
00620               }
00621        }
00622 }
00623 
00624 PRInt32 nsEudoraAddress::FindAlias( nsCString& name)
00625 {
00626        CAliasEntry * pEntry;
00627        PRInt32                     max = m_alias.Count();
00628        PRInt32                     i;
00629        
00630        // First off, run through the list and build person cards - groups/lists have to be done later
00631        for (i = 0; i < max; i++) {
00632               pEntry = (CAliasEntry *) m_alias.ElementAt( i);
00633               if (pEntry->m_name == name)
00634                      return( i);
00635        }
00636 
00637        return( -1);
00638 }
00639 
00640 void nsEudoraAddress::BuildABCards( PRUint32 *pBytes, nsIAddrDatabase *pDb)
00641 {
00642        CAliasEntry * pEntry;
00643        PRInt32                     max = m_alias.Count();
00644        PRInt32                     i;
00645        nsVoidArray          emailList;
00646   nsVoidArray membersArray;// Remember group members.
00647   nsVoidArray groupsArray; // Remember groups.
00648        
00649        // First off, run through the list and build person cards - groups/lists have to be done later
00650        for (i = 0; i < max; i++) {
00651               pEntry = (CAliasEntry *) m_alias.ElementAt( i);
00652               ResolveEntries( pEntry->m_name, pEntry->m_list, emailList);           
00653     if (emailList.Count() > 1)
00654     {
00655       // Remember group members uniquely and add them to db later.
00656       RememberGroupMembers(membersArray, emailList);
00657       // Remember groups and add them to db later.
00658       groupsArray.AppendElement(pEntry);
00659     }
00660     else
00661       AddSingleCard( pEntry, emailList, pDb);
00662 
00663               emailList.Clear();
00664 
00665               if (pBytes) {
00666                      // This isn't exact but it will get us close enough
00667                      *pBytes += (pEntry->m_name.Length() + pEntry->m_notes.Length() + 10);
00668               }
00669        }
00670 
00671   // Make sure group members exists before adding groups.
00672   nsresult rv = AddGroupMembersAsCards(membersArray, pDb);
00673   if (NS_FAILED(rv))
00674     return;
00675 
00676   // Now add the lists/groups (now that all cards have been added).
00677   max = groupsArray.Count();
00678   for (i = 0; i < max; i++)
00679   {
00680     pEntry = (CAliasEntry *) groupsArray.ElementAt(i);
00681     ResolveEntries( pEntry->m_name, pEntry->m_list, emailList);
00682     AddSingleList(pEntry, emailList, pDb);
00683     emailList.Clear();
00684   }
00685 }
00686 
00687 void nsEudoraAddress::ExtractNoteField( nsCString& note, nsCString& value, const char *pFieldName)
00688 {
00689        value.Truncate( 0);
00690        nsCString     field("<");
00691        field.Append( pFieldName);
00692        field.Append( ':');
00693 
00694        /* 
00695               this is a bit of a cheat, but there's no reason it won't work
00696               fine for us, even better than Eudora in some cases!
00697         */
00698        
00699        PRInt32 idx = note.Find( field);
00700        if (idx != -1) {
00701               idx += field.Length();
00702               PRInt32 endIdx = note.FindChar( '>', idx);
00703               if (endIdx == -1)
00704                      endIdx = note.Length() - 1;
00705               note.Mid( value, idx, endIdx - idx);
00706               idx -= field.Length();
00707               nsCString tempL;
00708               if (idx)
00709                      note.Left( tempL, idx);
00710               nsCString tempR;
00711               note.Right( tempR, note.Length() - endIdx - 1);
00712               note = tempL;
00713               note.Append( tempR);
00714        }
00715 }
00716 
00717 void nsEudoraAddress::SanitizeValue( nsCString& val)
00718 {
00719        val.ReplaceSubstring( "\x0D\x0A", ", ");
00720        val.ReplaceChar( 13, ',');
00721        val.ReplaceChar( 10, ',');
00722 }
00723 
00724 void nsEudoraAddress::SplitString( nsCString& val1, nsCString& val2)
00725 {
00726        nsCString     temp;
00727 
00728        // Find the last line if there is more than one!
00729        PRInt32 idx = val1.RFind( "\x0D\x0A");
00730        PRInt32       cnt = 2;
00731        if (idx == -1) {
00732               cnt = 1;
00733               idx = val1.RFindChar( 13);
00734        }
00735        if (idx == -1)
00736               idx= val1.RFindChar( 10);
00737        if (idx != -1) {
00738               val1.Right( val2, val1.Length() - idx - cnt);
00739               val1.Left( temp, idx);
00740               val1 = temp;
00741               SanitizeValue( val1);
00742        }
00743 }
00744 
00745 void nsEudoraAddress::AddSingleCard( CAliasEntry *pEntry, nsVoidArray &emailList, nsIAddrDatabase *pDb)
00746 {
00747   // We always have a nickname and everything else is optional.
00748   // Map both home and work related fiedls to our address card. Eudora
00749   // fields that can't be mapped will be left in the 'note' field!
00750        nsIMdbRow* newRow = nsnull;
00751        pDb->GetNewRow( &newRow); 
00752   if (!newRow)
00753     return;
00754 
00755        nsCString     displayName, name, firstName, lastName;
00756        nsCString     fax, phone, mobile, webLink;
00757        nsCString     address, address2, city, state, zip, country;
00758        nsCString     phoneWK, webLinkWK, title, company;
00759   nsCString   addressWK, address2WK, cityWK, stateWK, zipWK, countryWK;
00760        nsCString     note(pEntry->m_notes);
00761 
00762        if (!note.IsEmpty())
00763   {
00764               ExtractNoteField( note, fax, "fax");
00765               ExtractNoteField( note, phone, "phone");
00766     ExtractNoteField( note, mobile, "mobile");
00767               ExtractNoteField( note, address, "address");
00768     ExtractNoteField( note, city, "city");
00769     ExtractNoteField( note, state, "state");
00770     ExtractNoteField( note, zip, "zip");
00771     ExtractNoteField( note, country, "country");
00772               ExtractNoteField( note, name, "name");
00773     ExtractNoteField( note, firstName, "first");
00774     ExtractNoteField( note, lastName, "last");
00775     ExtractNoteField( note, webLink, "web");
00776 
00777     ExtractNoteField( note, addressWK, "address2");
00778     ExtractNoteField( note, cityWK, "city2");
00779     ExtractNoteField( note, stateWK, "state2");
00780     ExtractNoteField( note, zipWK, "zip2");
00781     ExtractNoteField( note, countryWK, "country2");
00782               ExtractNoteField( note, phoneWK, "phone2");
00783     ExtractNoteField( note, title, "title");
00784     ExtractNoteField( note, company, "company");
00785     ExtractNoteField( note, webLinkWK, "web2");
00786        }
00787 
00788   CAliasData *pData = emailList.Count() ? (CAliasData *)emailList.ElementAt(0) : nsnull;
00789 
00790   if (pData && !pData->m_realName.IsEmpty())
00791     displayName = pData->m_realName;
00792        else if (!name.IsEmpty())
00793               displayName = name;
00794        else
00795               displayName = pEntry->m_name;
00796        
00797        address.ReplaceSubstring( "\x03", "\x0D\x0A");
00798        SplitString( address, address2);
00799        note.ReplaceSubstring( "\x03", "\x0D\x0A");
00800        fax.ReplaceSubstring( "\x03", " ");
00801        phone.ReplaceSubstring( "\x03", " ");
00802        name.ReplaceSubstring( "\x03", " ");
00803   city.ReplaceSubstring( "\x03", " ");
00804        state.ReplaceSubstring( "\x03", " ");
00805   zip.ReplaceSubstring( "\x03", " ");
00806   country.ReplaceSubstring( "\x03", " ");
00807 
00808   addressWK.ReplaceSubstring( "\x03", "\x0D\x0A");
00809   SplitString( addressWK, address2WK);
00810        phoneWK.ReplaceSubstring( "\x03", " ");
00811   cityWK.ReplaceSubstring( "\x03", " ");
00812        stateWK.ReplaceSubstring( "\x03", " ");
00813   zipWK.ReplaceSubstring( "\x03", " ");
00814   countryWK.ReplaceSubstring( "\x03", " ");
00815   title.ReplaceSubstring( "\x03", " ");
00816   company.ReplaceSubstring( "\x03", " ");
00817        
00818        if (newRow)
00819   {
00820               nsAutoString uniStr;
00821 
00822     // Home related fields.
00823     ADD_FIELD_TO_DB_ROW(pDb, AddDisplayName, newRow, displayName, uniStr);
00824     ADD_FIELD_TO_DB_ROW(pDb, AddNickName, newRow, pEntry->m_name, uniStr);
00825     if (pData)
00826       ADD_FIELD_TO_DB_ROW(pDb, AddPrimaryEmail, newRow, pData->m_email, uniStr);
00827     ADD_FIELD_TO_DB_ROW(pDb, AddFirstName, newRow, firstName, uniStr);
00828     ADD_FIELD_TO_DB_ROW(pDb, AddLastName, newRow, lastName, uniStr);
00829     ADD_FIELD_TO_DB_ROW(pDb, AddWebPage2, newRow, webLink, uniStr);
00830     ADD_FIELD_TO_DB_ROW(pDb, AddFaxNumber, newRow, fax, uniStr);
00831     ADD_FIELD_TO_DB_ROW(pDb, AddHomePhone, newRow, phone, uniStr);
00832     ADD_FIELD_TO_DB_ROW(pDb, AddHomeAddress, newRow, address, uniStr);
00833     ADD_FIELD_TO_DB_ROW(pDb, AddHomeAddress2, newRow, address2, uniStr);
00834     ADD_FIELD_TO_DB_ROW(pDb, AddHomeCity, newRow, city, uniStr);
00835     ADD_FIELD_TO_DB_ROW(pDb, AddHomeZipCode, newRow, zip, uniStr);
00836     ADD_FIELD_TO_DB_ROW(pDb, AddHomeState, newRow, state, uniStr);
00837     ADD_FIELD_TO_DB_ROW(pDb, AddHomeCountry, newRow, country, uniStr);
00838     ADD_FIELD_TO_DB_ROW(pDb, AddCellularNumber, newRow, mobile, uniStr);
00839 
00840     // Work related fields.
00841     ADD_FIELD_TO_DB_ROW(pDb, AddJobTitle, newRow, title, uniStr);
00842     ADD_FIELD_TO_DB_ROW(pDb, AddCompany, newRow, company, uniStr);
00843     ADD_FIELD_TO_DB_ROW(pDb, AddWebPage1, newRow, webLinkWK, uniStr);
00844     ADD_FIELD_TO_DB_ROW(pDb, AddWorkPhone, newRow, phoneWK, uniStr);
00845     ADD_FIELD_TO_DB_ROW(pDb, AddWorkAddress, newRow, addressWK, uniStr);
00846     ADD_FIELD_TO_DB_ROW(pDb, AddWorkAddress2, newRow, address2WK, uniStr);
00847     ADD_FIELD_TO_DB_ROW(pDb, AddWorkCity, newRow, cityWK, uniStr);
00848     ADD_FIELD_TO_DB_ROW(pDb, AddWorkZipCode, newRow, zipWK, uniStr);
00849     ADD_FIELD_TO_DB_ROW(pDb, AddWorkState, newRow, stateWK, uniStr);
00850     ADD_FIELD_TO_DB_ROW(pDb, AddWorkCountry, newRow, countryWK, uniStr);
00851 
00852     // Lastly, note field.
00853     ADD_FIELD_TO_DB_ROW(pDb, AddNotes, newRow, note, uniStr);
00854 
00855               pDb->AddCardRowToDB( newRow);
00856 
00857               IMPORT_LOG1( "Added card to db: %s\n", displayName.get());
00858        }             
00859 }
00860 
00861 //
00862 // Since there is no way to check if a card for a given email address already exists,
00863 // elements in 'membersArray' are make unique. So for each email address in 'emailList'
00864 // we check it in 'membersArray' and if it's not there then we add it to 'membersArray'.
00865 //
00866 void nsEudoraAddress::RememberGroupMembers(nsVoidArray &membersArray, nsVoidArray &emailList)
00867 {
00868   PRInt32 cnt = emailList.Count();
00869   CAliasData *pData;
00870 
00871   for (PRInt32 i = 0; i < cnt; i++)
00872   {
00873     pData = (CAliasData *)emailList.ElementAt(i);
00874     if (!pData)
00875       continue;
00876 
00877     PRInt32 memberCnt = membersArray.Count();
00878     PRInt32 j = 0;
00879     for (j = 0; j < memberCnt; j++)
00880     {
00881       if (pData == membersArray.ElementAt(j))
00882         break;
00883     }
00884     if (j >= memberCnt)
00885       membersArray.AppendElement(pData); // add to member list
00886   }
00887 }
00888 
00889 nsresult nsEudoraAddress::AddGroupMembersAsCards(nsVoidArray &membersArray, nsIAddrDatabase *pDb)
00890 {
00891   PRInt32 max = membersArray.Count();
00892   CAliasData *pData;
00893   nsresult rv = NS_OK;
00894   nsCOMPtr <nsIMdbRow> newRow;
00895   nsAutoString uniStr;
00896   nsCAutoString      displayName;
00897 
00898   for (PRInt32 i = 0; i < max; i++)
00899   {
00900     pData = (CAliasData *)membersArray.ElementAt(i);
00901 
00902     if (!pData || (pData->m_email.IsEmpty()))
00903       continue;
00904 
00905     rv = pDb->GetNewRow(getter_AddRefs(newRow)); 
00906     if (NS_FAILED(rv) || !newRow)
00907       return rv;
00908 
00909     if (!pData->m_realName.IsEmpty())
00910       displayName = pData->m_realName;
00911     else if (!pData->m_nickName.IsEmpty())
00912       displayName = pData->m_nickName;
00913     else
00914       displayName.Truncate();
00915 
00916     ADD_FIELD_TO_DB_ROW(pDb, AddDisplayName, newRow, displayName, uniStr);
00917     ADD_FIELD_TO_DB_ROW(pDb, AddPrimaryEmail, newRow, pData->m_email, uniStr);
00918     rv = pDb->AddCardRowToDB( newRow);
00919     NS_ENSURE_SUCCESS(rv, rv);
00920   }
00921   return rv;
00922 }
00923 
00924 nsresult nsEudoraAddress::AddSingleList(CAliasEntry *pEntry, nsVoidArray &emailList, nsIAddrDatabase *pDb)
00925 {
00926   // Create a list.
00927   nsCOMPtr <nsIMdbRow> newRow;
00928   nsresult rv = pDb->GetNewListRow(getter_AddRefs(newRow)); 
00929   if (NS_FAILED(rv) || !newRow)
00930       return rv;
00931 
00932   rv = pDb->AddListName(newRow, pEntry->m_name.get());
00933   NS_ENSURE_SUCCESS(rv, rv);
00934 
00935   // Now add the members.
00936   PRInt32 max = emailList.Count();
00937   for (PRInt32 i = 0; i < max; i++)
00938   {
00939     CAliasData *pData = (CAliasData *)emailList.ElementAt(i);
00940     nsCAutoString ldifValue(NS_LITERAL_CSTRING("mail=") + nsDependentCString(pData->m_email.get()));
00941     rv = pDb->AddLdifListMember(newRow, ldifValue.get());
00942   }
00943 
00944   rv = pDb->AddCardRowToDB(newRow);
00945   NS_ENSURE_SUCCESS(rv, rv);
00946 
00947   rv = pDb->AddListDirNode(newRow);
00948   return rv;
00949 }
00950