/*********************************************************************** * * OOUSER.C * * Microsoft At Work Fax AB One Off Mail User object * This file contains the code for implementing the Microsoft At Work Fax AB * One Off Mail user. * * Copyright 1992, 1994 Microsoft Corporation. All Rights Reserved. * * Revision History: * * When Who What * -------- ------------------ --------------------------------------- * MAPI Original source from MAPI(154) sample AB Provider * 3.7.94 Yoram Yaacovi Modifications to make it an At Work Fax ABP * 3.17.94 Yoram Yaacovi Update to MAPI build 154 * 4.8.94 Yoram Yaacovi Update to MAPI build 158. Made edit boxes editable * 4.12.94 Yoram Yaacovi Most props are now set on the OOTID (ootid.c) object * instead of the OOUSER object. * 8.8.94 Yoram Yaacovi Updated to MAPI 304 and new spec * ***********************************************************************/ #define _FAXAB_OOUSER #include "faxab.h" /* * External functions */ /* * Display table control structures for the OneOff property sheet. */ /* * Control definitions in abuser.c */ extern DTBLEDIT editUserDisplayName; extern DTBLEDIT editUserAreaCode; extern DTBLEDIT editUserTelNumber; extern DTBLDDLBX ddlbxCountryCodes; /* * General Property Page definition * * Should be kept in sync with the one for an AB user in abuser.c * Could not use the same because of some fields that need to be editable * here, and read-only for an AB user */ // extern DTCTL rgdtctlUserGeneral[]; // extern WORD sizeof_rgdtpageUserGeneral; // extern DTPAGE rgdtpageUser[]; // extern WORD sizeof_rgdtpageUser; // Description the the Fax AB pane in MAPI dialog description language static DTCTL rgdtctlOOUserGeneral[] = { /* general property page */ { DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage }, /* cover page name static control and edit control */ { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_DISPLAY_NAME_LABEL, &dtbllabel }, { DTCT_EDIT, DT_REQUIRED | DT_EDITABLE | DT_ACCEPT_DBCS | DT_SET_IMMEDIATE, NULL, 0, (LPTSTR)szNoFilter, IDC_RECIP_DISPLAY_NAME, &editUserDisplayName }, /* Country codes label and drop down list box */ { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_COUNTRY_CODE_LABEL, &dtbllabel }, { DTCT_DDLBX, DT_EDITABLE, NULL, 0, NULL, IDC_RECIP_COUNTRY_CODE, &ddlbxCountryCodes }, /* Area code and fax number label */ { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_FAX_NUMBER_LABEL, &dtbllabel }, /* area code edit control */ { DTCT_EDIT, DT_EDITABLE, NULL, 0, (LPTSTR)szDigitsOnlyFilter, IDC_RECIP_FAX_NUMBER_AREA_CODE, &editUserAreaCode }, /* Fax number static control and edit control */ { DTCT_LABEL, 0, NULL, 0, NULL, IDC_RECIP_FAX_NUMBER_LABEL2, &dtbllabel }, { DTCT_EDIT, DT_REQUIRED | DT_EDITABLE, NULL, 0, (LPTSTR)szDigitsOnlyFilter, IDC_RECIP_FAX_NUMBER, &editUserTelNumber} }; /* * The OneOff property sheet definition * Currently using exactly the same layout as the AB user dialog * with some fields editable here and read-only for an AB user */ static DTPAGE rgdtpageOOUser[] = { { ARRAYSIZE(rgdtctlOOUserGeneral), (LPTSTR)MAKEINTRESOURCE(MAWFRecipient), TEXT(""), rgdtctlOOUserGeneral }, }; /* * ABOOUser jump table is defined here... */ ABOOUSER_Vtbl vtblABOOUSER = { (ABOOUSER_QueryInterface_METHOD *) ABU_QueryInterface, (ABOOUSER_AddRef_METHOD *) WRAP_AddRef, ABOOUSER_Release, (ABOOUSER_GetLastError_METHOD *) WRAP_GetLastError, (ABOOUSER_SaveChanges_METHOD *) WRAP_SaveChanges, (ABOOUSER_GetProps_METHOD *) WRAP_GetProps, (ABOOUSER_GetPropList_METHOD *) WRAP_GetPropList, ABOOUSER_OpenProperty, (ABOOUSER_SetProps_METHOD *) WRAP_SetProps, (ABOOUSER_DeleteProps_METHOD *) WRAP_DeleteProps, (ABOOUSER_CopyTo_METHOD *) WRAP_CopyTo, (ABOOUSER_CopyProps_METHOD *) WRAP_CopyProps, (ABOOUSER_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs, (ABOOUSER_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames, }; enum { ivalusrPR_DISPLAY_TYPE = 0, ivalusrPR_OBJECT_TYPE, ivalusrPR_ADDRTYPE, ivalusrPR_COUNTRY_ID, ivalusrPR_AREA_CODE, #ifdef INIT_TEL_NUMBER ivalusrPR_TEL_NUMBER, #endif ivalusrPR_TEMPLATEID, cvalusrMax }; /************************************************************************* * - HrNewFaxOOUser - * Creates the IMAPIProp associated with a one off mail user. * * */ HRESULT HrNewFaxOOUser( LPMAILUSER * lppMAPIPropEntry, ULONG * lpulObjType, ULONG cbEntryID, LPENTRYID lpEntryID, LPABLOGON lpABPLogon, LPCIID lpInterface, HINSTANCE hLibrary, LPALLOCATEBUFFER lpAllocBuff, LPALLOCATEMORE lpAllocMore, LPFREEBUFFER lpFreeBuff, LPMALLOC lpMalloc ) { LPABOOUSER lpABOOUser = NULL; SCODE sc; HRESULT hr = hrSuccess; LPPROPDATA lpPropData = NULL; SPropValue spv[cvalusrMax]; #ifdef UNICODE CHAR szAnsiAreaCode[ AREA_CODE_SIZE ]; CHAR szEMT[ MAX_PATH ]; #endif /* Do I support this interface?? */ if (lpInterface) { if ( memcmp(lpInterface, &IID_IMailUser, SIZEOF(IID)) && memcmp(lpInterface, &IID_IMAPIProp, SIZEOF(IID)) && memcmp(lpInterface, &IID_IUnknown, SIZEOF(IID)) ) { DebugTraceSc(HrNewSampOOUser, MAPI_E_INTERFACE_NOT_SUPPORTED); return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); } } /* * Allocate space for the ABOOUser structure */ sc = lpAllocBuff(SIZEOF(ABOOUSER), (LPVOID *) & lpABOOUser); if (FAILED(sc)) { hr = ResultFromScode (sc); DebugTraceResult(NewFaxUser, hr); goto err; } lpABOOUser->lpVtbl = &vtblABOOUSER; lpABOOUser->lcInit = 1; lpABOOUser->hResult = hrSuccess; lpABOOUser->idsLastError = 0; lpABOOUser->hLibrary = hLibrary; lpABOOUser->lpAllocBuff = lpAllocBuff; lpABOOUser->lpAllocMore = lpAllocMore; lpABOOUser->lpFreeBuff = lpFreeBuff; lpABOOUser->lpMalloc = lpMalloc; lpABOOUser->lpABLogon = lpABPLogon; lpABOOUser->lpTDatDDListBox = NULL; /* * Create lpPropData */ sc = CreateIProp( (LPIID) &IID_IMAPIPropData, lpAllocBuff, lpAllocMore, lpFreeBuff, lpMalloc, &lpPropData ); if (FAILED(sc)) { hr = ResultFromScode (sc); goto err; } /* * Set up the initial set of properties */ spv[ivalusrPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE; spv[ivalusrPR_DISPLAY_TYPE].Value.l = DT_MAILUSER; spv[ivalusrPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE; spv[ivalusrPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER; spv[ivalusrPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE_A; #ifdef UNICODE szEMT[0] = 0; WideCharToMultiByte( CP_ACP, 0, lpszEMT, -1, szEMT, ARRAYSIZE(szEMT), NULL, NULL ); spv[ivalusrPR_ADDRTYPE].Value.lpszA = szEMT; #else spv[ivalusrPR_ADDRTYPE].Value.LPSZ = lpszEMT; #endif spv[ivalusrPR_TEMPLATEID].ulPropTag = PR_TEMPLATEID; spv[ivalusrPR_TEMPLATEID].Value.bin.cb = SIZEOF(OOUSER_ENTRYID); spv[ivalusrPR_TEMPLATEID].Value.bin.lpb = (LPBYTE) lpEntryID; spv[ivalusrPR_COUNTRY_ID].ulPropTag = PR_COUNTRY_ID; /* spv[ivalusrPR_COUNTRY_ID].Value.ul = 1; // U.S.; */ spv[ivalusrPR_COUNTRY_ID].Value.ul = GetCurrentLocationCountryID(); // display the area code of the current location spv[ivalusrPR_AREA_CODE].ulPropTag = PR_AREA_CODE_A; #ifdef UNICODE szAnsiAreaCode[0] = 0; WideCharToMultiByte( CP_ACP, 0, GetCurrentLocationAreaCode(), -1, szAnsiAreaCode, ARRAYSIZE(szAnsiAreaCode), NULL, NULL ); spv[ivalusrPR_AREA_CODE].Value.lpszA = szAnsiAreaCode; #else spv[ivalusrPR_AREA_CODE].Value.lpszA = GetCurrentLocationAreaCode(); #endif #ifdef INIT_TEL_NUMBER // initialize the fax number, so that it won't be PT_ERROR spv[ivalusrPR_TEL_NUMBER].ulPropTag = PR_TEL_NUMBER_A; spv[ivalusrPR_TEL_NUMBER].Value.lpszA = (LPSTR) ""; #endif /* * Note that we're using our entryID for our templateID. * This is a really simple way to implement templateIDs. * (See TID.C) */ /* * Set the default properties */ hr = lpPropData->lpVtbl->SetProps( lpPropData, cvalusrMax, spv, NULL ); if (HR_FAILED(hr)) { DebugTraceResult(NewFaxOOUser, hr); goto err; } (void) lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READWRITE); lpABOOUser->lpPropData = (LPMAPIPROP) lpPropData; InitializeCriticalSection(&lpABOOUser->cs); *lppMAPIPropEntry = (LPVOID) lpABOOUser; *lpulObjType = MAPI_MAILUSER; out: DebugTraceResult(HrNewSampOOUser, hr); return hr; err: if (lpPropData) lpPropData->lpVtbl->Release(lpPropData); lpFreeBuff( lpABOOUser ); goto out; } /*************************************************** * * The actual ABOOUser methods */ /************************************************** * - ABOOUSER_Release - * Decrement lpInit. * When lcInit == 0, free up the lpABOOUser structure * */ STDMETHODIMP_(ULONG) ABOOUSER_Release (LPABOOUSER lpABOOUser) { LONG lcInit; /* * Check to see if it's big enough to hold this object */ if (IsBadReadPtr(lpABOOUser, SIZEOF(ABOOUSER))) { /* * Not large enough */ return 1; } /* * Check to see that it's the correct vtbl */ if (lpABOOUser->lpVtbl != &vtblABOOUSER) { /* * Not my vtbl */ return 1; } EnterCriticalSection(&lpABOOUser->cs); lcInit = --lpABOOUser->lcInit; LeaveCriticalSection(&lpABOOUser->cs); if (lcInit == 0) { /* * Get rid of the lpPropData */ lpABOOUser->lpPropData->lpVtbl->Release(lpABOOUser->lpPropData); /* * Get rid of the country codes table */ if (lpABOOUser->lpTDatDDListBox) lpABOOUser->lpTDatDDListBox->lpVtbl->Release(lpABOOUser->lpTDatDDListBox); /* * Destroy the critical section for this object */ DeleteCriticalSection(&lpABOOUser->cs); /* * Set the vtbl to NULL. This way the client will find out * real fast if it's calling a method on a released object. That is, * the client will crash. Hopefully, this will happen during the * development stage of the client. */ lpABOOUser->lpVtbl = NULL; /* * Need to free the object */ lpABOOUser->lpFreeBuff( lpABOOUser ); return 0; } return lcInit; } /************************************************************************* * - ABOOUSER_OpenProperty - * * This is how we get the display table associated with this users * details screen. */ STDMETHODIMP ABOOUSER_OpenProperty( LPABOOUSER lpABOOUser, ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN * lppUnk) { LPMAPITABLE lpDisplayTable=NULL; /* * Since the default is that we do not support opening this * object, we can initialize our hResult here. */ HRESULT hResult = ResultFromScode(MAPI_E_NO_SUPPORT); /* * Check to see if it can be pointing to the right structure. */ if (IsBadReadPtr(lpABOOUser, SIZEOF(ABOOUSER))) { /* * Not big enough to be my object */ hResult = ResultFromScode(E_INVALIDARG); goto out; } /* * Check to see that it's got the correct vtbl */ if (lpABOOUser->lpVtbl != &vtblABOOUSER) { /* * Not my vtbl */ hResult = ResultFromScode(E_INVALIDARG); goto out; } if (IsBadReadPtr(lpiid, SIZEOF(IID))) { /* * Interfaces are required on this method. */ hResult = ResultFromScode(E_ACCESSDENIED); goto out; } if (ulInterfaceOptions & ~MAPI_UNICODE ) { /* * Only UNICODE flag should be set for any of the objects that might * be returned from this object. */ hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } if ( ulInterfaceOptions & MAPI_UNICODE ) { hResult = ResultFromScode( MAPI_E_BAD_CHARWIDTH ); goto out; } if (ulFlags & ~(MAPI_CREATE|MAPI_MODIFY|MAPI_DEFERRED_ERRORS)) { /* * Don't understand the flags that were passed in */ hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); goto out; } if (ulFlags & MAPI_CREATE) { /* * Don't support creating any sub-objects */ hResult = ResultFromScode(E_ACCESSDENIED); goto out; } if (IsBadWritePtr(lppUnk, SIZEOF(LPUNKNOWN))) { /* * Got to be able to return an object */ hResult = ResultFromScode(E_INVALIDARG); goto out; } // If the caller is trying to open a table property and is not expecting a table interface.. switch (ulPropTag) { case PR_DETAILS_TABLE: case PR_DDLBX_COUNTRIES_TABLE: if (memcmp( lpiid, &IID_IMAPITable, SIZEOF(IID) )) { // ... we will abort right here hResult = ResultFromScode(E_NOINTERFACE); goto out; } break; default: break; } /* Check to see if I need a display table*/ switch (ulPropTag) { case PR_DETAILS_TABLE: /* Looking for the display table*/ /* // Going to use the AB user display array, but make all editable // fields editable for (i=0; i < (sizeof_rgdtpageUserGeneral / sizeof(DTCTL)); i++) if ((rgdtctlUserGeneral[i].ulCtlType == DTCT_EDIT) || (rgdtctlUserGeneral[i].ulCtlType == DTCT_DDLBX)) */ /* Create a display table */ hResult = BuildDisplayTable( lpABOOUser->lpAllocBuff, lpABOOUser->lpAllocMore, lpABOOUser->lpFreeBuff, lpABOOUser->lpMalloc, lpABOOUser->hLibrary, ARRAYSIZE(rgdtpageOOUser), rgdtpageOOUser, 0, &lpDisplayTable, NULL ); #ifdef WRAP_TABLE HrNewTableWrap(&lpDisplayTable); #endif *lppUnk = (LPUNKNOWN) lpDisplayTable; if (HR_FAILED(hResult)) { goto out; } /* * We're succeeding. Ensure our hResult is set properly */ hResult = hrSuccess; break; case PR_DDLBX_COUNTRIES_TABLE: // This table is not changing dynamically. No need to rebuild if already built. if (!lpABOOUser->lpTDatDDListBox) { hResult = HrBuildDDLBXCountriesTable((LPABUSER) lpABOOUser); if (HR_FAILED(hResult)) goto out; } Assert(lpABOOUser->lpTDatDDListBox); /* Get a view from the TAD*/ hResult = lpABOOUser->lpTDatDDListBox->lpVtbl->HrGetView( lpABOOUser->lpTDatDDListBox, NULL, NULL, 0, (LPMAPITABLE *) lppUnk); break; default: hResult = ResultFromScode(MAPI_E_NO_SUPPORT); break; } out: DebugTraceResult(ABOOUSER_OpenProperty, hResult); return hResult; } /********************************************************************** * * Private functions */ #undef _FAXAB_OOUSER