Back to index

lightning-sunbird  0.9+nobinonly
nsAbOSXCard.mm
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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  * Peter Van der Beken.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Peter Van der Beken <peterv@propagandism.org>
00024  *
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * 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 "nsAbOSXCard.h"
00041 #include "nsAbOSXDirectory.h"
00042 #include "nsAbOSXUtils.h"
00043 #include "nsAutoPtr.h"
00044 #include "nsIAddrBookSession.h"
00045 #include "nsServiceManagerUtils.h"
00046 
00047 #include <AddressBook/AddressBook.h>
00048 
00049 NS_IMPL_ISUPPORTS_INHERITED2(nsAbOSXCard,
00050                              nsRDFResource,
00051                              nsIAbCard,
00052                              nsIAbOSXCard)
00053 
00054 #ifdef DEBUG
00055 static ABPropertyType
00056 GetPropertType(ABRecord *aCard, NSString *aProperty)
00057 {
00058     ABPropertyType propertyType = kABErrorInProperty;
00059     if ([aCard isKindOfClass:[ABPerson class]]) {
00060         propertyType = [ABPerson typeOfProperty:aProperty];
00061     }
00062     else if ([aCard isKindOfClass:[ABGroup class]]) {
00063         propertyType = [ABGroup typeOfProperty:aProperty];
00064     }
00065     return propertyType;
00066 }
00067 #endif
00068 
00069 static void
00070 SetStringProperty(nsAbOSXCard *aCard, nsString &aValue, nsString &aMember,
00071                   const char *aMemberName, PRBool aNotify,
00072                   nsIAddrBookSession *aSession)
00073 {
00074     if (!aNotify) {
00075         aMember = aValue;
00076     }
00077     else if (!aMember.Equals(aValue)) {
00078         nsString oldValue(aMember);
00079         aMember = aValue;
00080 
00081         nsISupports *supports = NS_ISUPPORTS_CAST(nsRDFResource*, aCard);
00082         aSession->NotifyItemPropertyChanged(supports, aMemberName,
00083                                             oldValue.get(), aMember.get());
00084     }
00085 }
00086 
00087 static void
00088 SetStringProperty(nsAbOSXCard *aCard, NSString *aValue, nsString &aMember,
00089                   const char *aMemberName, PRBool aNotify,
00090                   nsIAddrBookSession *aSession)
00091 {
00092     nsAutoString value;
00093     if (aValue) {
00094         AppendToString(aValue, value);
00095     }
00096     SetStringProperty(aCard, value, aMember, aMemberName, aNotify, aSession);
00097 }
00098 
00099 static void
00100 MapStringProperty(nsAbOSXCard *aCard, ABRecord *aOSXCard, NSString *aProperty,
00101                   nsString &aMember, const char *aMemberName, PRBool aNotify,
00102                   nsIAddrBookSession *aSession)
00103 {
00104     NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
00105     NS_ASSERTION(GetPropertType(aOSXCard, aProperty) == kABStringProperty,
00106                  "Wrong type!");
00107 
00108     SetStringProperty(aCard, [aOSXCard valueForProperty:aProperty], aMember,
00109                       aMemberName, aNotify, aSession);
00110 }
00111 
00112 static ABMutableMultiValue*
00113 GetMultiValue(ABRecord *aCard, NSString *aProperty)
00114 {
00115     NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
00116     NS_ASSERTION(GetPropertType(aCard, aProperty) & kABMultiValueMask,
00117                  "Wrong type!");
00118 
00119     return [aCard valueForProperty:aProperty];
00120 }
00121 
00122 static void
00123 MapDate(nsAbOSXCard *aCard, NSDate *aDate, nsString &aYear,
00124         const char *aYearName, nsString &aMonth, const char *aMonthName,
00125         nsString &aDay, const char *aDayName, PRBool aNotify,
00126         nsIAddrBookSession *aSession)
00127 {
00128     // XXX Should we pass a format and timezone?
00129     NSCalendarDate *date = [aDate dateWithCalendarFormat:nil timeZone:nil];
00130 
00131     nsAutoString value;
00132     value.AppendInt([date yearOfCommonEra]);
00133     SetStringProperty(aCard, value, aYear, aYearName, aNotify, aSession);
00134     value.AppendInt([date monthOfYear]);
00135     SetStringProperty(aCard, value, aMonth, aMonthName, aNotify, aSession);
00136     value.AppendInt([date dayOfWeek]);
00137     SetStringProperty(aCard, value, aDay, aDayName, aNotify, aSession);
00138 }
00139 
00140 static PRBool
00141 MapMultiValue(nsAbOSXCard *aCard, ABRecord *aOSXCard,
00142               const nsAbOSXPropertyMap &aMap, PRBool aNotify,
00143               nsIAddrBookSession *aSession)
00144 {
00145     ABMultiValue *value = GetMultiValue(aOSXCard, aMap.mOSXProperty);
00146     if (value) {
00147         unsigned int j, count = [value count];
00148         for (j = 0; j < count; ++j) {
00149             if ([[value labelAtIndex:j] isEqualToString:aMap.mOSXLabel]) {
00150                 NSString *stringValue;
00151                 if (aMap.mOSXKey) {
00152                     stringValue = [[value valueAtIndex:j] objectForKey:aMap.mOSXKey];
00153                 }
00154                 else {
00155                     stringValue = [value valueAtIndex:j];
00156                 }
00157 
00158                 SetStringProperty(aCard, stringValue, aCard->*(aMap.mProperty),
00159                                   aMap.mPropertyName, aNotify, aSession);
00160 
00161                 return PR_TRUE;
00162             }
00163         }
00164     }
00165 
00166     return PR_FALSE;
00167 }
00168 
00169 NS_IMETHODIMP
00170 nsAbOSXCard::Init(const char *aUri)
00171 {
00172     if (strncmp(aUri, NS_ABOSXCARD_URI_PREFIX,
00173                 sizeof(NS_ABOSXCARD_URI_PREFIX) - 1) != 0) {
00174         return NS_ERROR_FAILURE;
00175     }
00176 
00177     nsresult rv = nsRDFResource::Init(aUri);
00178     NS_ENSURE_SUCCESS(rv, rv);
00179 
00180     return Update(PR_FALSE);
00181 }
00182 
00183 nsresult
00184 nsAbOSXCard::Update(PRBool aNotify)
00185 {
00186     ABAddressBook *addressBook = [ABAddressBook sharedAddressBook];
00187 
00188     const char *uid = &((mURI.get())[16]);
00189     ABRecord *card = [addressBook recordForUniqueId:[NSString stringWithUTF8String:uid]];
00190     NS_ENSURE_TRUE(card, NS_ERROR_FAILURE);
00191 
00192     nsCOMPtr<nsIAddrBookSession> abSession;
00193     nsresult rv;
00194     if (aNotify) {
00195         abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00196         NS_ENSURE_SUCCESS(rv, rv);
00197     }
00198 
00199     if ([card isKindOfClass:[ABGroup class]]) {
00200         m_IsMailList = PR_TRUE;
00201         m_MailListURI.AssignLiteral(NS_ABOSXDIRECTORY_URI_PREFIX);
00202         m_MailListURI.Append(uid);
00203         MapStringProperty(this, card, kABGroupNameProperty, m_DisplayName,
00204                           "DisplayName", aNotify, abSession);
00205 
00206         return NS_OK;
00207     }
00208 
00209     PRBool foundHome = PR_FALSE, foundWork = PR_FALSE;
00210 
00211     PRUint32 i;
00212     for (i = 0; i < nsAbOSXUtils::kPropertyMapSize; ++i) {
00213         const nsAbOSXPropertyMap &propertyMap = nsAbOSXUtils::kPropertyMap[i];
00214         if (!propertyMap.mOSXProperty) {
00215             continue;
00216         }
00217 
00218         if (propertyMap.mOSXLabel) {
00219             PRBool found = MapMultiValue(this, card, propertyMap, aNotify,
00220                                          abSession);
00221 
00222             if (found && propertyMap.mOSXProperty == kABAddressProperty) {
00223                 if (propertyMap.mOSXLabel == kABAddressHomeLabel) {
00224                     foundHome = PR_TRUE;
00225                 }
00226                 else {
00227                     foundWork = PR_TRUE;
00228                 }
00229             }
00230         }
00231         else {
00232             MapStringProperty(this, card, propertyMap.mOSXProperty,
00233                               this->*(propertyMap.mProperty),
00234                               propertyMap.mPropertyName, aNotify, abSession);
00235         }
00236     }
00237 
00238     int flags = 0;
00239     if (kABPersonFlags) {
00240         flags = [[card valueForProperty:kABPersonFlags] intValue];
00241     }
00242 
00243 #define SET_STRING(_value, _name, _notify, _session) \
00244     SetStringProperty(this, _value, m_##_name, #_name, _notify, _session)
00245 
00246     // If kABShowAsCompany is set we use the company name as display name.
00247     if (flags & kABShowAsCompany) {
00248         SET_STRING(m_Company, DisplayName, aNotify, abSession);
00249     }
00250     else {
00251         // Use the order used in the OS X address book to set DisplayName.
00252         int order = flags & kABNameOrderingMask;
00253         if (order == kABDefaultNameOrdering) {
00254            order = [addressBook defaultNameOrdering];
00255         }
00256 
00257         nsAutoString displayName;
00258         if (order == kABFirstNameFirst) {
00259             displayName.Append(m_FirstName);
00260             displayName.Append(' ');
00261             displayName.Append(m_LastName);
00262         }
00263         else {
00264             displayName.Append(m_LastName);
00265             displayName.Append(' ');
00266             displayName.Append(m_FirstName);
00267         }
00268         SET_STRING(displayName, DisplayName, aNotify, abSession);
00269     }
00270 
00271     ABMultiValue *value = GetMultiValue(card, kABEmailProperty);
00272     if (value) {
00273         unsigned int count = [value count];
00274         if (count > 0) {
00275             unsigned int j = [value indexForIdentifier:[value primaryIdentifier]];
00276 
00277             if (j < count) {
00278                 SET_STRING([value valueAtIndex:j], PrimaryEmail, aNotify,
00279                            abSession);
00280             }
00281 
00282             // If j is 0 (first in the list) we want the second in the list
00283             // (index 1), if j is anything else we want the first in the list
00284             // (index 0).
00285             j = (j == 0);
00286             if (j < count) {
00287                 SET_STRING([value valueAtIndex:j], SecondEmail, aNotify,
00288                            abSession);
00289             }
00290         }
00291     }
00292 
00293     // We map the first home address we can find and the first work address
00294     // we can find. If we find none, we map the primary address to the home
00295     // address.
00296     if (!foundHome && !foundWork) {
00297         value = GetMultiValue(card, kABAddressProperty);
00298         if (value) {
00299             unsigned int j, count = [value count];
00300             j = [value indexForIdentifier:[value primaryIdentifier]];
00301 
00302             if (j < count) {
00303                 NSDictionary *address = [value valueAtIndex:j];
00304                 if (address) {
00305                     SET_STRING([address objectForKey:kABAddressStreetKey],
00306                                HomeAddress, aNotify, abSession);
00307                     SET_STRING([address objectForKey:kABAddressCityKey],
00308                                HomeCity, aNotify, abSession);
00309                     SET_STRING([address objectForKey:kABAddressStateKey],
00310                                HomeState, aNotify, abSession);
00311                     SET_STRING([address objectForKey:kABAddressZIPKey],
00312                                HomeZipCode, aNotify, abSession);
00313                     SET_STRING([address objectForKey:kABAddressCountryKey],
00314                                HomeCountry, aNotify, abSession);
00315                 }
00316             }
00317         }
00318     }
00319 
00320     value = GetMultiValue(card, kABAIMInstantProperty);
00321     if (value) {
00322         unsigned int count = [value count];
00323         if (count > 0) {
00324             unsigned int j = [value indexForIdentifier:[value primaryIdentifier]];
00325 
00326             if (j < count) {
00327                 SET_STRING([value valueAtIndex:j], AimScreenName, aNotify,
00328                            abSession);
00329             }
00330         }
00331     }
00332 
00333 #define MAP_DATE(_date, _name, _notify, _session) \
00334     MapDate(this, _date, m_##_name##Year, #_name"Year", m_##_name##Month, \
00335             #_name"Month", m_##_name##Day, #_name"Day", _notify, _session)
00336 
00337     NSDate *date = [card valueForProperty:kABBirthdayProperty];
00338     if (date) {
00339         MAP_DATE(date, Birth, aNotify, abSession);
00340     }
00341 
00342     if (kABOtherDatesProperty) {
00343         value = GetMultiValue(card, kABOtherDatesProperty);
00344         if (value) {
00345             unsigned int j, count = [value count];
00346             for (j = 0; j < count; ++j) {
00347                 if ([[value labelAtIndex:j] isEqualToString:kABAnniversaryLabel]) {
00348                     date = [value valueAtIndex:j];
00349                     if (date) {
00350                         MAP_DATE(date, Anniversary, aNotify, abSession);
00351 
00352                         break;
00353                     }
00354                 }
00355             }
00356         }
00357     }
00358 #undef MAP_DATE
00359 #undef SET_STRING
00360 
00361     date = [card valueForProperty:kABModificationDateProperty];
00362     if (date) {
00363         m_LastModDate = PRUint32([date timeIntervalSince1970]);
00364         // XXX No way to notify about this?
00365     }
00366 
00367     return NS_OK;
00368 }