/*********************************************************************** * * ABP.C * * * The Microsoft At Work Fax Address Book Provider. * This file contains the routines that handle the ABPJump table. * * The following routines are implemented in this file: * * ABProviderInit * ABP_QueryInterface * ABP_Release * ABP_Shutdown * ABP_Logon * * ServiceEntry * HrOpenSingleProvider * * RemoveLogonObject * FindLogonObject * ScLoadString * * Globals defined in this file: * * Copyright 1992, 1993 Microsoft Corporation. All Rights Reserved. * * Revision History: * * When Who What * -------- ------------------ --------------------------------------- * 1.1.94 MAPI Original source from MAPI sample AB Provider * 1.27.94 Yoram Yaacovi Modifications to make it an At Work Fax ABP * 3.5.94 Yoram Yaacovi Update to MAPI build 154 * 4.1.94 Yoram Yaacovi Update to MAPI and sample AB build 157 * 8.1.94 Yoram Yaacovi Update to MAPI and sample AB build 306 * ***********************************************************************/ #define _FAXAB_ABP #include "faxab.h" /* * Prototypes for the functions in this file, most of which I return * in the jump table returned from ABProviderInit(). */ ABPROVIDERINIT ABProviderInit; MSGSERVICEENTRY FABServiceEntry; HRESULT HrOpenSingleProvider( LPPROVIDERADMIN lpAdminProviders, LPPROFSECT FAR *lppProfSect ); void LoadIniParams(void); /* * The jump table returned from ABProviderInit(). */ ABP_Vtbl vtblABP = { ABP_QueryInterface, (ABP_AddRef_METHOD *) ROOT_AddRef, ABP_Release, ABP_Shutdown, ABP_Logon }; /************************************************************************* * - ABProviderInit - * Initializes this provider. Returns a jump table that contains the * addresses of the rest of the functions. * */ HRESULT STDMAPIINITCALLTYPE ABProviderInit ( HINSTANCE hLibrary, LPMALLOC lpMalloc, LPALLOCATEBUFFER lpAllocBuff, LPALLOCATEMORE lpAllocMore, LPFREEBUFFER lpFreeBuff, ULONG ulFlags, ULONG ulMAPIVersion, ULONG FAR * lpulABVersion, LPABPROVIDER FAR * lppABProvider) { HRESULT hResult = hrSuccess; LPABP lpABP; SCODE scode; //DebugBreak(); DebugTrace("AWFXAB32(ABProviderInit): entering\n"); // Get registry settings LoadIniParams(); #ifdef DEBUG if (fDebugTrap) DebugBreak(); #endif /* * Check the version */ if (ulMAPIVersion < CURRENT_SPI_VERSION) { /* * MAPI's version is too old. */ /* * See if they understand my version */ *lpulABVersion = CURRENT_SPI_VERSION; DebugTraceSc(ABProviderInit, MAPI_E_VERSION); return ResultFromScode(MAPI_E_VERSION); } /* * Allocate memory for this Init Object */ scode = lpAllocBuff (SIZEOF(ABP), &lpABP); if (FAILED(scode)) { /* * Out of memory */ DebugTraceSc(ABProviderInit, scode); return ResultFromScode(scode); } /* * Initialize the idle engine that MAPI supplies. This is most useful * when browsing the .FAB file. See ABCTBLn.C. */ if (MAPIInitIdle( NULL )==-1) { hResult = ResultFromScode(E_FAIL); goto err; } /* * Hold on to the lpMalloc */ if (lpMalloc) lpMalloc->lpVtbl->AddRef(lpMalloc); lpABP->lpVtbl = &vtblABP; lpABP->lcInit = 1; lpABP->hLibrary = hLibrary; lpABP->lpMalloc = lpMalloc; lpABP->lpAllocBuff = lpAllocBuff; lpABP->lpAllocMore = lpAllocMore; lpABP->lpFreeBuff = lpFreeBuff; lpABP->lpObjectList= NULL; InitializeCriticalSection(&lpABP->cs); *lppABProvider = (LPABPROVIDER)lpABP; *lpulABVersion = CURRENT_SPI_VERSION; /* * Get our Locale Identifier */ lcidUser = GetUserDefaultLCID(); out: DebugTraceResult(ABProviderInit, hResult); return hResult; err: lpFreeBuff(lpABP); goto out; } /* * The Init Object's methods implementation */ /********************************************************************** - ABP_QueryInterface - * Supports QI'ing to IUnknown and IABProvider * * Note that for all the methods of IABProvider that parameter validation * is unnecessary. This is because MAPI is handling all the parameters * being passed in. * At best you can assert your parameters. */ STDMETHODIMP ABP_QueryInterface (LPABP lpABP, REFIID lpiid, LPVOID *ppvObj) { DebugTrace("AWFXAB32(ABP_QueryInterface): entering\n"); /* See if the requested interface is one of ours */ if ( memcmp (lpiid, &IID_IUnknown, SIZEOF (IID)) && memcmp (lpiid, &IID_IABProvider, SIZEOF (IID)) ) { *ppvObj = NULL; /* OLE requires zeroing [out] parameter on error */ DebugTraceSc(ABP_QueryInterface, E_NOINTERFACE); return ResultFromScode (E_NOINTERFACE); } /* We'll do this one. Bump the usage count and return a new pointer. */ EnterCriticalSection(&lpABP->cs); ++lpABP->lcInit; LeaveCriticalSection(&lpABP->cs); *ppvObj = lpABP; return hrSuccess; } /* * Use ROOTs AddRef */ /************************************************************************* * - ABP_Release - * Releases and cleans up this object */ STDMETHODIMP_(ULONG) ABP_Release (LPABP lpABP) { long lcInit; DebugTrace("AWFXAB32(ABP_Release): entering\n"); EnterCriticalSection(&lpABP->cs); lcInit = --lpABP->lcInit; LeaveCriticalSection(&lpABP->cs); if (lcInit == 0) { DeleteCriticalSection(&lpABP->cs); lpABP->lpVtbl = NULL; lpABP->lpFreeBuff(lpABP); return (0); } return lcInit; } /********************************************************************** - ABP_Shutdown - * Informs this provider that MAPI is done with it. * * */ STDMETHODIMP ABP_Shutdown (LPABP lpABP, ULONG FAR *lpulFlags) { DebugTrace("AWFXAB32(ABP_Shutdown): entering\n"); MAPIDeinitIdle(); if (lpABP->lpMalloc) { lpABP->lpMalloc->lpVtbl->Release(lpABP->lpMalloc); lpABP->lpMalloc = NULL; } return hrSuccess; } /************************************************************************* * - ABP_Logon - * Create a logon object and return it to MAPI. * */ /* * The PropTagArray used to retrieve logon properties */ enum { ivallogonPR_FAB_FILE=0, ivallogonPR_FAB_UID, cvallogonMax }; static const SizedSPropTagArray(cvallogonMax, tagaFABLogonProps) = { cvallogonMax, { PR_FAB_FILE_A, PR_FAB_UID } }; STDMETHODIMP ABP_Logon( LPABP lpABP, LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG ulFlags, ULONG FAR * lpulpcbSecurity, LPBYTE FAR * lppbSecurity, LPMAPIERROR FAR * lppMapiError, LPABLOGON FAR * lppABPLogon ) { LPABLOGON lpABLogon = NULL; HRESULT hResult = hrSuccess; SCODE scode; LPPROFSECT lpProfSect = NULL; LPSPropValue lpsPropVal = NULL; ULONG cValues = 0; TCHAR szFileName[MAX_PATH]; LPTSTR lpstrT = NULL; BOOL fUINeeded; BOOL fNeedMAPIUID = FALSE; MAPIUID muidID; LPOBJECTLIST lpObjectList; LPTSTR lpszAppName=NULL; #ifdef UNICODE CHAR szAnsiFileName[ MAX_PATH ]; #endif #ifdef EXTENDED_DEBUG MessageBox((HWND) ulUIParam, TEXT("ABP_Logon: entering"), TEXT("awfxab debug message"), MB_OK); #endif DebugTrace("AWFXAB32(ABP_Logon): entering\n"); szFileName[0] = TEXT('\0'); *lppMapiError = NULL; if ( ulFlags & MAPI_UNICODE ) { DebugTraceArg( ABP_Logon, "Bad Character width" ); return ResultFromScode( MAPI_E_BAD_CHARWIDTH ); } /* * Get the name of my browse file from the profile section */ /* Open the section for my provider */ hResult = lpMAPISup->lpVtbl->OpenProfileSection( lpMAPISup, NULL, MAPI_MODIFY, &lpProfSect ); if (HR_FAILED(hResult)) goto out; /* Get the property containing the Fax AB file name. */ hResult = lpProfSect->lpVtbl->GetProps( lpProfSect, (LPSPropTagArray)&tagaFABLogonProps, 0, // ANSI &cValues, &lpsPropVal ); if (HR_FAILED(hResult)) goto out; #ifdef DEBUG /* The only expected return code is MAPI_E_NOT_FOUND. */ if (hResult != hrSuccess) { if (GetScode (hResult) != MAPI_W_ERRORS_RETURNED) { DebugTrace("AWFXAB32(ABP_Logon): got unexpected hResult: "); DebugTraceResult(ProfileGetProps, hResult); } else if (lpsPropVal[0].Value.err != MAPI_E_NOT_FOUND) { DebugTrace("AWFXAB32(ABP_Logon): got unexpected scode: "); DebugTraceSc(ProfileGetProps, lpsPropVal[0].Value.err); } } #endif /* Ignore warnings from reading the property. */ hResult = hrSuccess; /* copy the Fax Address Book file name */ if (lpsPropVal[0].ulPropTag==PR_FAB_FILE_A) { UINT cch = lstrlenA(lpsPropVal[0].Value.lpszA); if (cch >= MAX_PATH) cch = MAX_PATH-1; if (cch) #ifdef UNICODE MultiByteToWideChar( CP_ACP, 0, lpsPropVal[0].Value.lpszA, -1, szFileName, ARRAYSIZE(szFileName) ); #else memcpy(szFileName, lpsPropVal[0].Value.lpszA, cch); #endif szFileName[cch] = TEXT('\0'); } else { DebugTrace("AWFXAB32(ABP_Logon): PR_FAB_FILE not found\n"); } /* copy the fab uid */ if (lpsPropVal[1].ulPropTag==PR_FAB_UID) { memcpy(&muidID,lpsPropVal[1].Value.bin.lpb, SIZEOF(MAPIUID)); } else { DebugTrace("AWFXAB32(ABP_Logon): PR_FAB_UID not found\n"); fNeedMAPIUID = TRUE; } /* Discard GetProps() return data, if any. */ lpABP->lpFreeBuff (lpsPropVal); /* * (UI needed unless the file name is good and file exists.) * * in Fax, the AB is not exposed, so there is never a UI * If you insist on using a fax AB, you can set the name in the registry */ fUINeeded = TRUE; if (szFileName[0] != 0) { /* Verify the file exists. */ HANDLE hFile = CreateFile ( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { CloseHandle (hFile); fUINeeded = FALSE; } } // Am I allowed to bring up UI ? if (ulFlags & AB_NO_DIALOG) fUINeeded = FALSE; // If the registry flag does not allow to expose the fax AB UI, don't allow it, no // matter what happened earlier if (!fExposeFaxAB) fUINeeded = FALSE; /* * if the sab file name was not found in the profile or the sab file * does not exist we have to get the user to pick another one and * save back into the profile */ if (fUINeeded) { OPENFILENAME openfilename; SPropValue sProp[1]; /* * Can't bring up UI unless the client allows it */ if (ulFlags & AB_NO_DIALOG) { hResult = ResultFromScode (MAPI_E_LOGON_FAILED); goto out; } /* * Get the user to select a file */ openfilename.lStructSize = SIZEOF(OPENFILENAME); openfilename.hwndOwner = (HWND) ulUIParam; openfilename.hInstance = 0; /* Ignored */ openfilename.lpstrFilter = TEXT("Microsoft Fax Address Book files\0*.fab\0\0"); openfilename.lpstrCustomFilter = NULL; openfilename.nMaxCustFilter = 0; openfilename.nFilterIndex = 0; openfilename.lpstrFile = szFileName; openfilename.nMaxFile = MAX_PATH; openfilename.lpstrFileTitle = NULL; openfilename.nMaxFileTitle = 0; openfilename.lpstrInitialDir = NULL; openfilename.lpstrTitle = TEXT("Microsoft Fax Address Book"); openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; openfilename.nFileOffset = 0; openfilename.nFileExtension = 0; openfilename.lpstrDefExt = TEXT("fab"); openfilename.lCustData = 0; openfilename.lpfnHook = NULL; openfilename.lpTemplateName = NULL; /* * Call up the common dialog */ if (!GetOpenFileName (&openfilename)) { #ifdef DEBUG DWORD dwT; dwT = CommDlgExtendedError(); #endif /* DEBUG */ // next two lines not needed for fax AB. an empty fax AB is valid. // hResult = ResultFromScode (MAPI_E_LOGON_FAILED); // goto out; } /* * Set the fab file name property value */ sProp[0].ulPropTag = PR_FAB_FILE_A; #ifdef UNICODE WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szAnsiFileName, ARRAYSIZE(szAnsiFileName), NULL, NULL ); sProp[0].Value.lpszA = szAnsiFileName; #else sProp[0].Value.lpszA = szFileName; #endif /* * Save the fab file into the profile */ if (hResult = lpProfSect->lpVtbl->SetProps(lpProfSect, 1, sProp, NULL)) { /* * Do nothing... So I couldn't save it away this time... */ DebugTraceResult("ABP_Logon got unexpected result on SetProps\n", hResult); hResult = hrSuccess; } } // if (fUINeeded) /* * if the uid was not found we have to generate a new muid for the * PR_SAB_ID property and save it back into the profile */ if (fNeedMAPIUID) { SPropValue sProp[1]; /* * Get a new fab uid */ hResult=lpMAPISup->lpVtbl->NewUID(lpMAPISup,&muidID); if (HR_FAILED(hResult)) { DebugTraceResult(NewUID, hResult); goto out; } /* * Set the fab uid property value */ sProp[1].ulPropTag = PR_FAB_UID; sProp[1].Value.bin.cb = SIZEOF(MAPIUID); sProp[1].Value.bin.lpb = (LPBYTE)&muidID; /* * Save the sab uid into the profile */ if (hResult = lpProfSect->lpVtbl->SetProps(lpProfSect, 1, sProp, NULL)) { /* * Do nothing... So I couldn't save it away this time... */ DebugTraceResult("ABP_Logon got unexpected result on SetProps\n", hResult); hResult = hrSuccess; } } // if (fNeedMAPIUID) /* * Allocate space for keeping the file name in the ABLogon object */ if (scode = lpABP->lpAllocBuff((lstrlen(szFileName)+1)*SIZEOF(TCHAR), &lpstrT)) { hResult = ResultFromScode (scode); goto out; } lstrcpy (lpstrT, szFileName); hResult = HrNewABLogon( &lpABLogon, (LPABPROVIDER) lpABP, lpMAPISup, lpstrT, &muidID, lpABP->hLibrary, lpABP->lpAllocBuff, lpABP->lpAllocMore, lpABP->lpFreeBuff, lpABP->lpMalloc ); if (HR_FAILED(hResult)) { goto out; } /* * Allocate space for another object list item */ if (scode = lpABP->lpAllocBuff( sizeof(OBJECTLIST), &lpObjectList)) { hResult = ResultFromScode(scode); goto out; } /* * add logon object to list */ /* Get the Critical Section */ EnterCriticalSection(&lpABP->cs); /* add logon object to begining of providers object list */ lpObjectList->lpObject = (LPVOID) lpABLogon; lpObjectList->lppNext = lpABP->lpObjectList; /* insert new logon object into the head of the providers object list */ lpABP->lpObjectList = lpObjectList; /* leave critical section */ LeaveCriticalSection(&lpABP->cs); /* * Register my MAPIUID for this provider, * but do not allow an error from setting the * MAPIUID to cause failure to Logon. */ (void)lpMAPISup->lpVtbl->SetProviderUID(lpMAPISup, (LPMAPIUID) &muidABMAWF, 0); #ifdef DO_WE_REALLY_NEED_TAPI /* * TAPI * * everything seems OK. get TAPI initialized */ scode = ScLoadString( IDS_APP_NAME, MAX_PATH, lpABP->lpAllocBuff, lpABP->hLibrary, &lpszAppName ); InitTAPI(lpABP->hLibrary, (HWND) ulUIParam, lpszAppName); // Make sure we have the required location information handy // bring up mini-dial helper if not InitLocationParams((HWND) ulUIParam); #endif lpABP->lpFreeBuff(lpszAppName); // return the object to the caller *lppABPLogon = lpABLogon; out: if (lpProfSect) lpProfSect->lpVtbl->Release(lpProfSect); if (hResult) { lpABP->lpFreeBuff(lpstrT); Assert(lpABLogon == NULL); /* Verify we don't return warnings at this time. */ Assert(HR_FAILED(hResult)); } DebugTraceResult(ABP_Logon, hResult); return hResult; } /************************************************************************* - - RemoveLogonObject - * Removes a particular logon object from the list of logon objects * that's kept track of in the IABProvider object */ void RemoveLogonObject( LPABPROVIDER lpABProvider, LPVOID lpvABLogon, LPFREEBUFFER lpFreeBuff ) { LPOBJECTLIST *lppObjectList; LPOBJECTLIST lpObjectListT; LPABP lpABP = (LPABP) lpABProvider; #if defined DEBUG BOOL fFound = FALSE; #endif /* Get the Critical Section */ EnterCriticalSection(&lpABP->cs); /* * remove this logon object from the provider init objects list * of logon objects */ lppObjectList = &(lpABP->lpObjectList); while (*lppObjectList) { /* is this the logon object? */ if ((*lppObjectList)->lpObject == lpvABLogon) { /* save next list item */ lpObjectListT = (*lppObjectList)->lppNext; /* free the object list item */ lpFreeBuff(*lppObjectList); /* delete object from the list */ *lppObjectList = lpObjectListT; #if defined DEBUG fFound = TRUE; #endif break; } lppObjectList = &(*lppObjectList)->lppNext; } /* leave critical section */ LeaveCriticalSection(&lpABP->cs); #if defined DEBUG AssertSz(fFound, "Logon object not found on providers object list"); #endif return; } /************************************************************************* - - FindLogonObject - * Finds a particular logon object by its muid. */ void FindLogonObject( LPABPROVIDER lpABProvider, LPMAPIUID lpMuidToFind, LPABLOGON * lppABLogon ) { LPABP lpABP = (LPABP) lpABProvider; LPABLOGON lpABLogonT = NULL; LPOBJECTLIST lpObjectList = NULL; LPMAPIUID lpMuidLogon = NULL; Assert(!IsBadReadPtr(lpABP, SIZEOF(ABP))); Assert(!IsBadReadPtr(lpMuidToFind, SIZEOF(MAPIUID))); Assert(!IsBadReadPtr(lppABLogon, SIZEOF(LPABLOGON))); /* Get the Critical Section */ EnterCriticalSection(&lpABP->cs); *lppABLogon = NULL; for (lpObjectList = lpABP->lpObjectList; lpObjectList; lpObjectList = lpObjectList->lppNext) { lpABLogonT = (LPABLOGON) lpObjectList->lpObject; lpMuidLogon = LpMuidFromLogon(lpABLogonT); if (memcmp((LPVOID) lpMuidLogon, (LPVOID) lpMuidToFind, SIZEOF(MAPIUID)) == 0) { *lppABLogon = lpABLogonT; break; } } /* leave critical section */ LeaveCriticalSection(&lpABP->cs); } /************************************************************************* * - FABServiceEntry - * This funtion is used by MAPI to configure the Sample Address Book. * It's a lot like ABP_Logon, except that it doesn't return a logon object * and it can be passed in its configuration information (as defined in * smpab.h) from MAPI so that no UI is required. * * lppMapiError a pointer to a MAPI error structure which allows * the provider to return extended error info to MAPI */ STDAPI FABServiceEntry( HINSTANCE hInstance, LPMALLOC lpMalloc, LPMAPISUP lpMAPISup, ULONG ulUIParam, ULONG ulFlags, ULONG ulContext, ULONG cValues, LPSPropValue lpProps, LPPROVIDERADMIN lpAdminProviders, LPMAPIERROR FAR *lppMapiError) { OPENFILENAME openfilename; TCHAR szFileName[MAX_PATH]; HRESULT hResult=hrSuccess; SPropValue sProp[cvallogonMax]; LPSPropValue lpsPropVal = NULL; ULONG ulCount = 0; LPALLOCATEBUFFER lpAllocBuff; LPALLOCATEMORE lpAllocMore; LPFREEBUFFER lpFreeBuff; MAPIUID muid; LPPROFSECT lpProf = NULL; BOOL fFABFound=FALSE; // No fab file name yet BOOL fUIDFound=FALSE; // No fab uid yet BOOL fNeedMAPIUID = FALSE; ULONG uliProp; #ifdef UNICODE CHAR szAnsiFileName[ MAX_PATH ]; #endif #ifdef EXTENDED_DEBUG TCHAR szTempBuf[256]; #endif //DebugBreak(); DebugTrace("AWFXAB32(ServiceEntry): entering\n"); // Get registry settings LoadIniParams(); #ifdef DEBUG if (fDebugTrap) DebugBreak(); #endif /* * Parameter validation */ // check the support object if (IsBadReadPtr(lpMAPISup, SIZEOF(LPMAPISUP))) { DebugTraceSc(ServiceEntry, E_INVALIDARG); return ResultFromScode(E_INVALIDARG); } if ( ulFlags & MAPI_UNICODE ) { DebugTraceArg( ServiceEntry, "Bad character width" ); return ResultFromScode( MAPI_E_BAD_CHARWIDTH ); } #ifdef EXTENDED_DEBUG switch (ulContext) { case MSG_SERVICE_DELETE: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_DELETE called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_INSTALL: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_INSTALL called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_UNINSTALL: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_UNINSTALL called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_CREATE: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_CREATE called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_CONFIGURE: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_CONFIGURE called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_PROVIDER_CREATE: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_PROVIDER_CREATE called!"), TEXT("awfxab debug message"), MB_OK); break; case MSG_SERVICE_PROVIDER_DELETE: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry MSG_SERVICE_PROVIDER_DELETE called!"), TEXT("awfxab debug message"), MB_OK); break; default: MessageBox((HWND) ulUIParam, TEXT("ServiceEntry unknown called!"), TEXT("awfxab debug message"), MB_OK); break; } #endif /* * Check what to do */ if ( ulContext==MSG_SERVICE_DELETE || ulContext==MSG_SERVICE_INSTALL || ulContext==MSG_SERVICE_UNINSTALL ) { return hrSuccess; } // Only supporting MSG_SERVICE_CONFIGURE and MSG_SERVICE_CREATE if ( ulContext!=MSG_SERVICE_CONFIGURE && ulContext!=MSG_SERVICE_CREATE ) { DebugTrace("ServiceEntry unsupported context\n"); return ResultFromScode(MAPI_E_NO_SUPPORT); } /* Get the memory allocation routines we'll be needing. */ hResult = lpMAPISup->lpVtbl->GetMemAllocRoutines( lpMAPISup, &lpAllocBuff, &lpAllocMore, &lpFreeBuff ); if (hResult) { DebugTraceResult (MAPISUP::GetMemAllocRoutines, hResult); goto out; } /* Open the profile section associated with our provider */ hResult = HrOpenSingleProvider(lpAdminProviders, &lpProf); if (hResult) { DebugTrace ("AWFXAB32(ServiceEntry): Unable to open the profile."); goto out; } #ifdef EXTENDED_DEBUG wsprintf (szTempBuf, TEXT("ServiceEntry: HrOpenSingleProvider succeeded. hResult=0x%08lx\n"), (ULONG) hResult); MessageBox( (HWND)ulUIParam, szTempBuf, TEXT("awfxab Debug Message"), MB_ICONINFORMATION ); #endif // No file name for now szFileName[0] = TEXT('\0'); /* * Now looking for the two properties I need: * PR_FAB_FILE * PR_FAB_UID * * they can either be: * 1. in the lpProps passed to ServiceEntry * 2. in my profile section * 3. be requested from the user through a UI */ // see if these properties exist on the profile hResult = lpProf->lpVtbl->GetProps( lpProf, (LPSPropTagArray)&tagaFABLogonProps, ulFlags & MAPI_UNICODE, &ulCount, &lpsPropVal ); // If the GetProps fail, I'm dump some debug messages, but it's OK to continue. // Can still get the props from the ServiceEntry input parameter or from UI if (hResult!=hrSuccess) { #ifdef DEBUG /* The only expected return code is MAPI_E_NOT_FOUND. */ if (GetScode (hResult) != MAPI_W_ERRORS_RETURNED) { DebugTrace("AWFXAB32(ServiceEntry): got unexpected hResult: "); DebugTraceResult(ProfileGetProps, hResult); } else if (lpsPropVal[0].Value.err != MAPI_E_NOT_FOUND) { DebugTrace("AWFXAB32(ServiceEntry): got unexpected scode: "); DebugTraceSc(ProfileGetProps, lpsPropVal[0].Value.err); } #endif /* Ignore errors/warnings from reading the property. */ hResult = hrSuccess; // These two should be false anyway at this point fFABFound = FALSE; fUIDFound = FALSE; } /************************ *** PR_FAB_FILE ****** ************************/ /* * 1. Check the lpProps (cValues) passed to ServiceEntry */ // First, look for the fab file property in the config props that were passed to // ServiceEntry. So I am not really looking at what I got in the above GetProps yet for (uliProp=0; uliProp < cValues; uliProp++) { if (PROP_ID(lpProps[uliProp].ulPropTag)==PROP_ID(PR_FAB_FILE_A)) // This is the fab file property break; } // If the fab file property was found (must be found, isn't it ?) and it has a // non-error value, get the fab filename from it if ((uliProp < cValues) && (PROP_TYPE(lpProps[uliProp].ulPropTag)!=PT_ERROR)) { ULONG cch = lstrlenA(lpProps[uliProp].Value.lpszA); if (cch >= MAX_PATH) cch = MAX_PATH-1; if (cch) #ifdef UNICODE MultiByteToWideChar( CP_ACP, 0, lpProps[uliProp].Value.lpszA, -1, szFileName, ARRAYSIZE(szFileName) ); #else memcpy(szFileName, lpProps[uliProp].Value.LPSZ, (size_t)cch*SIZEOF(TCHAR)); #endif szFileName[cch] = TEXT('\0'); // got my FAB file. Might be "". No need for UI for that fFABFound = TRUE; } /* * 2. Now the properties I got from the profile (if any) */ // no fab file name in the input properties. Look in the profile properties else if ( (PROP_ID(lpsPropVal[0].ulPropTag) == PROP_ID(PR_FAB_FILE_A)) && (PROP_TYPE(lpsPropVal[0].ulPropTag)!= PT_ERROR) ) { ULONG cch = lstrlenA(lpsPropVal[0].Value.lpszA); if (cch >= MAX_PATH) cch = MAX_PATH-1; if (cch) #ifdef UNICODE MultiByteToWideChar( CP_ACP, 0, lpProps[0].Value.lpszA, -1, szFileName, ARRAYSIZE(szFileName) ); #else memcpy(szFileName, lpsPropVal[0].Value.LPSZ, (size_t)cch*SIZEOF(TCHAR)); #endif szFileName[cch] = TEXT('\0'); fFABFound = TRUE; } else { fFABFound = FALSE; } /* * 3. Last resort: UI */ if (fExposeFaxAB) { if (!fFABFound || (ulFlags & UI_SERVICE)) { openfilename.lStructSize = SIZEOF(OPENFILENAME); openfilename.hwndOwner = (HWND) ulUIParam; openfilename.hInstance = 0; /* Ignored */ openfilename.lpstrFilter = TEXT("Microsoft Fax Address Book files\0*.fab\0\0"); openfilename.lpstrCustomFilter = NULL; openfilename.nMaxCustFilter = 0; openfilename.nFilterIndex = 0; openfilename.lpstrFile = szFileName; openfilename.nMaxFile = MAX_PATH; openfilename.lpstrFileTitle = NULL; openfilename.nMaxFileTitle = 0; openfilename.lpstrInitialDir = NULL; openfilename.lpstrTitle = TEXT("Pick a Microsoft Fax Address Book file"); openfilename.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; openfilename.nFileOffset = 0; openfilename.nFileExtension = 0; openfilename.lpstrDefExt = TEXT("fab"); openfilename.lCustData = 0; openfilename.lpfnHook = NULL; openfilename.lpTemplateName = NULL; // This hides the fax address book. define FAXAB_YES to expose it. // No Fax address book, unless it's hardcoded into the profile /* * Call up the common dialog */ if (!GetOpenFileName (&openfilename)) { // user pressed cancel // CHECK: This means we do not have a fab file. Shouldn't I return // some kind of an error ? The SAB doesn't. goto out; } } } /* * Set the file name property */ sProp[ivallogonPR_FAB_FILE].ulPropTag = PR_FAB_FILE_A; #ifdef UNICODE WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szAnsiFileName, ARRAYSIZE(szAnsiFileName), NULL, NULL ); sProp[ivallogonPR_FAB_FILE].Value.lpszA = szAnsiFileName; #else sProp[ivallogonPR_FAB_FILE].Value.lpszA = szFileName; #endif /* if no properties were found then we're configuring for the * first time and so we have to generate a new muid for the * PR_FAB_ID property */ /************************ *** PR_FAB_UID ****** ************************/ /* * 1. Check the lpProps (cValues) passed to ServiceEntry */ for (uliProp=0; uliProp < cValues; uliProp++) { if (PROP_ID(lpProps[uliProp].ulPropTag)==PROP_ID(PR_FAB_UID)) break; } if ( (uliProp < cValues) && (PROP_TYPE(lpProps[uliProp].ulPropTag)!=PT_ERROR)) { memcpy(&muid,lpProps[uliProp].Value.bin.lpb,SIZEOF(MAPIUID)); fUIDFound = TRUE; } /* * 2. Now the properties I got from the profile (if any) */ else if ( (PROP_ID(lpsPropVal[1].ulPropTag) == PROP_ID(PR_FAB_UID)) && (PROP_TYPE(lpsPropVal[1].ulPropTag) != PT_ERROR) ) { memcpy(&muid,lpsPropVal[1].Value.bin.lpb,SIZEOF(MAPIUID)); fUIDFound = TRUE; } else { /* need to generate a uid */ fUIDFound = FALSE; } /* Discard GetProps() return data, if any. */ if (lpsPropVal) lpFreeBuff (lpsPropVal); /* * 3. Last resort: generate a UID */ if (!fUIDFound) { hResult = lpMAPISup->lpVtbl->NewUID(lpMAPISup,&muid); if (HR_FAILED(hResult)) { /* * Can't get a uid so just leave */ goto out; } } /* * Set the id property */ sProp[ivallogonPR_FAB_UID].ulPropTag = PR_FAB_UID; sProp[ivallogonPR_FAB_UID].Value.bin.cb = SIZEOF(MAPIUID); sProp[ivallogonPR_FAB_UID].Value.bin.lpb = (LPBYTE) &muid; /* * Save the file name and the id back into the profile */ hResult=lpProf->lpVtbl->SetProps( lpProf, cvallogonMax, sProp, NULL ); if (HR_FAILED(hResult)) { /* * Do nothing... So I couldn't save it away this time... */ DebugTrace("AWFXAB32(ServiceEntry): could not SetProps in profile\n"); hResult = hrSuccess; } out: if (lpProf) lpProf->lpVtbl->Release(lpProf); DebugTraceResult(ServiceEntry, hResult); return hResult; } /************************************************************************* - HrOpenSingleProvider - * Opens the profile section associated with this provider. * * If the ServiceEntry() function exported from a provider had * more than 1 section associated with it, this is where you'd get the chance * to get all of them. */ static SizedSPropTagArray(1, tagaProviderTable) = { 1, { PR_PROVIDER_UID } }; HRESULT HrOpenSingleProvider( LPPROVIDERADMIN lpAdminProviders, LPPROFSECT FAR * lppProfSect ) { HRESULT hResult; LPMAPITABLE lpTable = NULL; LPSRowSet lpRows = NULL; LPSPropValue lpProp; hResult = lpAdminProviders->lpVtbl->GetProviderTable( lpAdminProviders, 0, &lpTable ); if (HR_FAILED(hResult)) goto out; hResult = lpTable->lpVtbl->SetColumns(lpTable, (LPSPropTagArray) &tagaProviderTable, 0); if (HR_FAILED(hResult)) goto out; hResult = lpTable->lpVtbl->QueryRows(lpTable, 1, 0, &lpRows); if (HR_FAILED(hResult)) goto out; if (lpRows->cRows == 0) { hResult = ResultFromScode(MAPI_E_NOT_FOUND); goto out; } lpProp = lpRows->aRow[0].lpProps; hResult = lpAdminProviders->lpVtbl->OpenProfileSection( lpAdminProviders, (LPMAPIUID) lpProp->Value.bin.lpb, NULL, MAPI_MODIFY, lppProfSect); out: FreeProws(lpRows); if (lpTable) lpTable->lpVtbl->Release(lpTable); DebugTraceResult(HrOpenSingleProvider, hResult); return hResult; } /* - ScLoadString - * Loads a string from a resource. It will optionally allocate the string if * a allocation function is passed in. Otherwise it assumes that the *lppsz * is already allocated. */ SCODE ScLoadString( UINT ids, ULONG ulcch, LPALLOCATEBUFFER lpAllocBuff, HINSTANCE hLibrary, LPTSTR * lppsz ) { SCODE sc = S_OK; int iRet; /* * Assert parameters */ Assert((lpAllocBuff ? !IsBadCodePtr((FARPROC) lpAllocBuff):TRUE)); Assert(ids!=0); if (lpAllocBuff) { sc = lpAllocBuff(ulcch*SIZEOF(TCHAR), lppsz); if (FAILED(sc)) { goto out; } } #ifdef DEBUG else { Assert(!IsBadWritePtr(*lppsz, (UINT) ulcch*SIZEOF(TCHAR))); } #endif /* DEBUG */ iRet = LoadString( hLibrary, ids, *lppsz, (UINT)ulcch ); if (!iRet) { DebugTrace("AWFXAB32(ScLoadString): LoadString() failed...\n"); sc = E_FAIL; goto out; } out: DebugTraceSc(ScLoadString, sc); return sc; } /************************************************************************* * - LoadIniParams - * Loads any paramters I need from the registry * */ void LoadIniParams(void) { //fExposeFaxAB = TRUE; #if 0 fExposeFaxAB = GetInitializerInt( HKEY_CURRENT_USER, TEXT("Address Book Provider"), TEXT("ExposeFaxAB"), FALSE, TEXT("Software\\Microsoft\\At Work Fax") ); fDebugTrap = GetInitializerInt( HKEY_CURRENT_USER, TEXT("Address Book Provider"), TEXT("DebugTrap"), FALSE, TEXT("Software\\Microsoft\\At Work Fax") ); #endif } #undef _FAXAB_ABP