#include <mapix.h>
#include <mapiutil.h>
#include <edkmdb.h>
#include "Profiles.h"
 
/***********************************************************************
 
  STDMETHODIMP CreateProfile(LPSTR lpszProfileName,
                                                                             LPSTR lpszExchangeServer,
                                                                             LPSTR lpszMailbox)
 
            - lpszProfileName:                    [in] Name of profile to be created
            - lpszExchangeServer:   [in] Name of the Exchange server
            - lpszMailbox:                           [in] Name of the mailbox
 
  This procedure is fairly straightforward. It creates a profile by using the MAPI interfaces.
 
***********************************************************************/
STDMETHODIMP CreateProfile(LPSTR lpszProfileName,
                                                                           LPSTR lpszExchangeServer,
                                                                           LPSTR lpszMailbox)
{
            HRESULT         hRes = S_OK;                                   // Result from MAPI calls                      
    LPPROFADMIN     lpProfAdmin = NULL;             // Profile Admin object
 
            // Get an IProfAdmin interface
            hRes = MAPIAdminProfiles(0,                             // Flags
                                                                                     &lpProfAdmin); // Pointer to new IProfAdmin
            if(SUCCEEDED(hRes) && lpProfAdmin)
            {
                        // Create a new profile
                        hRes = lpProfAdmin->CreateProfile((LPTSTR)lpszProfileName,          // Name of new profile
                                                                                                                          NULL,                                               // Password for profile
                                                                                                                          NULL,                                               // Handle to parent window
                                                                                                                          NULL);                                  // Flags
                        if(SUCCEEDED(hRes))
                        {
                                    LPSERVICEADMIN  lpSvcAdmin = NULL;              // Service Admin object
 
                                    // Get an IMsgServiceAdmin interface off the IProfAdmin interface
                                    hRes = lpProfAdmin->AdminServices((LPTSTR)lpszProfileName,       // Profile that we want to modify
                                                                                                                                      NULL,                                               // Password for that profile
                                                                                                                                      NULL,                                               // Handle to parent window
                                                                                                                                      0,                                           // Flags
                                                                                                                                      &lpSvcAdmin);                      // Pointer to new IMsgServiceAdmin
                                    if(SUCCEEDED(hRes) && lpSvcAdmin)
                                    {
                                                // Create the new message service for Exchange
                                                hRes = lpSvcAdmin->CreateMsgService((LPTSTR)"MSEMS",                       // Name of service from MAPISVC.INF
                                                                                                                                                            NULL,                         // Display name of service
                                                                                                                                                            NULL,                         // Handle to parent window
                                                                                                                                                            NULL);                                    // Flags
                                                if(SUCCEEDED(hRes))
                                                {
                                                            // We now have to obtain the entry ID for the new service.
                                                            // You can do this by obtaining the message service table
                                                            // and by obtaining the entry that corresponds to the new service.
 
                                                            LPMAPITABLE     lpMsgSvcTable = NULL;  // Table to hold services
 
                                                            hRes = lpSvcAdmin->GetMsgServiceTable(0,                                      // Flags
                                                                                                                                                                          &lpMsgSvcTable);       // Pointer to table
                                                            if(SUCCEEDED(hRes) && lpMsgSvcTable)
                                                            {
                                                                        LPSRowSet       lpSvcRows = NULL;             // Rowset to hold results of table query
                                                                        SRestriction      sres;                                                     // Restriction structure
                                                                        SPropValue                  SvcProps;                                            // Property structure for restriction
 
                                                                        // Set up restriction to query table.
 
                                                                        sres.rt = RES_CONTENT;
                                                                        sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
                                                                        sres.res.resContent.ulPropTag = PR_SERVICE_NAME_A;
                                                                        sres.res.resContent.lpProp = &SvcProps;
 
                                                                        SvcProps.ulPropTag = PR_SERVICE_NAME;
                                                                        SvcProps.Value.lpszA = "MSEMS";
 
                                                                        // Query the table to obtain the entry for the newly created message service.
                                                                        // This indicates the columns that we want to be returned from HrQueryAllRows
                                                                        enum {iSvcName, iSvcUID, cptaSvc};
                                                                        SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc, PR_SERVICE_NAME_A, PR_SERVICE_UID };
 
                                                                        hRes = HrQueryAllRows(lpMsgSvcTable,
                                                                                                                                      (LPSPropTagArray)&sptCols,
                                                                                                                                      &sres,
                                                                                                                                      NULL,
                                                                                                                                      0,
                                                                                                                                      &lpSvcRows);
                                                                        if(SUCCEEDED(hRes) && lpSvcRows)
                                                                        {
                                                                                    // Set up a SPropValue array for the properties that you have to configure.
                                                                                    SPropValue rgval[2];
                                                                                    int i = 0;
 
                                                                                    // First, the server name
                                                                                    ZeroMemory(&rgval[i], sizeof(SPropValue) );
                                                                                    rgval[i].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER;
                                                                                    rgval[i++].Value.lpszA = lpszExchangeServer;
 
                                                                                    // Next, the mailbox name
                                                                                    ZeroMemory(&rgval[i], sizeof(SPropValue) );
                                                                                    rgval[i].ulPropTag = PR_PROFILE_UNRESOLVED_NAME; 
                                                                                    rgval[i++].Value.lpszA = lpszMailbox;
 
                                                                                    hRes = lpSvcAdmin->ConfigureMsgService((LPMAPIUID)lpSvcRows->aRow[0].lpProps[1].Value.bin.lpb, // Entry ID of service to configure
                                                                                                                                                                                                   NULL,                                                                                                                                              // Handle to parent window
                                                                                                                                                                                                   0,                                                                                                                                                      // Flags
                                                                                                                                                                                                   i,                                                                                                                                                       // Number of properties that we are setting
                                                                                                                                                                                                   rgval);                                                                                                                                                // Pointer to SPropValue array
                                                                        }
 
                                                                        if (lpSvcRows) FreeProws(lpSvcRows);
                                                            }
 
                                                            if (lpMsgSvcTable) lpMsgSvcTable->Release();
                                                }
                                    }
 
                                    if (lpSvcAdmin) lpSvcAdmin->Release();
                        }
            }
 
            if (lpProfAdmin) lpProfAdmin->Release();
 
            return hRes;
}
 
