Back to index

lightning-sunbird  0.9+nobinonly
nsAbAddressCollecter.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "msgCore.h"  // for pre-compiled headers
00041 
00042 #include "nsIServiceManager.h"
00043 
00044 #include "nsIAbCard.h"
00045 #include "nsAbBaseCID.h"
00046 #include "nsAbAddressCollecter.h"
00047 #include "nsIPrefService.h"
00048 #include "nsIPrefBranch2.h"
00049 #include "nsIAddrBookSession.h"
00050 #include "nsIMsgHeaderParser.h"
00051 #include "nsIRDFService.h"
00052 #include "nsRDFCID.h"
00053 #include "nsXPIDLString.h"
00054 #include "nsReadableUtils.h"
00055 #include "prmem.h"
00056 #include "nsIAddressBook.h"
00057 
00058 NS_IMPL_ISUPPORTS2(nsAbAddressCollecter, nsIAbAddressCollecter, nsIObserver)
00059 
00060 #define PREF_MAIL_COLLECT_ADDRESSBOOK "mail.collect_addressbook"
00061 
00062 nsAbAddressCollecter::nsAbAddressCollecter()
00063 {
00064 }
00065 
00066 nsAbAddressCollecter::~nsAbAddressCollecter()
00067 {
00068   if (m_database) {
00069     m_database->Commit(nsAddrDBCommitType::kSessionCommit);
00070     m_database->Close(PR_FALSE);
00071     m_database = nsnull;
00072   }
00073 
00074   nsresult rv;
00075   nsCOMPtr<nsIPrefBranch2> pPrefBranchInt(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00076   if(NS_SUCCEEDED(rv))
00077     pPrefBranchInt->RemoveObserver(PREF_MAIL_COLLECT_ADDRESSBOOK, this);
00078 }
00079 
00080 NS_IMETHODIMP nsAbAddressCollecter::CollectUnicodeAddress(const PRUnichar *aAddress, PRBool aCreateCard, PRUint32 aSendFormat)
00081 {
00082   NS_ENSURE_ARG_POINTER(aAddress);
00083   // convert the unicode string to UTF-8...
00084   nsresult rv = CollectAddress(NS_ConvertUCS2toUTF8(aAddress).get(), aCreateCard, aSendFormat);
00085   NS_ENSURE_SUCCESS(rv,rv);
00086   return rv;
00087 }
00088 
00089 NS_IMETHODIMP nsAbAddressCollecter::GetCardFromAttribute(const char *aName, const char *aValue, nsIAbCard **aCard)
00090 {
00091   NS_ENSURE_ARG_POINTER(aCard);
00092   if (m_database)
00093     // Please DO NOT change the 3rd param of GetCardFromAttribute() call to 
00094     // PR_TRUE (ie, case insensitive) without reading bugs #128535 and #121478.
00095     return m_database->GetCardFromAttribute(m_directory, aName, aValue, PR_FALSE /* retain case */, aCard);
00096 
00097   return NS_ERROR_FAILURE;
00098 }
00099 
00100 NS_IMETHODIMP nsAbAddressCollecter::CollectAddress(const char *aAddress, PRBool aCreateCard, PRUint32 aSendFormat)
00101 {
00102   // note that we're now setting the whole recipient list,
00103   // not just the pretty name of the first recipient.
00104   PRUint32 numAddresses;
00105   char *names;
00106   char *addresses;
00107 
00108   nsresult rv;
00109   nsCOMPtr<nsIMsgHeaderParser> pHeader = do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID, &rv);
00110   NS_ENSURE_SUCCESS(rv,rv);
00111 
00112   rv = pHeader->ParseHeaderAddresses(nsnull, aAddress, &names, &addresses, &numAddresses);
00113   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to parse, so can't collect");
00114   if (NS_FAILED(rv))
00115     return NS_OK;
00116 
00117   char *curName = names;
00118   char *curAddress = addresses;
00119 
00120   for (PRUint32 i = 0; i < numAddresses; i++)
00121   {
00122     nsXPIDLCString unquotedName;
00123     rv = pHeader->UnquotePhraseOrAddr(curName, PR_FALSE, getter_Copies(unquotedName));
00124     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to unquote name");
00125     if (NS_FAILED(rv))
00126       continue;
00127 
00128     nsCOMPtr <nsIAbCard> existingCard;
00129     nsCOMPtr <nsIAbCard> cardInstance;
00130     PRBool emailAddressIn2ndEmailColumn = PR_FALSE;
00131 
00132     rv = GetCardFromAttribute(kPriEmailColumn, curAddress, getter_AddRefs(existingCard));
00133     // We've not found a card, but is this address actually in the additional
00134     // email column?
00135     if (!existingCard)
00136     {
00137       rv = GetCardFromAttribute(k2ndEmailColumn, curAddress, getter_AddRefs(existingCard));
00138       if (existingCard)
00139         emailAddressIn2ndEmailColumn = PR_TRUE;
00140     }
00141 
00142     if (!existingCard && aCreateCard)
00143     {
00144       nsCOMPtr<nsIAbCard> senderCard = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
00145       if (NS_SUCCEEDED(rv) && senderCard)
00146       {
00147         PRBool modifiedCard;
00148         rv = SetNamesForCard(senderCard, unquotedName.get(), &modifiedCard);
00149         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to set names");
00150 
00151         rv = AutoCollectScreenName(senderCard, curAddress, &modifiedCard);
00152         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to set screenname");
00153 
00154         rv = senderCard->SetPrimaryEmail(NS_ConvertASCIItoUCS2(curAddress).get());
00155         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to set email");
00156 
00157         if (aSendFormat != nsIAbPreferMailFormat::unknown)
00158         {
00159           rv = senderCard->SetPreferMailFormat(aSendFormat);
00160           NS_ASSERTION(NS_SUCCEEDED(rv), "failed to remember preferred mail format");
00161         }
00162 
00163         rv = AddCardToAddressBook(senderCard);
00164         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to add card");
00165       }
00166     }
00167     else if (existingCard && !emailAddressIn2ndEmailColumn) { 
00168       // address is already in the AB, so update the names
00169       PRBool setNames = PR_FALSE;
00170       
00171       if (!unquotedName.IsEmpty())
00172       {
00173         rv = SetNamesForCard(existingCard, unquotedName.get(), &setNames);
00174         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to set names");
00175       }
00176 
00177       PRBool setScreenName = PR_FALSE; 
00178       rv = AutoCollectScreenName(existingCard, curAddress, &setScreenName);
00179       NS_ASSERTION(NS_SUCCEEDED(rv), "failed to set screen name");
00180 
00181       PRBool setPreferMailFormat = PR_FALSE; 
00182       if (aSendFormat != nsIAbPreferMailFormat::unknown)
00183       {
00184         PRUint32 currentFormat;
00185         rv = existingCard->GetPreferMailFormat(&currentFormat);
00186         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get preferred mail format");
00187 
00188         // we only want to update the AB if the current format is unknown
00189         if (currentFormat == nsIAbPreferMailFormat::unknown) 
00190         {
00191           rv = existingCard->SetPreferMailFormat(aSendFormat);
00192           NS_ASSERTION(NS_SUCCEEDED(rv), "failed to remember preferred mail format");
00193           setPreferMailFormat = PR_TRUE;
00194         }
00195       }
00196 
00197       if (setScreenName || setNames || setPreferMailFormat)
00198         existingCard->EditCardToDatabase(m_abURI.get());
00199     }
00200 
00201     curName += strlen(curName) + 1;
00202     curAddress += strlen(curAddress) + 1;
00203   } 
00204 
00205   PR_FREEIF(addresses);
00206   PR_FREEIF(names);
00207   return NS_OK;
00208 }
00209 
00210 nsresult nsAbAddressCollecter::AutoCollectScreenName(nsIAbCard *aCard, const char *aEmail, PRBool *aModifiedCard)
00211 {
00212   NS_ENSURE_ARG_POINTER(aCard);
00213   NS_ENSURE_ARG_POINTER(aEmail);
00214   NS_ENSURE_ARG_POINTER(aModifiedCard);
00215 
00216   *aModifiedCard = PR_FALSE;
00217 
00218   nsXPIDLString screenName;
00219   nsresult rv = aCard->GetAimScreenName(getter_Copies(screenName));
00220   NS_ENSURE_SUCCESS(rv,rv);
00221 
00222   // don't override existing screennames
00223   if (!screenName.IsEmpty())
00224     return NS_OK;
00225 
00226   const char *atPos = strchr(aEmail, '@');
00227   
00228   if (!atPos)
00229     return NS_OK;
00230   
00231   const char *domain = atPos + 1;
00232  
00233   if (!domain)
00234     return NS_OK;
00235  
00236   // username in 
00237   // username@aol.com (America Online)
00238   // username@cs.com (Compuserve)
00239   // username@netscape.net (Netscape webmail)
00240   // are all AIM screennames.  autocollect that info.
00241   if (strcmp(domain,"aol.com") && 
00242       strcmp(domain,"cs.com") && 
00243       strcmp(domain,"netscape.net"))
00244     return NS_OK;
00245 
00246   NS_ConvertASCIItoUTF16 userName(Substring(aEmail, atPos));
00247 
00248   rv = aCard->SetAimScreenName(userName.get());
00249   NS_ENSURE_SUCCESS(rv,rv);
00250   
00251   *aModifiedCard = PR_TRUE;
00252   return rv;
00253 }
00254 
00255 
00256 nsresult 
00257 nsAbAddressCollecter::SetNamesForCard(nsIAbCard *senderCard, const char *fullName, PRBool *aModifiedCard)
00258 {
00259   char *firstName = nsnull;
00260   char *lastName = nsnull;
00261   *aModifiedCard = PR_FALSE;
00262 
00263   nsXPIDLString displayName;
00264   nsresult rv = senderCard->GetDisplayName(getter_Copies(displayName));
00265   NS_ENSURE_SUCCESS(rv,rv);
00266 
00267   // we already have a display name, so don't do anything
00268   if (!displayName.IsEmpty())
00269     return NS_OK;
00270 
00271   senderCard->SetDisplayName(NS_ConvertUTF8toUCS2(fullName).get());
00272   *aModifiedCard = PR_TRUE;
00273 
00274   rv = SplitFullName(fullName, &firstName, &lastName);
00275   if (NS_SUCCEEDED(rv))
00276   {
00277     senderCard->SetFirstName(NS_ConvertUTF8toUCS2(firstName).get());
00278     
00279     if (lastName)
00280       senderCard->SetLastName(NS_ConvertUTF8toUCS2(lastName).get());
00281   }
00282   PR_FREEIF(firstName);
00283   PR_FREEIF(lastName);
00284   return rv;
00285 }
00286 
00287 nsresult nsAbAddressCollecter::SplitFullName(const char *fullName, char **firstName, char **lastName)
00288 {
00289   if (fullName)
00290   {
00291     *firstName = nsCRT::strdup(fullName);
00292     if (!*firstName)
00293       return NS_ERROR_OUT_OF_MEMORY;
00294 
00295     char *plastSpace = *firstName;
00296     char *walkName = *firstName;
00297     char *plastName = nsnull;
00298 
00299     while (walkName && *walkName)
00300     {
00301       if (*walkName == ' ')
00302       {
00303         plastSpace = walkName;
00304         plastName = plastSpace + 1;
00305       }
00306             
00307       walkName++;
00308     }
00309 
00310     if (plastName) 
00311     {
00312       *plastSpace = '\0';
00313       *lastName = nsCRT::strdup(plastName);
00314     }
00315   }
00316 
00317   return NS_OK;
00318 }
00319 
00320 NS_IMETHODIMP nsAbAddressCollecter::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
00321 {
00322   nsCOMPtr<nsIPrefBranch2> pPrefBranchInt = do_QueryInterface(aSubject);
00323   NS_ASSERTION(pPrefBranchInt, "failed to get prefs");
00324 
00325   nsresult rv;
00326   nsXPIDLCString prefVal;
00327   pPrefBranchInt->GetCharPref(PREF_MAIL_COLLECT_ADDRESSBOOK, getter_Copies(prefVal));
00328   rv = SetAbURI(prefVal.IsEmpty() ? kPersonalAddressbookUri : prefVal.get());
00329   NS_ASSERTION(NS_SUCCEEDED(rv),"failed to change collected ab");
00330   return NS_OK;
00331 }
00332 
00333 nsresult nsAbAddressCollecter::Init(void)
00334 {
00335   nsresult rv;
00336   nsCOMPtr<nsIPrefBranch2> pPrefBranchInt(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00337   NS_ENSURE_SUCCESS(rv,rv);
00338 
00339   rv = pPrefBranchInt->AddObserver(PREF_MAIL_COLLECT_ADDRESSBOOK, this, PR_FALSE);
00340 
00341   nsXPIDLCString prefVal;
00342   pPrefBranchInt->GetCharPref(PREF_MAIL_COLLECT_ADDRESSBOOK, getter_Copies(prefVal));
00343   return SetAbURI(prefVal.IsEmpty() ? kPersonalAddressbookUri : prefVal.get());
00344 }
00345 
00346 nsresult nsAbAddressCollecter::AddCardToAddressBook(nsIAbCard *card)
00347 {
00348   NS_ENSURE_ARG_POINTER(card);
00349 
00350   nsCOMPtr <nsIAbCard> addedCard;
00351   if (m_directory)
00352     return m_directory->AddCard(card, getter_AddRefs(addedCard));
00353 
00354   return NS_ERROR_FAILURE;
00355 }
00356 
00357 nsresult nsAbAddressCollecter::SetAbURI(const char *aURI)
00358 {
00359   NS_ENSURE_ARG_POINTER(aURI);
00360 
00361   if (!strcmp(aURI,m_abURI.get()))
00362     return NS_OK;
00363 
00364   if (m_database) {
00365     m_database->Commit(nsAddrDBCommitType::kSessionCommit);
00366     m_database->Close(PR_FALSE);
00367     m_database = nsnull;
00368   }
00369   
00370   m_directory = nsnull;
00371   m_abURI = aURI;
00372 
00373   nsresult rv;
00374   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 
00375   NS_ENSURE_SUCCESS(rv, rv);
00376 
00377   nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
00378   NS_ENSURE_SUCCESS(rv, rv);
00379   rv = addressBook->GetAbDatabaseFromURI(m_abURI.get(), getter_AddRefs(m_database));
00380   NS_ENSURE_SUCCESS(rv, rv);
00381 
00382   nsCOMPtr<nsIRDFService> rdfService = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00383   NS_ENSURE_SUCCESS(rv, rv);
00384 
00385   nsCOMPtr <nsIRDFResource> resource;
00386   rv = rdfService->GetResource(m_abURI, getter_AddRefs(resource));
00387   NS_ENSURE_SUCCESS(rv, rv);
00388 
00389   m_directory = do_QueryInterface(resource, &rv);
00390   NS_ENSURE_SUCCESS(rv, rv);
00391   return rv;
00392 }