Back to index

lightning-sunbird  0.9+nobinonly
nsAbWinHelper.cpp
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  * Sun Microsystems, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Created by Cyrille Moureaux <Cyrille.Moureaux@sun.com>
00024  *   Seth Spitzer <sspitzer@netscape.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 #define INITGUID
00040 #define USES_IID_IMAPIProp
00041 #define USES_IID_IMAPIContainer
00042 #define USES_IID_IABContainer
00043 #define USES_IID_IMAPITable
00044 #define USES_IID_IDistList
00045 
00046 #include "nsAbWinHelper.h"
00047 #include "nsMapiAddressBook.h"
00048 #include "nsWabAddressBook.h"
00049 #include "nsCRT.h"
00050 
00051 #include <mapiguid.h>
00052 
00053 #include "prlog.h"
00054 
00055 #ifdef PR_LOGGING
00056 static PRLogModuleInfo* gAbWinHelperLog
00057     = PR_NewLogModule("nsAbWinHelperLog");
00058 #endif
00059 
00060 #define PRINTF(args) PR_LOG(gAbWinHelperLog, PR_LOG_DEBUG, args)
00061 
00062 // Small utility to ensure release of all MAPI interfaces
00063 template <class tInterface> struct nsMapiInterfaceWrapper
00064 {
00065     tInterface mInterface ;
00066 
00067     nsMapiInterfaceWrapper(void) : mInterface(NULL) {}
00068     ~nsMapiInterfaceWrapper(void) {
00069         if (mInterface != NULL) { mInterface->Release() ; }
00070     }
00071     operator LPUNKNOWN *(void) { return NS_REINTERPRET_CAST(LPUNKNOWN *, &mInterface) ; }
00072     tInterface operator -> (void) const { return mInterface ; }
00073     operator tInterface *(void) { return &mInterface ; }
00074 } ;
00075 
00076 static void assignEntryID(LPENTRYID& aTarget, LPENTRYID aSource, ULONG aByteCount)
00077 {
00078     if (aTarget != NULL) {
00079         delete [] (NS_REINTERPRET_CAST (LPBYTE, aTarget)) ;
00080         aTarget = NULL ;
00081     }
00082     if (aSource != NULL) {
00083         aTarget = NS_REINTERPRET_CAST(LPENTRYID, new BYTE [aByteCount]) ;
00084         memcpy(aTarget, aSource, aByteCount) ;
00085     }
00086 }
00087 
00088 MOZ_DECL_CTOR_COUNTER(nsMapiEntry)
00089 
00090 nsMapiEntry::nsMapiEntry(void)
00091 : mByteCount(0), mEntryId(NULL)
00092 {
00093     MOZ_COUNT_CTOR(nsMapiEntry) ;
00094 }
00095 
00096 nsMapiEntry::nsMapiEntry(ULONG aByteCount, LPENTRYID aEntryId)
00097 : mByteCount(0), mEntryId(NULL)
00098 {
00099     Assign(aByteCount, aEntryId) ;
00100     MOZ_COUNT_CTOR(nsMapiEntry) ;
00101 }
00102 
00103 nsMapiEntry::~nsMapiEntry(void)
00104 {
00105     Assign(0, NULL) ;
00106     MOZ_COUNT_DTOR(nsMapiEntry) ;
00107 }
00108 
00109 void nsMapiEntry::Assign(ULONG aByteCount, LPENTRYID aEntryId)
00110 {
00111     assignEntryID(mEntryId, aEntryId, aByteCount) ;
00112     mByteCount = aByteCount ;
00113 }
00114 
00115 static char UnsignedToChar(unsigned char aUnsigned)
00116 {
00117     if (aUnsigned < 0xA) { return '0' + aUnsigned ; }
00118     return 'A' + aUnsigned - 0xA ;
00119 }
00120 
00121 static char kBase64Encoding [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-." ;
00122 static const int kARank = 0 ;
00123 static const int kaRank = 26 ;
00124 static const int k0Rank = 52 ;
00125 static const unsigned char kMinusRank = 62 ;
00126 static const unsigned char kDotRank = 63 ;
00127 
00128 static void UnsignedToBase64(unsigned char *& aUnsigned, 
00129                              ULONG aNbUnsigned, nsCString& aString)
00130 {
00131     if (aNbUnsigned > 0) {
00132         unsigned char remain0 = (*aUnsigned & 0x03) << 4 ;
00133 
00134         aString.Append(kBase64Encoding [(*aUnsigned >> 2) & 0x3F]) ;
00135         ++ aUnsigned ;
00136         if (aNbUnsigned > 1) {
00137             unsigned char remain1 = (*aUnsigned & 0x0F) << 2 ;
00138 
00139             aString.Append(kBase64Encoding [remain0 | ((*aUnsigned >> 4) & 0x0F)]) ;
00140             ++ aUnsigned ;
00141             if (aNbUnsigned > 2) {
00142                 aString.Append(kBase64Encoding [remain1 | ((*aUnsigned >> 6) & 0x03)]) ;
00143                 aString.Append(kBase64Encoding [*aUnsigned & 0x3F]) ;
00144                 ++ aUnsigned ;
00145             }
00146             else {
00147                 aString.Append(kBase64Encoding [remain1]) ;
00148             }
00149         }
00150         else {
00151             aString.Append(kBase64Encoding [remain0]) ;
00152         }
00153     }
00154 }
00155 
00156 static unsigned char CharToUnsigned(char aChar)
00157 {
00158     if (aChar >= '0' && aChar <= '9') { return NS_STATIC_CAST(unsigned char, aChar) - '0' ; }
00159     return NS_STATIC_CAST(unsigned char, aChar) - 'A' + 0xA ;
00160 }
00161 
00162 // This function must return the rank in kBase64Encoding of the 
00163 // character provided.
00164 static unsigned char Base64To6Bits(char aBase64)
00165 {
00166     if (aBase64 >= 'A' && aBase64 <= 'Z') { 
00167         return NS_STATIC_CAST(unsigned char, aBase64 - 'A' + kARank) ; 
00168     }
00169     if (aBase64 >= 'a' && aBase64 <= 'z') { 
00170         return NS_STATIC_CAST(unsigned char, aBase64 - 'a' + kaRank) ; 
00171     }
00172     if (aBase64 >= '0' && aBase64 <= '9') {
00173         return NS_STATIC_CAST(unsigned char, aBase64 - '0' + k0Rank) ;
00174     }
00175     if (aBase64 == '-') { return kMinusRank ; }
00176     if (aBase64 == '.') { return kDotRank ; }
00177     return 0 ;
00178 }
00179 
00180 static void Base64ToUnsigned(const char *& aBase64, PRUint32 aNbBase64, 
00181                              unsigned char *&aUnsigned)
00182 {
00183     // By design of the encoding, we must have at least two characters to use
00184     if (aNbBase64 > 1) {
00185         unsigned char first6Bits = Base64To6Bits(*aBase64 ++) ;
00186         unsigned char second6Bits = Base64To6Bits(*aBase64 ++) ;
00187 
00188         *aUnsigned = first6Bits << 2 ;
00189         *aUnsigned |= second6Bits >> 4 ;
00190         ++ aUnsigned ;
00191         if (aNbBase64 > 2) {
00192             unsigned char third6Bits = Base64To6Bits(*aBase64 ++) ;
00193 
00194             *aUnsigned = second6Bits << 4 ;
00195             *aUnsigned |= third6Bits >> 2 ;
00196             ++ aUnsigned ;
00197             if (aNbBase64 > 3) {
00198                 unsigned char fourth6Bits = Base64To6Bits(*aBase64 ++) ;
00199 
00200                 *aUnsigned = third6Bits << 6 ;
00201                 *aUnsigned |= fourth6Bits ;
00202                 ++ aUnsigned ;
00203             }
00204         }
00205     }
00206 }
00207 
00208 void nsMapiEntry::Assign(const nsCString& aString)
00209 {
00210     Assign(0, NULL) ;
00211     ULONG byteCount = aString.Length() / 4 * 3 ;
00212 
00213     if ((aString.Length() & 0x03) != 0) {
00214         byteCount += (aString.Length() & 0x03) - 1 ;
00215     }
00216     const char *currentSource = aString.get() ;
00217     unsigned char *currentTarget = new unsigned char [byteCount] ;
00218     PRUint32 i = 0 ;
00219 
00220     mByteCount = byteCount ;
00221     mEntryId = NS_REINTERPRET_CAST(LPENTRYID, currentTarget) ;
00222     for (i = aString.Length() ; i >= 4 ; i -= 4) {
00223         Base64ToUnsigned(currentSource, 4, currentTarget) ;
00224     }
00225     Base64ToUnsigned(currentSource, i, currentTarget) ;
00226 }
00227 
00228 void nsMapiEntry::ToString(nsCString& aString) const
00229 {
00230     aString.Truncate() ;
00231     ULONG i = 0 ;
00232     unsigned char *currentSource = NS_REINTERPRET_CAST(unsigned char *, mEntryId) ;
00233 
00234     for (i = mByteCount ; i >= 3 ; i -= 3) {
00235         UnsignedToBase64(currentSource, 3, aString) ;
00236     }
00237     UnsignedToBase64(currentSource, i, aString) ;
00238 }
00239 
00240 void nsMapiEntry::Dump(void) const
00241 {
00242     PRINTF(("%d\n", mByteCount)) ;
00243     for (ULONG i = 0 ; i < mByteCount ; ++ i) {
00244         PRINTF(("%02X", (NS_REINTERPRET_CAST(unsigned char *, mEntryId)) [i])) ;
00245     }
00246     PRINTF(("\n")) ;
00247 }
00248 
00249 MOZ_DECL_CTOR_COUNTER(nsMapiEntryArray)
00250 
00251 nsMapiEntryArray::nsMapiEntryArray(void)
00252 : mEntries(NULL), mNbEntries(0)
00253 {
00254     MOZ_COUNT_CTOR(nsMapiEntryArray) ;
00255 }
00256 
00257 nsMapiEntryArray::~nsMapiEntryArray(void)
00258 {
00259     if (mEntries) { delete [] mEntries ; }
00260     MOZ_COUNT_DTOR(nsMapiEntryArray) ;
00261 }
00262 
00263 void nsMapiEntryArray::CleanUp(void)
00264 {
00265     if (mEntries != NULL) { 
00266         delete [] mEntries ;
00267         mEntries = NULL ;
00268         mNbEntries = 0 ;
00269     }
00270 }
00271 
00272 MOZ_DECL_CTOR_COUNTER(nsAbWinHelper)
00273 
00274 PRUint32 nsAbWinHelper::mEntryCounter = 0 ;
00275 // There seems to be a deadlock/auto-destruction issue
00276 // in MAPI when multiple threads perform init/release 
00277 // operations at the same time. So I've put a mutex
00278 // around both the initialize process and the destruction
00279 // one. I just hope the rest of the calls don't need the 
00280 // same protection (MAPI is supposed to be thread-safe).
00281 PRLock *nsAbWinHelper::mMutex = PR_NewLock() ;
00282 
00283 nsAbWinHelper::nsAbWinHelper(void)
00284 : mAddressBook(NULL), mLastError(S_OK)
00285 {
00286     MOZ_COUNT_CTOR(nsAbWinHelper) ;
00287 }
00288 
00289 nsAbWinHelper::~nsAbWinHelper(void)
00290 {
00291     MOZ_COUNT_DTOR(nsAbWinHelper) ;
00292 }
00293 
00294 BOOL nsAbWinHelper::GetFolders(nsMapiEntryArray& aFolders)
00295 {
00296     aFolders.CleanUp() ;
00297     nsMapiInterfaceWrapper<LPABCONT> rootFolder ;
00298     nsMapiInterfaceWrapper<LPMAPITABLE> folders ;
00299     ULONG objType = 0 ;
00300     ULONG rowCount = 0 ;
00301     SRestriction restriction ;
00302     SPropTagArray folderColumns ;
00303 
00304     mLastError = mAddressBook->OpenEntry(0, NULL, NULL, 0, &objType, 
00305                                          rootFolder) ;
00306     if (HR_FAILED(mLastError)) { 
00307         PRINTF(("Cannot open root %08x.\n", mLastError)) ;
00308         return FALSE ; 
00309     }
00310     mLastError = rootFolder->GetHierarchyTable(0, folders) ;
00311     if (HR_FAILED(mLastError)) {
00312         PRINTF(("Cannot get hierarchy %08x.\n", mLastError)) ;
00313         return FALSE ; 
00314     }
00315     // We only take into account modifiable containers, 
00316     // otherwise, we end up with all the directory services...
00317     restriction.rt = RES_BITMASK ;
00318     restriction.res.resBitMask.ulPropTag = PR_CONTAINER_FLAGS ;
00319     restriction.res.resBitMask.relBMR = BMR_NEZ ;
00320     restriction.res.resBitMask.ulMask = AB_MODIFIABLE ;
00321     mLastError = folders->Restrict(&restriction, 0) ;
00322     if (HR_FAILED(mLastError)) {
00323         PRINTF(("Cannot restrict table %08x.\n", mLastError)) ;
00324     }
00325     folderColumns.cValues = 1 ;
00326     folderColumns.aulPropTag [0] = PR_ENTRYID ;
00327     mLastError = folders->SetColumns(&folderColumns, 0) ;
00328     if (HR_FAILED(mLastError)) {
00329         PRINTF(("Cannot set columns %08x.\n", mLastError)) ;
00330         return FALSE ;
00331     }
00332     mLastError = folders->GetRowCount(0, &rowCount) ;
00333     if (HR_SUCCEEDED(mLastError)) {
00334         aFolders.mEntries = new nsMapiEntry [rowCount] ;
00335         aFolders.mNbEntries = 0 ;
00336         do {
00337             LPSRowSet rowSet = NULL ;
00338 
00339             rowCount = 0 ;
00340             mLastError = folders->QueryRows(1, 0, &rowSet) ;
00341             if (HR_SUCCEEDED(mLastError)) {
00342                 rowCount = rowSet->cRows ;
00343                 if (rowCount > 0) {
00344                     nsMapiEntry& current = aFolders.mEntries [aFolders.mNbEntries ++] ;
00345                     SPropValue& currentValue = rowSet->aRow->lpProps [0] ;
00346                     
00347                     current.Assign(currentValue.Value.bin.cb,
00348                                    NS_REINTERPRET_CAST(LPENTRYID, currentValue.Value.bin.lpb)) ;
00349                 }
00350                 MyFreeProws(rowSet) ;
00351             }
00352             else {
00353                 PRINTF(("Cannot query rows %08x.\n", mLastError)) ;
00354             }
00355         } while (rowCount > 0) ;
00356     }
00357     return HR_SUCCEEDED(mLastError) ;
00358 }
00359 
00360 BOOL nsAbWinHelper::GetCards(const nsMapiEntry& aParent, LPSRestriction aRestriction,
00361                              nsMapiEntryArray& aCards)
00362 {
00363     aCards.CleanUp() ;
00364     return GetContents(aParent, aRestriction, &aCards.mEntries, aCards.mNbEntries, 0) ;
00365 }
00366  
00367 BOOL nsAbWinHelper::GetNodes(const nsMapiEntry& aParent, nsMapiEntryArray& aNodes)
00368 { 
00369     aNodes.CleanUp() ;
00370     return GetContents(aParent, NULL, &aNodes.mEntries, aNodes.mNbEntries, MAPI_DISTLIST) ;
00371 }
00372 
00373 BOOL nsAbWinHelper::GetCardsCount(const nsMapiEntry& aParent, ULONG& aNbCards) 
00374 {
00375     aNbCards = 0 ;
00376     return GetContents(aParent, NULL, NULL, aNbCards, 0) ;
00377 }
00378 
00379 BOOL nsAbWinHelper::GetPropertyString(const nsMapiEntry& aObject,
00380                                       ULONG aPropertyTag, 
00381                                       nsCString& aName)
00382 {
00383     aName.Truncate() ;
00384     LPSPropValue values = NULL ;
00385     ULONG valueCount = 0 ;
00386 
00387     if (!GetMAPIProperties(aObject, &aPropertyTag, 1, values, valueCount)) { return FALSE ; }
00388     if (valueCount == 1 && values != NULL) {
00389         if (PROP_TYPE(values->ulPropTag) == PT_STRING8) {
00390             aName = values->Value.lpszA ;
00391         }
00392         else if (PROP_TYPE(values->ulPropTag) == PT_UNICODE) {
00393             aName.AssignWithConversion(values->Value.lpszW) ;
00394         }
00395     }
00396     FreeBuffer(values) ;
00397     return TRUE ;
00398 }
00399 
00400 BOOL nsAbWinHelper::GetPropertyUString(const nsMapiEntry& aObject, ULONG aPropertyTag,
00401                                        nsString& aName)
00402 {
00403     aName.Truncate() ;
00404     LPSPropValue values = NULL ;
00405     ULONG valueCount = 0 ;
00406 
00407     if (!GetMAPIProperties(aObject, &aPropertyTag, 1, values, valueCount)) { return FALSE ; }
00408     if (valueCount == 1 && values != NULL) {
00409         if (PROP_TYPE(values->ulPropTag) == PT_UNICODE) {
00410             aName = values->Value.lpszW ;
00411         }
00412         else if (PROP_TYPE(values->ulPropTag) == PT_STRING8) {
00413             aName.AssignWithConversion(values->Value.lpszA) ;
00414         }
00415     }
00416     FreeBuffer(values) ;
00417     return TRUE ;
00418 }
00419 
00420 BOOL nsAbWinHelper::GetPropertiesUString(const nsMapiEntry& aObject, const ULONG *aPropertyTags,
00421                                          ULONG aNbProperties, nsStringArray& aNames)
00422 {
00423     aNames.Clear() ;
00424     LPSPropValue values = NULL ;
00425     ULONG valueCount = 0 ;
00426 
00427     if (!GetMAPIProperties(aObject, aPropertyTags, aNbProperties, values, valueCount)) { 
00428         return FALSE ; 
00429     }
00430     if (valueCount == aNbProperties && values != NULL) {
00431         ULONG i = 0 ;
00432 
00433         for (i = 0 ; i < valueCount ; ++ i) {
00434             if (PROP_ID(values [i].ulPropTag) == PROP_ID(aPropertyTags [i])) {
00435                 if (PROP_TYPE(values [i].ulPropTag) == PT_STRING8) {
00436                     nsAutoString temp ;
00437 
00438                     temp.AssignWithConversion (values [i].Value.lpszA) ;
00439                     aNames.AppendString(temp) ;
00440                 }
00441                 else if (PROP_TYPE(values [i].ulPropTag) == PT_UNICODE) {
00442                     aNames.AppendString(nsAutoString (values [i].Value.lpszW)) ;
00443                 }
00444                 else {
00445                     aNames.AppendString(nsAutoString((const PRUnichar *) "")) ;
00446                 }
00447             }
00448             else {
00449                 aNames.AppendString(nsAutoString((const PRUnichar *) "")) ;
00450             }
00451         }
00452         FreeBuffer(values) ;
00453     }
00454     return TRUE ;
00455 }
00456 
00457 BOOL nsAbWinHelper::GetPropertyDate(const nsMapiEntry& aObject, ULONG aPropertyTag, 
00458                                     WORD& aYear, WORD& aMonth, WORD& aDay)
00459 {
00460     aYear = 0 ; 
00461     aMonth = 0 ;
00462     aDay = 0 ;
00463     LPSPropValue values = NULL ;
00464     ULONG valueCount = 0 ;
00465 
00466     if (!GetMAPIProperties(aObject, &aPropertyTag, 1, values, valueCount)) { return FALSE ; }
00467     if (valueCount == 1 && values != NULL && PROP_TYPE(values->ulPropTag) == PT_SYSTIME) {
00468         SYSTEMTIME readableTime ;
00469 
00470         if (FileTimeToSystemTime(&values->Value.ft, &readableTime)) {
00471             aYear = readableTime.wYear ;
00472             aMonth = readableTime.wMonth ;
00473             aDay = readableTime.wDay ;
00474         }
00475     }
00476     FreeBuffer(values) ;
00477     return TRUE ;
00478 }
00479 
00480 BOOL nsAbWinHelper::GetPropertyLong(const nsMapiEntry& aObject, 
00481                                     ULONG aPropertyTag, 
00482                                     ULONG& aValue)
00483 {
00484     aValue = 0 ;
00485     LPSPropValue values = NULL ;
00486     ULONG valueCount = 0 ;
00487 
00488     if (!GetMAPIProperties(aObject, &aPropertyTag, 1, values, valueCount)) { return FALSE ; }
00489     if (valueCount == 1 && values != NULL && PROP_TYPE(values->ulPropTag) == PT_LONG) {
00490         aValue = values->Value.ul ;
00491     }
00492     FreeBuffer(values) ;
00493     return TRUE ;
00494 }
00495 
00496 BOOL nsAbWinHelper::GetPropertyBin(const nsMapiEntry& aObject, ULONG aPropertyTag, 
00497                                    nsMapiEntry& aValue)
00498 {
00499     aValue.Assign(0, NULL) ;
00500     LPSPropValue values = NULL ;
00501     ULONG valueCount = 0 ;
00502 
00503     if (!GetMAPIProperties(aObject, &aPropertyTag, 1, values, valueCount)) { return FALSE ; }
00504     if (valueCount == 1 && values != NULL && PROP_TYPE(values->ulPropTag) == PT_BINARY) {
00505         aValue.Assign(values->Value.bin.cb, 
00506                       NS_REINTERPRET_CAST(LPENTRYID, values->Value.bin.lpb)) ;
00507     }
00508     FreeBuffer(values) ;
00509     return TRUE ;
00510 }
00511 
00512 // This function, supposedly indicating whether a particular entry was
00513 // in a particular container, doesn't seem to work very well (has
00514 // a tendancy to return TRUE even if we're talking to different containers...).
00515 BOOL nsAbWinHelper::TestOpenEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aEntry)
00516 {
00517     nsMapiInterfaceWrapper<LPMAPICONTAINER> container ;
00518     nsMapiInterfaceWrapper<LPMAPIPROP> subObject ;
00519     ULONG objType = 0 ;
00520     
00521     mLastError = mAddressBook->OpenEntry(aContainer.mByteCount, aContainer.mEntryId,
00522                                          &IID_IMAPIContainer, 0, &objType, 
00523                                          container) ;
00524     if (HR_FAILED(mLastError)) {
00525         PRINTF(("Cannot open container %08x.\n", mLastError)) ;
00526         return FALSE ;
00527     }
00528     mLastError = container->OpenEntry(aEntry.mByteCount, aEntry.mEntryId,
00529                                       NULL, 0, &objType, subObject) ;
00530     return HR_SUCCEEDED(mLastError) ;
00531 }
00532 
00533 BOOL nsAbWinHelper::DeleteEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aEntry)
00534 {
00535     nsMapiInterfaceWrapper<LPABCONT> container ;
00536     ULONG objType = 0 ;
00537     SBinary entry ;
00538     SBinaryArray entryArray ;
00539 
00540     mLastError = mAddressBook->OpenEntry(aContainer.mByteCount, aContainer.mEntryId,
00541                                          &IID_IABContainer, MAPI_MODIFY, &objType, 
00542                                          container) ;
00543     if (HR_FAILED(mLastError)) {
00544         PRINTF(("Cannot open container %08x.\n", mLastError)) ;
00545         return FALSE ;
00546     }
00547     entry.cb = aEntry.mByteCount ;
00548     entry.lpb = NS_REINTERPRET_CAST(LPBYTE, aEntry.mEntryId) ;
00549     entryArray.cValues = 1 ;
00550     entryArray.lpbin = &entry ;
00551     mLastError = container->DeleteEntries(&entryArray, 0) ;
00552     if (HR_FAILED(mLastError)) {
00553         PRINTF(("Cannot delete entry %08x.\n", mLastError)) ;
00554         return FALSE ;
00555     }
00556     return TRUE ;
00557 }
00558 
00559 BOOL nsAbWinHelper::SetPropertyUString(const nsMapiEntry& aObject, ULONG aPropertyTag, 
00560                                        const PRUnichar *aValue)
00561 {
00562     SPropValue value ;
00563     nsCAutoString alternativeValue ;
00564 
00565     value.ulPropTag = aPropertyTag ;
00566     if (PROP_TYPE(aPropertyTag) == PT_UNICODE) {
00567         value.Value.lpszW = NS_CONST_CAST(WCHAR *, aValue) ;
00568     }
00569     else if (PROP_TYPE(aPropertyTag) == PT_STRING8) {
00570         alternativeValue.AssignWithConversion(aValue) ;
00571         value.Value.lpszA = NS_CONST_CAST(char *, alternativeValue.get()) ;
00572     }
00573     else {
00574         PRINTF(("Property %08x is not a string.\n", aPropertyTag)) ;
00575         return TRUE ;
00576     }
00577     return SetMAPIProperties(aObject, 1, &value) ;
00578 }
00579 
00580 BOOL nsAbWinHelper::SetPropertiesUString(const nsMapiEntry& aObject, const ULONG *aPropertiesTag,
00581                                          ULONG aNbProperties, nsXPIDLString *aValues) 
00582 {
00583     LPSPropValue values = new SPropValue [aNbProperties] ;
00584     if (!values)
00585         return FALSE ;
00586 
00587     ULONG i = 0 ;
00588     ULONG currentValue = 0 ;
00589     nsCAutoString alternativeValue ;
00590     BOOL retCode = TRUE ;
00591 
00592     for (i = 0 ; i < aNbProperties ; ++ i) {
00593         values [currentValue].ulPropTag = aPropertiesTag [i] ;
00594         if (PROP_TYPE(aPropertiesTag [i]) == PT_UNICODE) {
00595             values [currentValue ++].Value.lpszW = NS_CONST_CAST(WCHAR *, aValues [i].get()) ;
00596         }
00597         else if (PROP_TYPE(aPropertiesTag [i]) == PT_STRING8) {
00598             alternativeValue.AssignWithConversion(aValues [i].get()) ;
00599             char *av = nsCRT::strdup(alternativeValue.get()) ;
00600             if (!av) {
00601                 retCode = FALSE ;
00602                 break ;
00603             }
00604             values [currentValue ++].Value.lpszA = av ;
00605         }
00606     }
00607     if (retCode)
00608         retCode = SetMAPIProperties(aObject, currentValue, values) ;
00609     for (i = 0 ; i < currentValue ; ++ i) {
00610         if (PROP_TYPE(aPropertiesTag [i]) == PT_STRING8) {
00611             nsCRT::free(values [i].Value.lpszA) ;
00612         }
00613     }
00614     delete [] values ;
00615     return retCode ;
00616 }
00617 
00618 BOOL nsAbWinHelper::SetPropertyDate(const nsMapiEntry& aObject, ULONG aPropertyTag, 
00619                                     WORD aYear, WORD aMonth, WORD aDay)
00620 {
00621     SPropValue value ;
00622     
00623     value.ulPropTag = aPropertyTag ;
00624     if (PROP_TYPE(aPropertyTag) == PT_SYSTIME) {
00625         SYSTEMTIME readableTime ;
00626 
00627         readableTime.wYear = aYear ;
00628         readableTime.wMonth = aMonth ;
00629         readableTime.wDay = aDay ;
00630         readableTime.wDayOfWeek = 0 ;
00631         readableTime.wHour = 0 ;
00632         readableTime.wMinute = 0 ;
00633         readableTime.wSecond = 0 ;
00634         readableTime.wMilliseconds = 0 ;
00635         if (SystemTimeToFileTime(&readableTime, &value.Value.ft)) {
00636             return SetMAPIProperties(aObject, 1, &value) ;
00637         }
00638         return TRUE ;
00639     }
00640     return FALSE ;
00641 }
00642 
00643 BOOL nsAbWinHelper::CreateEntry(const nsMapiEntry& aParent, nsMapiEntry& aNewEntry)
00644 {
00645     nsMapiInterfaceWrapper<LPABCONT> container ;
00646     ULONG objType = 0 ;
00647 
00648     mLastError = mAddressBook->OpenEntry(aParent.mByteCount, aParent.mEntryId,
00649                                          &IID_IABContainer, MAPI_MODIFY, &objType,
00650                                          container) ;
00651     if (HR_FAILED(mLastError)) { 
00652         PRINTF(("Cannot open container %08x.\n", mLastError)) ;
00653         return FALSE ;
00654     }
00655     SPropTagArray property ;
00656     LPSPropValue value = NULL ;
00657     ULONG valueCount = 0 ;
00658 
00659     property.cValues = 1 ;
00660     property.aulPropTag [0] = PR_DEF_CREATE_MAILUSER ;
00661     mLastError = container->GetProps(&property, 0, &valueCount, &value) ;
00662     if (HR_FAILED(mLastError) || valueCount != 1) {
00663         PRINTF(("Cannot obtain template %08x.\n", mLastError)) ;
00664         return FALSE ;
00665     }
00666     nsMapiInterfaceWrapper<LPMAPIPROP> newEntry ;
00667 
00668     mLastError = container->CreateEntry(value->Value.bin.cb, 
00669                                         NS_REINTERPRET_CAST(LPENTRYID, value->Value.bin.lpb),
00670                                         CREATE_CHECK_DUP_LOOSE,
00671                                         newEntry) ;
00672     FreeBuffer(value) ;
00673     if (HR_FAILED(mLastError)) {
00674         PRINTF(("Cannot create new entry %08x.\n", mLastError)) ;
00675         return FALSE ;
00676     }
00677     SPropValue displayName ;
00678     LPSPropProblemArray problems = NULL ;
00679     nsAutoString tempName ;
00680 
00681     displayName.ulPropTag = PR_DISPLAY_NAME_W ;
00682     tempName.AssignLiteral("__MailUser__") ;
00683     tempName.AppendInt(mEntryCounter ++) ;
00684     displayName.Value.lpszW = NS_CONST_CAST(WCHAR *, tempName.get()) ;
00685     mLastError = newEntry->SetProps(1, &displayName, &problems) ;
00686     if (HR_FAILED(mLastError)) {
00687         PRINTF(("Cannot set temporary name %08x.\n", mLastError)) ;
00688         return FALSE ;
00689     }
00690     mLastError = newEntry->SaveChanges(KEEP_OPEN_READONLY) ;
00691     if (HR_FAILED(mLastError)) {
00692         PRINTF(("Cannot commit new entry %08x.\n", mLastError)) ;
00693         return FALSE ;
00694     }
00695     property.aulPropTag [0] = PR_ENTRYID ;
00696     mLastError = newEntry->GetProps(&property, 0, &valueCount, &value) ;
00697     if (HR_FAILED(mLastError) || valueCount != 1) {
00698         PRINTF(("Cannot get entry id %08x.\n", mLastError)) ;
00699         return FALSE ;
00700     }
00701     aNewEntry.Assign(value->Value.bin.cb, NS_REINTERPRET_CAST(LPENTRYID, value->Value.bin.lpb)) ;
00702     FreeBuffer(value) ;
00703     return TRUE ;
00704 }
00705 
00706 BOOL nsAbWinHelper::CreateDistList(const nsMapiEntry& aParent, nsMapiEntry& aNewEntry)
00707 {
00708     nsMapiInterfaceWrapper<LPABCONT> container ;
00709     ULONG objType = 0 ;
00710 
00711     mLastError = mAddressBook->OpenEntry(aParent.mByteCount, aParent.mEntryId,
00712                                          &IID_IABContainer, MAPI_MODIFY, &objType,
00713                                          container) ;
00714     if (HR_FAILED(mLastError)) {
00715         PRINTF(("Cannot open container %08x.\n", mLastError)) ;
00716         return FALSE ;
00717     }
00718     SPropTagArray property ;
00719     LPSPropValue value = NULL ;
00720     ULONG valueCount = 0 ;
00721 
00722     property.cValues = 1 ;
00723     property.aulPropTag [0] = PR_DEF_CREATE_DL ;
00724     mLastError = container->GetProps(&property, 0, &valueCount, &value) ;
00725     if (HR_FAILED(mLastError) || valueCount != 1) {
00726         PRINTF(("Cannot obtain template %08x.\n", mLastError)) ;
00727         return FALSE ;
00728     }
00729     nsMapiInterfaceWrapper<LPMAPIPROP> newEntry ;
00730 
00731     mLastError = container->CreateEntry(value->Value.bin.cb, 
00732                                         NS_REINTERPRET_CAST(LPENTRYID, value->Value.bin.lpb),
00733                                         CREATE_CHECK_DUP_LOOSE,
00734                                         newEntry) ;
00735     FreeBuffer(value) ;
00736     if (HR_FAILED(mLastError)) {
00737         PRINTF(("Cannot create new entry %08x.\n", mLastError)) ;
00738         return FALSE ;
00739     }
00740     SPropValue displayName ;
00741     LPSPropProblemArray problems = NULL ;
00742     nsAutoString tempName ;
00743 
00744     displayName.ulPropTag = PR_DISPLAY_NAME_W ;
00745     tempName.AssignLiteral("__MailList__") ;
00746     tempName.AppendInt(mEntryCounter ++) ;
00747     displayName.Value.lpszW = NS_CONST_CAST(WCHAR *, tempName.get()) ;
00748     mLastError = newEntry->SetProps(1, &displayName, &problems) ;
00749     if (HR_FAILED(mLastError)) {
00750         PRINTF(("Cannot set temporary name %08x.\n", mLastError)) ;
00751         return FALSE ;
00752     }
00753     mLastError = newEntry->SaveChanges(KEEP_OPEN_READONLY) ;
00754     if (HR_FAILED(mLastError)) {
00755         PRINTF(("Cannot commit new entry %08x.\n", mLastError)) ;
00756         return FALSE ;
00757     }
00758     property.aulPropTag [0] = PR_ENTRYID ;
00759     mLastError = newEntry->GetProps(&property, 0, &valueCount, &value) ;
00760     if (HR_FAILED(mLastError) || valueCount != 1) {
00761         PRINTF(("Cannot get entry id %08x.\n", mLastError)) ;
00762         return FALSE ;
00763     }
00764     aNewEntry.Assign(value->Value.bin.cb, 
00765                      NS_REINTERPRET_CAST(LPENTRYID, value->Value.bin.lpb)) ;
00766     FreeBuffer(value) ;
00767     return TRUE ;
00768 }
00769 
00770 BOOL nsAbWinHelper::CopyEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aSource,
00771                               nsMapiEntry& aTarget)
00772 {
00773     nsMapiInterfaceWrapper<LPABCONT> container ;
00774     ULONG objType = 0 ;
00775 
00776     mLastError = mAddressBook->OpenEntry(aContainer.mByteCount, aContainer.mEntryId,
00777                                          &IID_IABContainer, MAPI_MODIFY, &objType,
00778                                          container) ;
00779     if (HR_FAILED(mLastError)) { 
00780         PRINTF(("Cannot open container %08x.\n", mLastError)) ;
00781         return FALSE ;
00782     }
00783     nsMapiInterfaceWrapper<LPMAPIPROP> newEntry ;
00784 
00785     mLastError = container->CreateEntry(aSource.mByteCount, aSource.mEntryId,
00786                                         CREATE_CHECK_DUP_LOOSE, newEntry) ;
00787     if (HR_FAILED(mLastError)) {
00788         PRINTF(("Cannot create new entry %08x.\n", mLastError)) ;
00789         return FALSE ;
00790     }
00791     mLastError = newEntry->SaveChanges(KEEP_OPEN_READONLY) ;
00792     if (HR_FAILED(mLastError)) {
00793         PRINTF(("Cannot commit new entry %08x.\n", mLastError)) ;
00794         return FALSE ;
00795     }
00796     SPropTagArray property ;
00797     LPSPropValue value = NULL ;
00798     ULONG valueCount = 0 ;
00799     
00800     property.cValues = 1 ;
00801     property.aulPropTag [0] = PR_ENTRYID ;
00802     mLastError = newEntry->GetProps(&property, 0, &valueCount, &value) ;
00803     if (HR_FAILED(mLastError) || valueCount != 1) {
00804         PRINTF(("Cannot get entry id %08x.\n", mLastError)) ;
00805         return FALSE ;
00806     }
00807     aTarget.Assign(value->Value.bin.cb, 
00808                    NS_REINTERPRET_CAST(LPENTRYID, value->Value.bin.lpb)) ;
00809     FreeBuffer(value) ;
00810     return TRUE ;
00811 }
00812 
00813 BOOL nsAbWinHelper::GetDefaultContainer(nsMapiEntry& aContainer)
00814 {
00815     LPENTRYID entryId = NULL ; 
00816     ULONG byteCount = 0 ;
00817 
00818     mLastError = mAddressBook->GetPAB(&byteCount, &entryId) ;
00819     if (HR_FAILED(mLastError)) {
00820         PRINTF(("Cannot get PAB %08x.\n", mLastError)) ;
00821         return FALSE ;
00822     }
00823     aContainer.Assign(byteCount, entryId) ;
00824     FreeBuffer(entryId) ;
00825     return TRUE ;
00826 }
00827 
00828 enum
00829 {
00830     ContentsColumnEntryId = 0,
00831     ContentsColumnObjectType,
00832     ContentsColumnsSize
00833 } ;
00834 
00835 static const SizedSPropTagArray(ContentsColumnsSize, ContentsColumns) =
00836 {
00837     ContentsColumnsSize,
00838     {
00839         PR_ENTRYID,
00840         PR_OBJECT_TYPE
00841     }
00842 } ;
00843 
00844 BOOL nsAbWinHelper::GetContents(const nsMapiEntry& aParent, LPSRestriction aRestriction,
00845                                 nsMapiEntry **aList, ULONG& aNbElements, ULONG aMapiType)
00846 {
00847     if (aList != NULL) { *aList = NULL ; }
00848     aNbElements = 0 ;
00849     nsMapiInterfaceWrapper<LPMAPICONTAINER> parent ;
00850     nsMapiInterfaceWrapper<LPMAPITABLE> contents ;
00851     ULONG objType = 0 ;
00852     ULONG rowCount = 0 ;
00853 
00854     mLastError = mAddressBook->OpenEntry(aParent.mByteCount, aParent.mEntryId, 
00855                                          &IID_IMAPIContainer, 0, &objType, 
00856                                          parent) ;
00857     if (HR_FAILED(mLastError)) {
00858         PRINTF(("Cannot open parent %08x.\n", mLastError)) ;
00859         return FALSE ; 
00860     }
00861     // Here, flags for WAB and MAPI could be different, so this works
00862     // only as long as we don't want to use any flag in GetContentsTable
00863     mLastError = parent->GetContentsTable(0, contents) ;
00864     if (HR_FAILED(mLastError)) {
00865         PRINTF(("Cannot get contents %08x.\n", mLastError)) ;
00866         return FALSE ; 
00867     }
00868     if (aRestriction != NULL) {
00869         mLastError = contents->Restrict(aRestriction, 0) ;
00870         if (HR_FAILED(mLastError)) {
00871             PRINTF(("Cannot set restriction %08x.\n", mLastError)) ;
00872             return FALSE ;
00873         }
00874     }
00875     mLastError = contents->SetColumns((LPSPropTagArray) &ContentsColumns, 0) ;
00876     if (HR_FAILED(mLastError)) {
00877         PRINTF(("Cannot set columns %08x.\n", mLastError)) ;
00878         return FALSE ;
00879     }
00880     mLastError = contents->GetRowCount(0, &rowCount) ;
00881     if (HR_FAILED(mLastError)) {
00882         PRINTF(("Cannot get result count %08x.\n", mLastError)) ;
00883         return FALSE ;
00884     }
00885     if (aList != NULL) { *aList = new nsMapiEntry [rowCount] ; }
00886     aNbElements = 0 ;
00887     do {
00888         LPSRowSet rowSet = NULL ;
00889         
00890         rowCount = 0 ;
00891         mLastError = contents->QueryRows(1, 0, &rowSet) ;
00892         if (HR_FAILED(mLastError)) {
00893             PRINTF(("Cannot query rows %08x.\n", mLastError)) ;
00894             return FALSE ;
00895         }
00896         rowCount = rowSet->cRows ;
00897         if (rowCount > 0 &&
00898             (aMapiType == 0 ||
00899             rowSet->aRow->lpProps[ContentsColumnObjectType].Value.ul == aMapiType)) {
00900             if (aList != NULL) {
00901                 nsMapiEntry& current = (*aList) [aNbElements] ;
00902                 SPropValue& currentValue = rowSet->aRow->lpProps[ContentsColumnEntryId] ;
00903                 
00904                 current.Assign(currentValue.Value.bin.cb,
00905                     NS_REINTERPRET_CAST(LPENTRYID, currentValue.Value.bin.lpb)) ;
00906             }
00907             ++ aNbElements ;
00908         }
00909         MyFreeProws(rowSet) ;
00910     } while (rowCount > 0) ;
00911     return TRUE ;
00912 }
00913 
00914 BOOL nsAbWinHelper::GetMAPIProperties(const nsMapiEntry& aObject, const ULONG *aPropertyTags, 
00915                                       ULONG aNbProperties, LPSPropValue& aValue, 
00916                                       ULONG& aValueCount)
00917 {
00918     nsMapiInterfaceWrapper<LPMAPIPROP> object ;
00919     ULONG objType = 0 ;
00920     LPSPropTagArray properties = NULL ;
00921     ULONG i = 0 ;
00922     
00923     mLastError = mAddressBook->OpenEntry(aObject.mByteCount, aObject.mEntryId,
00924                                          &IID_IMAPIProp, 0, &objType, 
00925                                          object) ;
00926     if (HR_FAILED(mLastError)) { 
00927         PRINTF(("Cannot open entry %08x.\n", mLastError)) ;
00928         return FALSE ; 
00929     }
00930     AllocateBuffer(CbNewSPropTagArray(aNbProperties), 
00931                    NS_REINTERPRET_CAST(void **, &properties)) ;
00932     properties->cValues = aNbProperties ;
00933     for (i = 0 ; i < aNbProperties ; ++ i) {
00934         properties->aulPropTag [i] = aPropertyTags [i] ;
00935     }
00936     mLastError = object->GetProps(properties, 0, &aValueCount, &aValue) ;
00937     FreeBuffer(properties) ;
00938     if (HR_FAILED(mLastError)) {
00939         PRINTF(("Cannot get props %08x.\n", mLastError)) ;
00940     }
00941     return HR_SUCCEEDED(mLastError) ;
00942 }
00943 
00944 BOOL nsAbWinHelper::SetMAPIProperties(const nsMapiEntry& aObject, ULONG aNbProperties, 
00945                                       const LPSPropValue& aValues)
00946 {
00947     nsMapiInterfaceWrapper<LPMAPIPROP> object ;
00948     ULONG objType = 0 ;
00949     LPSPropProblemArray problems = NULL ;
00950 
00951     mLastError = mAddressBook->OpenEntry(aObject.mByteCount, aObject.mEntryId,
00952                                          &IID_IMAPIProp, MAPI_MODIFY, &objType, 
00953                                          object) ;
00954     if (HR_FAILED(mLastError)) {
00955         PRINTF(("Cannot open entry %08x.\n", mLastError)) ;
00956         return FALSE ;
00957     }
00958     mLastError = object->SetProps(aNbProperties, aValues, &problems) ;
00959     if (HR_FAILED(mLastError)) {
00960         PRINTF(("Cannot update the object %08x.\n", mLastError)) ;
00961         return FALSE ;
00962     }
00963     if (problems != NULL) {
00964         for (ULONG i = 0 ; i < problems->cProblem ; ++ i) {
00965             PRINTF(("Problem %d: index %d code %08x.\n", i, 
00966                 problems->aProblem [i].ulIndex, 
00967                 problems->aProblem [i].scode)) ;
00968         }
00969     }
00970     mLastError = object->SaveChanges(0) ;
00971     if (HR_FAILED(mLastError)) {
00972         PRINTF(("Cannot commit changes %08x.\n", mLastError)) ;
00973     }
00974     return HR_SUCCEEDED(mLastError) ;
00975 }
00976 
00977 void nsAbWinHelper::MyFreeProws(LPSRowSet aRowset)
00978 {
00979     if (aRowset == NULL) { return ; }
00980     ULONG i = 0 ; 
00981 
00982     for (i = 0 ; i < aRowset->cRows ; ++ i) {
00983         FreeBuffer(aRowset->aRow [i].lpProps) ;
00984     }
00985     FreeBuffer(aRowset) ;
00986 }
00987 
00988 nsAbWinHelperGuard::nsAbWinHelperGuard(PRUint32 aType)
00989 : mHelper(NULL) 
00990 {
00991     switch(aType) {
00992     case nsAbWinType_Outlook: mHelper = new nsMapiAddressBook ; break ;
00993     case nsAbWinType_OutlookExp: mHelper = new nsWabAddressBook ; break ;
00994     default: break ;
00995     }
00996 }
00997 
00998 nsAbWinHelperGuard::~nsAbWinHelperGuard(void)
00999 {
01000     delete mHelper ;
01001 }
01002 
01003 const char *kOutlookDirectoryScheme = "moz-aboutlookdirectory://" ;
01004 const int kOutlookDirSchemeLength = 21 ;
01005 const char *kOutlookStub = "op/" ;
01006 const int kOutlookStubLength = 3 ;
01007 const char *kOutlookExpStub = "oe/" ;
01008 const int kOutlookExpStubLength = 3 ;
01009 const char *kOutlookCardScheme = "moz-aboutlookcard://" ;
01010 const int kOutlookCardSchemeLength = 16 ;
01011 
01012 nsAbWinType getAbWinType(const char *aScheme, const char *aUri, nsCString& aStub, nsCString& aEntry) 
01013 {
01014     aStub.Truncate() ;
01015     aEntry.Truncate() ;
01016     PRUint32 schemeLength = strlen(aScheme) ;
01017 
01018     if (nsCRT::strncmp(aUri, aScheme, schemeLength) == 0) {
01019         if (nsCRT::strncmp(aUri + schemeLength, kOutlookStub, kOutlookStubLength) == 0) {
01020             aEntry = aUri + schemeLength + kOutlookStubLength ;
01021             aStub = kOutlookStub ;
01022             return nsAbWinType_Outlook ;
01023         }
01024         if (nsCRT::strncmp(aUri + schemeLength, kOutlookExpStub, kOutlookExpStubLength) == 0) {
01025             aEntry = aUri + schemeLength + kOutlookExpStubLength ;
01026             aStub = kOutlookExpStub ;
01027             return nsAbWinType_OutlookExp ;
01028         }
01029     }
01030     return nsAbWinType_Unknown ;   
01031 }
01032 
01033 void buildAbWinUri(const char *aScheme, PRUint32 aType, nsCString& aUri)
01034 {
01035     aUri.Assign(aScheme) ;
01036     switch(aType) {
01037     case nsAbWinType_Outlook: aUri.Append(kOutlookStub) ; break ; 
01038     case nsAbWinType_OutlookExp: aUri.Append(kOutlookExpStub) ; break ;
01039     default: aUri.Assign("") ;
01040     }
01041 }
01042 
01043 
01044 
01045 
01046 
01047