/***********************************************************************
 
  STDMETHODIMP DeleteProfile(LPSTR lpszProfileName)
 
            - lpszProfileName:                    [in] Name of profile to delete
 
  This procedure is fairly straightforward.  It deletes the indicated profile by using the
  MAPI interfaces.
 
***********************************************************************/
STDMETHODIMP DeleteProfile(LPSTR lpszProfileName)
{
            HRESULT                               hRes = S_OK;
            LPPROFADMIN     lpProfAdmin = NULL;
 
            // Get an IProfAdmin interface
 
            hRes = MAPIAdminProfiles(0,                             // Flags
                                                                                     &lpProfAdmin); // Pointer to new IProfAdmin
            if(SUCCEEDED(hRes) && lpProfAdmin)
            {
                        hRes = lpProfAdmin->DeleteProfile(lpszProfileName, 0);
            }
 
            if (lpProfAdmin) lpProfAdmin->Release();
 
            return hRes;
}
 
STDMETHODIMP OpenGlobalProfileSection(LPSTR lpszProfile, LPPROFSECT * lppProfSect)
{
            HRESULT hRes = S_OK;
            LPPROFADMIN lpProfAdmin = NULL;
 
            hRes = MAPIAdminProfiles(0, &lpProfAdmin);
            if(SUCCEEDED(hRes) && lpProfAdmin)
            {
                        LPSERVICEADMIN lpSvcAdmin = NULL;
 
                        hRes = lpProfAdmin->AdminServices((LPTSTR)lpszProfile,
                                                                                                                          NULL,
                                                                                                                          NULL,
                                                                                                                          0,
                                                                                                                          &lpSvcAdmin);
                        if(SUCCEEDED(hRes) && lpSvcAdmin)
                        {
                                    hRes = lpSvcAdmin->OpenProfileSection((LPMAPIUID)&pbGlobalProfileSectionGuid,
                                                                                                                                                  NULL,
                                                                                                                                                  0,
                                                                                                                                                  lppProfSect);
 
                                    lpSvcAdmin->Release();
                        }
 
                        lpProfAdmin->Release();
            }
 
            return hRes;
}
 
STDMETHODIMP SvcAdminOpenProfileSection(LPSERVICEADMIN lpSvcAdmin, 
                                                                                                                        LPMAPIUID lpUID, 
                                                                                                                        LPCIID lpInterface, 
                                                                                                                        ULONG ulFlags, 
                                                                                                                        LPPROFSECT FAR * lppProfSect)
{
            HRESULT hRes = S_OK;
 
            // Note: We have to open the profile section with full access.
            // MAPI discriminates  who can modify profiles, especially
            // in certain sections.  The way to force access has changed in
            // different versions of Outlook. Therefore, there are two methods.  See KB article 822977
            // for more information.
 
            // First, let us try the easier method of passing the MAPI_FORCE_ACCESS flag
            // to OpenProfileSection.  This method is available only in Outlook 2003 and in later versions of Outlook.
 
            hRes = lpSvcAdmin->OpenProfileSection(lpUID,
                                                                                                                          lpInterface,
                                                                                                                          ulFlags | MAPI_FORCE_ACCESS,
                                                                                                                          lppProfSect);
            if(FAILED(hRes))
            {
                        // If this does not succeed, it may be because you are using an earlier version of Outlook.
                        // In this case, use the sample code
                        // from KB article 228736 for more information.  Note: This information was compiled from that sample.
                        // 
 
                        ///////////////////////////////////////////////////////////////////
                        //  MAPI will always return E_ACCESSDENIED
                        // when we open a profile section on the service if we are a client.  The workaround
                        // is to call into one of MAPI's internal functions that bypasses
                        // the security check.  We build an interface to it, and then point to it from our
                        // offset of 0x48.  USE THIS METHOD AT YOUR OWN RISK!  THIS METHOD IS NOT SUPPORTED!
                        interface IOpenSectionHack : public IUnknown
                        {
                                    public:
                                    virtual HRESULT STDMETHODCALLTYPE OpenSection(LPMAPIUID, ULONG, LPPROFSECT*) = 0;
                        };
 
                        IOpenSectionHack** ppProfile = (IOpenSectionHack**)((((BYTE*)lpSvcAdmin) + 0x48));
 
                        // Now, we want to open the Services Profile Section and store that
                        // interface with the Object
                        hRes = (*ppProfile)->OpenSection(lpUID, 
                                                                                                                         ulFlags, 
                                                                                                                         lppProfSect);
                                                
                        // 
                        ///////////////////////////////////////////////////////////////////
            }
 
            return hRes;
}
 
