/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org Code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsEudoraAddress.h" #include "nsIAddrDatabase.h" #include "mdb.h" #include "nsAbBaseCID.h" #include "nsIAbCard.h" #include "nsIServiceManager.h" #include "nsEudoraImport.h" #include "nsReadableUtils.h" #include "nsMsgI18N.h" #include "nsNativeCharsetUtils.h" #include "EudoraDebugLog.h" #define kWhitespace " \t\b\r\n" #define ADD_FIELD_TO_DB_ROW(pdb, func, dbRow, val, uniStr) \ if (!val.IsEmpty()) \ { \ NS_CopyNativeToUnicode(val, uniStr); \ pdb->func(dbRow, NS_ConvertUTF16toUTF8(uniStr).get());\ } // If we get a line longer than 16K it's just toooooo bad! #define kEudoraAddressBufferSz (16 * 1024) #ifdef IMPORT_DEBUG void DumpAliasArray( nsVoidArray& a); #endif class CAliasData { public: CAliasData() {} ~CAliasData() {} PRBool Process( const char *pLine, PRInt32 len); public: nsCString m_nickName; nsCString m_realName; nsCString m_email; }; class CAliasEntry { public: CAliasEntry( nsCString& name) { m_name = name;} ~CAliasEntry() { EmptyList();} void EmptyList( void) { CAliasData *pData; for (PRInt32 i = 0; i < m_list.Count(); i++) { pData = (CAliasData *)m_list.ElementAt( i); delete pData; } m_list.Clear(); } public: nsCString m_name; nsVoidArray m_list; nsCString m_notes; }; nsEudoraAddress::nsEudoraAddress() { } nsEudoraAddress::~nsEudoraAddress() { EmptyAliases(); } nsresult nsEudoraAddress::ImportAddresses( PRUint32 *pBytes, PRBool *pAbort, const PRUnichar *pName, nsIFileSpec *pSrc, nsIAddrDatabase *pDb, nsString& errors) { // Open the source file for reading, read each line and process it! EmptyAliases(); nsresult rv = pSrc->OpenStreamForReading(); if (NS_FAILED( rv)) { IMPORT_LOG0( "*** Error opening address file for reading\n"); return( rv); } char *pLine = new char[kEudoraAddressBufferSz]; PRBool wasTruncated; PRBool eof = PR_FALSE; rv = pSrc->Eof( &eof); if (NS_FAILED( rv)) { IMPORT_LOG0( "*** Error checking address file for eof\n"); pSrc->CloseStream(); return( rv); } while (!(*pAbort) && !eof && NS_SUCCEEDED( rv)) { wasTruncated = PR_FALSE; rv = pSrc->ReadLine( &pLine, kEudoraAddressBufferSz, &wasTruncated); if (wasTruncated) pLine[kEudoraAddressBufferSz - 1] = 0; if (NS_SUCCEEDED( rv)) { PRInt32 len = strlen( pLine); ProcessLine( pLine, len, errors); rv = pSrc->Eof( &eof); if (pBytes) *pBytes += (len / 2); } } rv = pSrc->CloseStream(); delete [] pLine; if (!eof) { IMPORT_LOG0( "*** Error reading the address book, didn't reach the end\n"); return( NS_ERROR_FAILURE); } // Run through the alias array and make address book entries... #ifdef IMPORT_DEBUG DumpAliasArray( m_alias); #endif BuildABCards( pBytes, pDb); rv = pDb->Commit(nsAddrDBCommitType::kLargeCommit); return rv; } PRInt32 nsEudoraAddress::CountWhiteSpace( const char *pLine, PRInt32 len) { PRInt32 cnt = 0; while (len && ((*pLine == ' ') || (*pLine == '\t'))) { len--; pLine++; cnt++; } return( cnt); } void nsEudoraAddress::EmptyAliases( void) { CAliasEntry *pData; for (PRInt32 i = 0; i < m_alias.Count(); i++) { pData = (CAliasEntry *)m_alias.ElementAt( i); delete pData; } m_alias.Clear(); } void nsEudoraAddress::ProcessLine( const char *pLine, PRInt32 len, nsString& errors) { if (len < 6) return; PRInt32 cnt; CAliasEntry *pEntry; if (!nsCRT::strncmp( pLine, "alias", 5)) { pLine += 5; len -= 5; cnt = CountWhiteSpace( pLine, len); if (cnt) { pLine += cnt; len -= cnt; if ((pEntry = ProcessAlias( pLine, len, errors)) != nsnull) { m_alias.AppendElement( pEntry); } } } else if (!nsCRT::strncmp( pLine, "note", 4)) { pLine += 4; len -= 4; cnt = CountWhiteSpace( pLine, len); if (cnt) { pLine += cnt; len -= cnt; ProcessNote( pLine, len, errors); } } // as far as I know everything must be on one line // if not, then I need to add a state variable. } PRInt32 nsEudoraAddress::GetAliasName( const char *pLine, PRInt32 len, nsCString& name) { name.Truncate(); if (!len) return( 0); const char *pStart = pLine; char end[2] = {' ', '\t'}; if (*pLine == '"') { pLine++; pStart++; len--; end[0] = '"'; end[1] = 0; } PRInt32 cnt = 0; while (len) { if ((*pLine == end[0]) || (*pLine == end[1])) break; len--; pLine++; cnt++; } if (cnt) name.Append( pStart, cnt); if (end[0] == '"') { cnt++; if (len && (*pLine == '"')) { cnt++; pLine++; len--; } } cnt += CountWhiteSpace( pLine, len); return( cnt); } CAliasEntry *nsEudoraAddress::ProcessAlias( const char *pLine, PRInt32 len, nsString& errors) { nsCString name; PRInt32 cnt = GetAliasName( pLine, len, name); pLine += cnt; len -= cnt; // we have 3 known forms of addresses in Eudora // 1) real name // 2) email@address // 3) // 4) real name email@address // 5) (Real name) CAliasEntry *pEntry = new CAliasEntry( name); if (!cnt || !len) return(pEntry); // Theoretically, an alias is just an RFC822 email adress, but it may contain // an alias to another alias as the email! I general, it appears close // but unfortunately not exact so we can't use the nsIMsgHeaderParser to do // the work for us! // Very big bummer! const char *pStart; PRInt32 tLen; nsCString alias; while ( len) { pStart = pLine; cnt = 0; while (len && (*pLine != ',')) { if (*pLine == '"') { tLen = CountQuote( pLine, len); pLine += tLen; len -= tLen; cnt += tLen; } else if (*pLine == '(') { tLen = CountComment( pLine, len); pLine += tLen; len -= tLen; cnt += tLen; } else if (*pLine == '<') { tLen = CountAngle( pLine, len); pLine += tLen; len -= tLen; cnt += tLen; } else { cnt++; pLine++; len--; } } if (cnt) { CAliasData *pData = new CAliasData(); if (pData->Process( pStart, cnt)) { pEntry->m_list.AppendElement( pData); } else delete pData; } if (len && (*pLine == ',')) { pLine++; len--; } } // Always return the entry even if there's no other attribute associated with the contact. return( pEntry); } void nsEudoraAddress::ProcessNote( const char *pLine, PRInt32 len, nsString& errors) { nsCString name; PRInt32 cnt = GetAliasName( pLine, len, name); pLine += cnt; len -= cnt; if (!cnt || !len) return; // Find the alias for this note and store the note data there! CAliasEntry *pEntry = nsnull; PRInt32 idx = FindAlias( name); if (idx == -1) return; pEntry = (CAliasEntry *) m_alias.ElementAt( idx); pEntry->m_notes.Append( pLine, len); pEntry->m_notes.Trim( kWhitespace); } PRInt32 nsEudoraAddress::CountQuote( const char *pLine, PRInt32 len) { if (!len) return( 0); PRInt32 cnt = 1; pLine++; len--; while (len && (*pLine != '"')) { cnt++; len--; pLine++; } if (len) cnt++; return( cnt); } PRInt32 nsEudoraAddress::CountAngle( const char *pLine, PRInt32 len) { if (!len) return( 0); PRInt32 cnt = 1; pLine++; len--; while (len && (*pLine != '>')) { cnt++; len--; pLine++; } if (len) cnt++; return( cnt); } PRInt32 nsEudoraAddress::CountComment( const char *pLine, PRInt32 len) { if (!len) return( 0); PRInt32 cCnt; PRInt32 cnt = 1; pLine++; len--; while (len && (*pLine != ')')) { if (*pLine == '(') { cCnt = CountComment( pLine, len); cnt += cCnt; pLine += cCnt; len -= cCnt; } else { cnt++; len--; pLine++; } } if (len) cnt++; return( cnt); } /* nsCString m_nickName; nsCString m_realName; nsCString m_email; */ PRBool CAliasData::Process( const char *pLine, PRInt32 len) { // Extract any comments first! nsCString str; const char *pStart = pLine; PRInt32 tCnt = 0; PRInt32 cnt = 0; PRInt32 max = len; PRBool endCollect = PR_FALSE; while (max) { if (*pLine == '"') { if (tCnt && !endCollect) { str.Trim( kWhitespace); if (!str.IsEmpty()) str.Append( " ", 1); str.Append( pStart, tCnt); } cnt = nsEudoraAddress::CountQuote( pLine, max); if ((cnt > 2) && m_realName.IsEmpty()) { m_realName.Append( pLine + 1, cnt - 2); } pLine += cnt; max -= cnt; pStart = pLine; tCnt = 0; } else if (*pLine == '<') { if (tCnt && !endCollect) { str.Trim( kWhitespace); if (!str.IsEmpty()) str.Append( " ", 1); str.Append( pStart, tCnt); } cnt = nsEudoraAddress::CountAngle( pLine, max); if ((cnt > 2) && m_email.IsEmpty()) { m_email.Append( pLine + 1, cnt - 2); } pLine += cnt; max -= cnt; pStart = pLine; tCnt = 0; endCollect = PR_TRUE; } else if (*pLine == '(') { if (tCnt && !endCollect) { str.Trim( kWhitespace); if (!str.IsEmpty()) str.Append( " ", 1); str.Append( pStart, tCnt); } cnt = nsEudoraAddress::CountComment( pLine, max); if (cnt > 2) { if (!m_realName.IsEmpty() && m_nickName.IsEmpty()) m_nickName = m_realName; m_realName.Truncate(); m_realName.Append( pLine + 1, cnt - 2); } pLine += cnt; max -= cnt; pStart = pLine; tCnt = 0; } else { tCnt++; pLine++; max--; } } if (tCnt) { str.Trim( kWhitespace); if (!str.IsEmpty()) str.Append( " ", 1); str.Append( pStart, tCnt); } str.Trim( kWhitespace); if (!m_realName.IsEmpty() && !m_email.IsEmpty()) return( PR_TRUE); // now we should have a string with any remaining non-delimitted text // we assume that the last token is the email // anything before that is realName if (!m_email.IsEmpty()) { m_realName = str; return( PR_TRUE); } tCnt = str.RFindChar( ' '); if (tCnt == -1) { if (!str.IsEmpty()) { m_email = str; return( PR_TRUE); } return( PR_FALSE); } str.Right( m_email, str.Length() - tCnt - 1); str.Left( m_realName, tCnt); m_realName.Trim( kWhitespace); m_email.Trim( kWhitespace); return( !m_email.IsEmpty()); } #ifdef IMPORT_DEBUG void DumpAliasArray( nsVoidArray& a) { CAliasEntry *pEntry; CAliasData *pData; PRInt32 cnt = a.Count(); IMPORT_LOG1( "Alias list size: %ld\n", cnt); for (PRInt32 i = 0; i < cnt; i++) { pEntry = (CAliasEntry *)a.ElementAt( i); IMPORT_LOG1( "\tAlias: %s\n", pEntry->m_name.get()); if (pEntry->m_list.Count() > 1) { IMPORT_LOG1( "\tList count #%ld\n", pEntry->m_list.Count()); for (PRInt32 j = 0; j < pEntry->m_list.Count(); j++) { pData = (CAliasData *) pEntry->m_list.ElementAt( j); IMPORT_LOG0( "\t\t--------\n"); IMPORT_LOG1( "\t\temail: %s\n", pData->m_email.get()); IMPORT_LOG1( "\t\trealName: %s\n", pData->m_realName.get()); IMPORT_LOG1( "\t\tnickName: %s\n", pData->m_nickName.get()); } } else if (pEntry->m_list.Count()) { pData = (CAliasData *) pEntry->m_list.ElementAt( 0); IMPORT_LOG1( "\t\temail: %s\n", pData->m_email.get()); IMPORT_LOG1( "\t\trealName: %s\n", pData->m_realName.get()); IMPORT_LOG1( "\t\tnickName: %s\n", pData->m_nickName.get()); } } } #endif CAliasEntry *nsEudoraAddress::ResolveAlias( nsCString& name) { PRInt32 max = m_alias.Count(); CAliasEntry *pEntry; for (PRInt32 i = 0; i < max; i++) { pEntry = (CAliasEntry *) m_alias.ElementAt( i); if (name.Equals( pEntry->m_name, nsCaseInsensitiveCStringComparator())) return( pEntry); } return( nsnull); } void nsEudoraAddress::ResolveEntries( nsCString& name, nsVoidArray& list, nsVoidArray& result) { /* a safe-guard against recursive entries */ if (result.Count() > m_alias.Count()) return; PRInt32 max = list.Count(); PRInt32 i; CAliasData * pData; CAliasEntry * pEntry; for (i = 0; i < max; i++) { pData = (CAliasData *)list.ElementAt( i); // resolve the email to an existing alias! if (!name.Equals( pData->m_email, nsCaseInsensitiveCStringComparator()) && ((pEntry = ResolveAlias( pData->m_email)) != nsnull)) { // This new entry has all of the entries for this puppie. // Resolve all of it's entries! ResolveEntries( pEntry->m_name, pEntry->m_list, result); } else { result.AppendElement( pData); } } } PRInt32 nsEudoraAddress::FindAlias( nsCString& name) { CAliasEntry * pEntry; PRInt32 max = m_alias.Count(); PRInt32 i; // First off, run through the list and build person cards - groups/lists have to be done later for (i = 0; i < max; i++) { pEntry = (CAliasEntry *) m_alias.ElementAt( i); if (pEntry->m_name == name) return( i); } return( -1); } void nsEudoraAddress::BuildABCards( PRUint32 *pBytes, nsIAddrDatabase *pDb) { CAliasEntry * pEntry; PRInt32 max = m_alias.Count(); PRInt32 i; nsVoidArray emailList; nsVoidArray membersArray;// Remember group members. nsVoidArray groupsArray; // Remember groups. // First off, run through the list and build person cards - groups/lists have to be done later for (i = 0; i < max; i++) { pEntry = (CAliasEntry *) m_alias.ElementAt( i); ResolveEntries( pEntry->m_name, pEntry->m_list, emailList); if (emailList.Count() > 1) { // Remember group members uniquely and add them to db later. RememberGroupMembers(membersArray, emailList); // Remember groups and add them to db later. groupsArray.AppendElement(pEntry); } else AddSingleCard( pEntry, emailList, pDb); emailList.Clear(); if (pBytes) { // This isn't exact but it will get us close enough *pBytes += (pEntry->m_name.Length() + pEntry->m_notes.Length() + 10); } } // Make sure group members exists before adding groups. nsresult rv = AddGroupMembersAsCards(membersArray, pDb); if (NS_FAILED(rv)) return; // Now add the lists/groups (now that all cards have been added). max = groupsArray.Count(); for (i = 0; i < max; i++) { pEntry = (CAliasEntry *) groupsArray.ElementAt(i); ResolveEntries( pEntry->m_name, pEntry->m_list, emailList); AddSingleList(pEntry, emailList, pDb); emailList.Clear(); } } void nsEudoraAddress::ExtractNoteField( nsCString& note, nsCString& value, const char *pFieldName) { value.Truncate( 0); nsCString field("<"); field.Append( pFieldName); field.Append( ':'); /* this is a bit of a cheat, but there's no reason it won't work fine for us, even better than Eudora in some cases! */ PRInt32 idx = note.Find( field); if (idx != -1) { idx += field.Length(); PRInt32 endIdx = note.FindChar( '>', idx); if (endIdx == -1) endIdx = note.Length() - 1; note.Mid( value, idx, endIdx - idx); idx -= field.Length(); nsCString tempL; if (idx) note.Left( tempL, idx); nsCString tempR; note.Right( tempR, note.Length() - endIdx - 1); note = tempL; note.Append( tempR); } } void nsEudoraAddress::SanitizeValue( nsCString& val) { val.ReplaceSubstring( "\x0D\x0A", ", "); val.ReplaceChar( 13, ','); val.ReplaceChar( 10, ','); } void nsEudoraAddress::SplitString( nsCString& val1, nsCString& val2) { nsCString temp; // Find the last line if there is more than one! PRInt32 idx = val1.RFind( "\x0D\x0A"); PRInt32 cnt = 2; if (idx == -1) { cnt = 1; idx = val1.RFindChar( 13); } if (idx == -1) idx= val1.RFindChar( 10); if (idx != -1) { val1.Right( val2, val1.Length() - idx - cnt); val1.Left( temp, idx); val1 = temp; SanitizeValue( val1); } } void nsEudoraAddress::AddSingleCard( CAliasEntry *pEntry, nsVoidArray &emailList, nsIAddrDatabase *pDb) { // We always have a nickname and everything else is optional. // Map both home and work related fiedls to our address card. Eudora // fields that can't be mapped will be left in the 'note' field! nsIMdbRow* newRow = nsnull; pDb->GetNewRow( &newRow); if (!newRow) return; nsCString displayName, name, firstName, lastName; nsCString fax, phone, mobile, webLink; nsCString address, address2, city, state, zip, country; nsCString phoneWK, webLinkWK, title, company; nsCString addressWK, address2WK, cityWK, stateWK, zipWK, countryWK; nsCString note(pEntry->m_notes); if (!note.IsEmpty()) { ExtractNoteField( note, fax, "fax"); ExtractNoteField( note, phone, "phone"); ExtractNoteField( note, mobile, "mobile"); ExtractNoteField( note, address, "address"); ExtractNoteField( note, city, "city"); ExtractNoteField( note, state, "state"); ExtractNoteField( note, zip, "zip"); ExtractNoteField( note, country, "country"); ExtractNoteField( note, name, "name"); ExtractNoteField( note, firstName, "first"); ExtractNoteField( note, lastName, "last"); ExtractNoteField( note, webLink, "web"); ExtractNoteField( note, addressWK, "address2"); ExtractNoteField( note, cityWK, "city2"); ExtractNoteField( note, stateWK, "state2"); ExtractNoteField( note, zipWK, "zip2"); ExtractNoteField( note, countryWK, "country2"); ExtractNoteField( note, phoneWK, "phone2"); ExtractNoteField( note, title, "title"); ExtractNoteField( note, company, "company"); ExtractNoteField( note, webLinkWK, "web2"); } CAliasData *pData = emailList.Count() ? (CAliasData *)emailList.ElementAt(0) : nsnull; if (pData && !pData->m_realName.IsEmpty()) displayName = pData->m_realName; else if (!name.IsEmpty()) displayName = name; else displayName = pEntry->m_name; address.ReplaceSubstring( "\x03", "\x0D\x0A"); SplitString( address, address2); note.ReplaceSubstring( "\x03", "\x0D\x0A"); fax.ReplaceSubstring( "\x03", " "); phone.ReplaceSubstring( "\x03", " "); name.ReplaceSubstring( "\x03", " "); city.ReplaceSubstring( "\x03", " "); state.ReplaceSubstring( "\x03", " "); zip.ReplaceSubstring( "\x03", " "); country.ReplaceSubstring( "\x03", " "); addressWK.ReplaceSubstring( "\x03", "\x0D\x0A"); SplitString( addressWK, address2WK); phoneWK.ReplaceSubstring( "\x03", " "); cityWK.ReplaceSubstring( "\x03", " "); stateWK.ReplaceSubstring( "\x03", " "); zipWK.ReplaceSubstring( "\x03", " "); countryWK.ReplaceSubstring( "\x03", " "); title.ReplaceSubstring( "\x03", " "); company.ReplaceSubstring( "\x03", " "); if (newRow) { nsAutoString uniStr; // Home related fields. ADD_FIELD_TO_DB_ROW(pDb, AddDisplayName, newRow, displayName, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddNickName, newRow, pEntry->m_name, uniStr); if (pData) ADD_FIELD_TO_DB_ROW(pDb, AddPrimaryEmail, newRow, pData->m_email, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddFirstName, newRow, firstName, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddLastName, newRow, lastName, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWebPage2, newRow, webLink, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddFaxNumber, newRow, fax, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomePhone, newRow, phone, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeAddress, newRow, address, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeAddress2, newRow, address2, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeCity, newRow, city, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeZipCode, newRow, zip, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeState, newRow, state, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddHomeCountry, newRow, country, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddCellularNumber, newRow, mobile, uniStr); // Work related fields. ADD_FIELD_TO_DB_ROW(pDb, AddJobTitle, newRow, title, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddCompany, newRow, company, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWebPage1, newRow, webLinkWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkPhone, newRow, phoneWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkAddress, newRow, addressWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkAddress2, newRow, address2WK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkCity, newRow, cityWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkZipCode, newRow, zipWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkState, newRow, stateWK, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddWorkCountry, newRow, countryWK, uniStr); // Lastly, note field. ADD_FIELD_TO_DB_ROW(pDb, AddNotes, newRow, note, uniStr); pDb->AddCardRowToDB( newRow); IMPORT_LOG1( "Added card to db: %s\n", displayName.get()); } } // // Since there is no way to check if a card for a given email address already exists, // elements in 'membersArray' are make unique. So for each email address in 'emailList' // we check it in 'membersArray' and if it's not there then we add it to 'membersArray'. // void nsEudoraAddress::RememberGroupMembers(nsVoidArray &membersArray, nsVoidArray &emailList) { PRInt32 cnt = emailList.Count(); CAliasData *pData; for (PRInt32 i = 0; i < cnt; i++) { pData = (CAliasData *)emailList.ElementAt(i); if (!pData) continue; PRInt32 memberCnt = membersArray.Count(); PRInt32 j = 0; for (j = 0; j < memberCnt; j++) { if (pData == membersArray.ElementAt(j)) break; } if (j >= memberCnt) membersArray.AppendElement(pData); // add to member list } } nsresult nsEudoraAddress::AddGroupMembersAsCards(nsVoidArray &membersArray, nsIAddrDatabase *pDb) { PRInt32 max = membersArray.Count(); CAliasData *pData; nsresult rv = NS_OK; nsCOMPtr newRow; nsAutoString uniStr; nsCAutoString displayName; for (PRInt32 i = 0; i < max; i++) { pData = (CAliasData *)membersArray.ElementAt(i); if (!pData || (pData->m_email.IsEmpty())) continue; rv = pDb->GetNewRow(getter_AddRefs(newRow)); if (NS_FAILED(rv) || !newRow) return rv; if (!pData->m_realName.IsEmpty()) displayName = pData->m_realName; else if (!pData->m_nickName.IsEmpty()) displayName = pData->m_nickName; else displayName.Truncate(); ADD_FIELD_TO_DB_ROW(pDb, AddDisplayName, newRow, displayName, uniStr); ADD_FIELD_TO_DB_ROW(pDb, AddPrimaryEmail, newRow, pData->m_email, uniStr); rv = pDb->AddCardRowToDB( newRow); NS_ENSURE_SUCCESS(rv, rv); } return rv; } nsresult nsEudoraAddress::AddSingleList(CAliasEntry *pEntry, nsVoidArray &emailList, nsIAddrDatabase *pDb) { // Create a list. nsCOMPtr newRow; nsresult rv = pDb->GetNewListRow(getter_AddRefs(newRow)); if (NS_FAILED(rv) || !newRow) return rv; rv = pDb->AddListName(newRow, pEntry->m_name.get()); NS_ENSURE_SUCCESS(rv, rv); // Now add the members. PRInt32 max = emailList.Count(); for (PRInt32 i = 0; i < max; i++) { CAliasData *pData = (CAliasData *)emailList.ElementAt(i); nsCAutoString ldifValue(NS_LITERAL_CSTRING("mail=") + nsDependentCString(pData->m_email.get())); rv = pDb->AddLdifListMember(newRow, ldifValue.get()); } rv = pDb->AddCardRowToDB(newRow); NS_ENSURE_SUCCESS(rv, rv); rv = pDb->AddListDirNode(newRow); return rv; }