STDMETHODIMP ProvAdminOpenProfileSection(LPPROVIDERADMIN lpProvAdmin, 
                                                                                                                         LPMAPIUID lpUID, 
                                                                                                                         LPCIID lpInterface, 
                                                                                                                         ULONG ulFlags, 
                                                                                                                         LPPROFSECT FAR * lppProfSect)
{
            HRESULT hRes = S_OK;
 
            hRes = lpProvAdmin->OpenProfileSection(lpUID,
                                                                                                                           lpInterface,
                                                                                                                           ulFlags | MAPI_FORCE_ACCESS,
                                                                                                                           lppProfSect);
 
            if((FAILED(hRes)) && (MAPI_E_UNKNOWN_FLAGS == hRes))
            {
                        // The MAPI_FORCE_ACCESS flag is implemented only in Outlook 2002 and in later versions of Outlook.
                        // 
 
                        // 
                        //                                     Makes MAPI think we are a service and not a client.
                        //                                     MAPI grants us Service Access.  This makes it all possible.
                        *(((BYTE*)lpProvAdmin) + 0x60) = 0x2;  // USE THIS METHOD AT YOUR OWN RISK! THIS METHOD IS NOT SUPPORTED!
 
                        hRes = lpProvAdmin->OpenProfileSection(lpUID,
                                                                                                                                       lpInterface,
                                                                                                                                       ulFlags,
                                                                                                                                       lppProfSect);
            }
 
            return hRes;
}
 
STDMETHODIMP EnableReconnect(LPSTR lpszProfile)
{
            HRESULT hRes = S_OK;
            LPPROFADMIN lpProfAdmin = NULL;
 
            hRes = MAPIAdminProfiles(0, &lpProfAdmin);
            if(SUCCEEDED(hRes) && lpProfAdmin)
            {
                        LPSERVICEADMIN lpSvcAdmin = NULL;
 
                        hRes = lpProfAdmin->AdminServices((LPTSTR)lpszProfile,
                                                                                                                          NULL,
                                                                                                                          NULL,
                                                                                                                          0,
                                                                                                                          &lpSvcAdmin);
                        if(SUCCEEDED(hRes) && lpSvcAdmin)
                        {
                                    LPPROFSECT lpABProfSect = NULL;
 
                                    hRes = SvcAdminOpenProfileSection(lpSvcAdmin, 
                                                (LPMAPIUID)&MUIDEMSAB, NULL, MAPI_MODIFY, &lpABProfSect);
                                    if(SUCCEEDED(hRes) && lpABProfSect)
                                    {
                                                SPropValue spReconnectProps[2] = {0};
 
                                                spReconnectProps[0].ulPropTag = PR_PROFILE_ABP_ALLOW_RECONNECT;
                                                spReconnectProps[0].Value.l = 1;
 
                                                spReconnectProps[1].ulPropTag = PR_PROFILE_ABP_MTHREAD_TIMEOUT_SECS;
                                                spReconnectProps[1].Value.l = 10;
 
                                                hRes = lpABProfSect->SetProps(2, spReconnectProps, NULL);
                                                if(SUCCEEDED(hRes))
                                                {
                                                            LPPROFSECT lpGlobalProfSect = NULL;
 
                                                            hRes = SvcAdminOpenProfileSection(lpSvcAdmin, 
                                                                        (LPMAPIUID)&pbGlobalProfileSectionGuid, NULL, MAPI_MODIFY, &lpGlobalProfSect);
                                                            if(SUCCEEDED(hRes) && lpGlobalProfSect)
                                                            {
                                                                        SPropValue spServerVersion = {0};
 
                                                                        spServerVersion.ulPropTag = PR_PROFILE_SERVER_VERSION;
                                                                        spServerVersion.Value.l = 3000;
 
                                                                        hRes = lpGlobalProfSect->SetProps(1, &spServerVersion, NULL);
                                                            }
 
                                                            if(lpGlobalProfSect)
                                                                        lpGlobalProfSect->Release();
                                                }
                                    }
 
                                    if(lpABProfSect)
                                                lpABProfSect->Release();
                        }
 
                        if(lpSvcAdmin)
                                    lpSvcAdmin->Release();
            }
 
            if(lpProfAdmin)
                        lpProfAdmin->Release();
 
            return hRes;
}