home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / remote.xp / xpsrvce.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  28.6 KB  |  747 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  File Name 
  4. //      XPSRVCE.CPP
  5. //
  6. //  Description
  7. //      This file implements the entry points, XPProviderInit and 
  8. //      ServiceEntry for this provider's DLL.
  9. //
  10. //  Author
  11. //      Irving De la Cruz
  12. //
  13. //  Revision: 1.7
  14. //
  15. // Written for Microsoft Windows Developer Support
  16. // Copyright (c) 1995-1996 Microsoft Corporation. All rights reserved.
  17. //
  18. #include "XPWDSR.H"
  19.  
  20. // Remark this line to turn verbose tracing OFF
  21. #define DO_INFO_TRACES
  22. #ifdef DO_INFO_TRACES
  23. #define InfoTrace(a)   TraceInfoMessage(a)
  24. #else
  25. #define InfoTrace(a)   
  26. #endif // DO_INFO_TRACES
  27.  
  28. DTBLEDIT     DtUploadTime = { sizeof(DTBLEDIT), fMapiUnicode, 5, PR_TMP_UPLOAD_TIME };
  29. DTBLCHECKBOX DtGetHeaders = { sizeof(DTBLCHECKBOX), fMapiUnicode, PR_SMP_GET_HEADERS };
  30.  
  31. DTCTL XPConfigPage[] =
  32. {
  33.     { DTCT_PAGE,     0,           NULL, 0, NULL,     0,                  &DtPage       },
  34.     { DTCT_EDIT,     DT_REQUIRED, NULL, 0, szFilter, IDC_UPLOAD_TIME,    &DtUploadTime },
  35.     { DTCT_CHECKBOX, 0,           NULL, 0, NULL,     IDC_UPDATE_HEADERS, &DtGetHeaders },
  36.     { DTCT_LABEL,    0,           NULL, 0, NULL,     IDC_STATIC1,        &DtLabel      },
  37.     { DTCT_GROUPBOX, 0,           NULL, 0, NULL,     IDC_STATIC2,        &DtGroupBox   },
  38.     { DTCT_GROUPBOX, 0,           NULL, 0, NULL,     IDC_STATIC3,        &DtGroupBox   }
  39. };
  40.  
  41. TCHAR szDefaultTime[] = TEXT("23:59");
  42.  
  43. // Global pointer to the MAPI memory allocation functions
  44. LPALLOCATEBUFFER    gpfnAllocateBuffer;  // MAPIAllocateBuffer function
  45. LPALLOCATEMORE      gpfnAllocateMore;    // MAPIAllocateMore function    
  46. LPFREEBUFFER        gpfnFreeBuffer;      // MAPIFreeBuffer function      
  47.  
  48. ///////////////////////////////////////////////////////////////////////////////
  49. //    ServiceEntry()
  50. //
  51. //    Parameters
  52. //      { Refer to MAPI Documentation on this method }
  53. //
  54. //    Purpose
  55. //      Called by the profile setup API to display the provider
  56. //      configuration properties for this transport provider
  57. //
  58. //    Return Value
  59. //      An HRESULT
  60. //
  61. HRESULT STDAPICALLTYPE ServiceEntry (HINSTANCE          hInstance,
  62.                                      LPMALLOC           pMallocObj,
  63.                                      LPMAPISUP          pSupObj,
  64.                                      ULONG              ulUIParam,
  65.                                      ULONG              ulFlags,
  66.                                      ULONG              ulContext,
  67.                                      ULONG              ulCfgPropCount,
  68.                                      LPSPropValue       pCfgProps,
  69.                                      LPPROVIDERADMIN    pAdminProvObj,
  70.                                      LPMAPIERROR *      ppMAPIError)
  71. {
  72.     // Look at TRACES.H and TRACES.CPP for more options to the InitTraces() function
  73.     //InitTraces (0);                                       // Send output only to the COM1 port
  74.     InitTraces (TRACES_CONSOLE | TRACES_NO_COM_OUTPUT);     // Send output to a console window BUT NOT to the COM1
  75.     //InitTraces (TRACES_CONSOLE | TRACES_LOG_FILE);        // Send output to COM1 port AND a console window AND to a log file in C:\MAPILOG.TXT
  76.  
  77.     InfoTrace ("ServiceEntry function called");
  78.     HRESULT hResult = S_OK;
  79.     LPPROFSECT pProfileObj = NULL;
  80.     ULONG ulPropCount;
  81.     LPSPropValue pProps = NULL;
  82.     HANDLE hUIMutex = NULL;
  83.  
  84.     // What context where were we called in?
  85.     if (MSG_SERVICE_INSTALL         == ulContext ||
  86.         MSG_SERVICE_UNINSTALL       == ulContext ||
  87.         MSG_SERVICE_PROVIDER_CREATE == ulContext ||
  88.         MSG_SERVICE_PROVIDER_DELETE == ulContext)
  89.     {
  90.         // We don't handle any of these contexts
  91.         TraceString1 ("ServiceEntry: Immediate return. Context: %d", ulContext);
  92.         goto ErrorExit;
  93.     }
  94.     TraceString1 ("ServiceEntry: Context for call: %d", ulContext);
  95.     ghInstance = hInstance;
  96.     
  97.     // Get the MAPI memory allocation routines we'll be needing
  98.     hResult = pSupObj->GetMemAllocRoutines (&gpfnAllocateBuffer, &gpfnAllocateMore, &gpfnFreeBuffer);
  99.     if (hResult)
  100.     {
  101.         TraceResult ("ServiceEntry: Failed to get the memory allocation functions", hResult);
  102.         goto ErrorExit;
  103.     }
  104.  
  105.     // Open the Profile Section for this service
  106.     hResult = pAdminProvObj->OpenProfileSection (NULL,
  107.                                                  NULL,
  108.                                                  MAPI_MODIFY,
  109.                                                  &pProfileObj);
  110.     if (hResult)
  111.     {
  112.         goto ErrorExit;
  113.     }
  114.     if (MSG_SERVICE_CREATE == ulContext)
  115.     {
  116.         // If ServiceEntry is called because it the service is being created, we create a temporary
  117.         // file where we save the headers text file when the user updates them from
  118.         // the remote host. The headers should be persistent from session to
  119.         // session (using the same profile, of course) but unique per session.
  120.         TCHAR szTmpDir[_MAX_PATH], szFile[_MAX_PATH];
  121.         GetTempPath (_MAX_PATH, szTmpDir);
  122.         lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
  123.         CreateDirectory (szTmpDir, NULL);
  124.         GetTempFileName (szTmpDir,      // Create the file in the system temp directory
  125.                          TEXT("XRH"),   // Our transport fixed prefix for temp files
  126.                          0,             // Use the time to create a pseudo-random number
  127.                          szFile);       // Destination buffer
  128.         SPropValue spvProps[4] = { 0 };
  129.         spvProps[0].ulPropTag = PR_SMP_HEADERS_FILENAME;
  130.         spvProps[0].Value.LPSZ = szFile;
  131.         SYSTEMTIME st;
  132.         GetLocalTime (&st);
  133.         st.wHour = 23; st.wMinute = 59; st.wSecond = 0;
  134.         spvProps[1].ulPropTag = PR_SMP_UPLOAD_TIME;
  135.         SystemTimeToFileTime (&st, &spvProps[1].Value.ft);
  136.         spvProps[2].ulPropTag = PR_SMP_CONNECTION_TYPE;
  137.         spvProps[2].Value.l = OFFLINE_CONNECT;
  138.         spvProps[3].ulPropTag = PR_SMP_GET_HEADERS;
  139.         spvProps[3].Value.b = TRUE;
  140.         hResult = pProfileObj->SetProps (sizeof(spvProps)/sizeof(SPropValue), spvProps, NULL);
  141.         TraceResult ("ServiceEntry: Failed to save the headers file name back into the profile", hResult);
  142.     }
  143.     // The profile section is open, get the properties out of it
  144.     hResult = pProfileObj->GetProps ((LPSPropTagArray)&sptLogonProps,
  145.                                      fMapiUnicode,
  146.                                      &ulPropCount,
  147.                                      &pProps);
  148.     if (FAILED(hResult))
  149.     {
  150.         TraceResult ("ServiceEntry: Failed to get profile section properties", hResult);
  151.         goto ErrorExit;
  152.     }
  153.     ASSERT (NUM_LOGON_PROPERTIES == ulPropCount);
  154.  
  155.     if (MSG_SERVICE_DELETE == ulContext)
  156.     {
  157.         // If the service is being removed from a profile, we must cleanup
  158.         // any temporary file (i.e. the headers text file)
  159.         if (PR_SMP_HEADERS_FILENAME == pProps[HEADER_FILE].ulPropTag)
  160.         {
  161.             DeleteFile (pProps[HEADER_FILE].Value.LPSZ);
  162.         }
  163.         TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
  164.         GetTempPath (_MAX_PATH, szTmpDir);
  165.         lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
  166.         if (PR_SMP_MAILBOX_NAME == pProps[MAILBOX_NAME].ulPropTag)
  167.         {
  168.             wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, pProps[MAILBOX_NAME].Value.LPSZ);
  169.             RemoveDirectory (szDownloadDir);
  170.         }
  171.         RemoveDirectory (szTmpDir);
  172.         // We are done
  173.         hResult = S_OK;
  174.         goto ErrorExit;
  175.     }
  176.     // After the setup wizard has been called the ServiceEntry functions gets called
  177.     // with a set of properties obtained from the user for configuring this provider.
  178.     // Merge or replace those properties onto the one we obtained from the profile section.
  179.     if (pCfgProps && ulCfgPropCount)
  180.     {
  181.         hResult = MergeConfigProps (ulCfgPropCount, pCfgProps, pProps);
  182.         if (hResult)
  183.         {
  184.             goto ErrorExit;
  185.         }
  186.     }
  187.     // If we can, display the UI...
  188.     if (SERVICE_UI_ALWAYS & ulFlags || SERVICE_UI_ALLOWED & ulFlags)
  189.     {
  190.         CFGDLG CfgDialog = { 0 };
  191.         hUIMutex = CreateMutex (NULL, FALSE, CONFIG_UI_MUTEX);
  192.         if (NULL == hUIMutex)
  193.         {
  194.             TraceResult ("ServiceEntry: Failed to create UI mutext", GetLastError());
  195.         }
  196.         PrivInitialize3DCtl (hInstance);
  197.         if (WAIT_TIMEOUT == WaitForSingleObject (hUIMutex, 250)) // Wait for the MUTEX for 1/4 second
  198.         {
  199.             PrivateMessageBox (IDS_MSG_CONFIG_UI_IN_USE, (HWND)ulUIParam);
  200.             hResult = MAPI_E_BUSY;
  201.             goto ErrorExit;
  202.         }
  203.  
  204.         // Fill in the logon UI structure
  205.         CfgDialog.hInst    = hInstance;
  206.         CfgDialog.hWnd     = (HWND)ulUIParam;
  207.         CfgDialog.ppProps  = &pProps;
  208.         CfgDialog.pSupObj  = pSupObj;
  209.         CfgDialog.ulFlags  = MSG_SERVICE_UI_READ_ONLY & ulFlags ? UI_READONLY : 0;
  210.         CfgDialog.hUIMutex = NULL; // So that the DoLogonDlg() won't have to wait.
  211. ShowPropsAgain:
  212.         hResult = DoLogonDlg (&CfgDialog);
  213.         if (hResult)
  214.         {
  215.             goto ErrorExit;
  216.         }
  217.         if (!PingRemoteServer ((HWND)ulUIParam, pProps))
  218.         {
  219.             goto ShowPropsAgain;
  220.         }
  221.     }
  222.     if (PR_SMP_MAILBOX_NAME == pProps[MAILBOX_NAME].ulPropTag)
  223.     {
  224.         TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
  225.         GetTempPath (_MAX_PATH, szTmpDir);
  226.         lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
  227.         wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, pProps[MAILBOX_NAME].Value.LPSZ);
  228.         CreateDirectory (szDownloadDir, NULL);
  229.     }
  230.  
  231.     hResult = pProfileObj->SetProps (NUM_LOGON_PROPERTIES, pProps, NULL);
  232.     TraceResult ("ServiceEntry: Failed to save the properties back into the profile", hResult);
  233.  
  234. ErrorExit:
  235.     // Clean up
  236.     if (pProfileObj)
  237.     {
  238.         pProfileObj->Release();
  239.     }
  240.     if (gpfnFreeBuffer)
  241.     {
  242.         gpfnFreeBuffer (pProps);
  243.     }
  244.     if (hUIMutex)
  245.     {
  246.         ReleaseMutex (hUIMutex);
  247.         CloseHandle (hUIMutex);
  248.     }
  249.     // In case the DLL was loaded, unload it.
  250.     // This DLL gets loaded and initialized in the call to DoLogonDlg()
  251.     PrivUninitialize3DCtl (hInstance);
  252.     
  253.     // If we have remote connections going on, close them now
  254.     TerminateRemoteConnections();
  255.  
  256.     // Close down the traces
  257.     UnInitTraces();
  258.     return hResult;
  259. }
  260.  
  261. ///////////////////////////////////////////////////////////////////////////////
  262. //    DoLogonDlg()
  263. //
  264. //    Parameters
  265. //      pCfgDialog   Pointer to an CFGDLG structure.
  266. //
  267. //    Purpose
  268. //      This functions gets called to display the configuration properties for
  269. //      this transport. When invoked, it will parse the transport logon 
  270. //      property array and initialize the fields in the property sheet with it.
  271. //      The function could also get invoked to display the settings in 
  272. //      READ-ONLY mode in which case we disable writing to the editable fields.
  273. //
  274. //    Return Value
  275. //      An HRESULT
  276. //
  277. HRESULT WINAPI DoLogonDlg (PCFGDLG pCfgDialog)
  278. {
  279.     DWORD dwWait = WaitForSingleObject (pCfgDialog->hUIMutex, 1000); // Wait for the MUTEX for 1 second
  280.     PrivInitialize3DCtl (pCfgDialog->hInst);
  281.     if (WAIT_TIMEOUT == dwWait)
  282.     {
  283.         PrivateMessageBox (IDS_MSG_CONFIG_UI_IN_USE, pCfgDialog->hWnd);
  284.         return MAPI_E_BUSY;
  285.     }
  286.  
  287.     LPMAPITABLE pTableObj= NULL;
  288.     ULONG ulPropCount;
  289.     SizedSPropTagArray(NUM_LOGON_PROPERTIES, sptCfgProps);
  290.     CopyMemory (&sptCfgProps, &sptLogonProps, sizeof(sptLogonProps));
  291.     sptCfgProps.aulPropTag[UPLOAD_TIME] = PR_TMP_UPLOAD_TIME;
  292.     
  293.     // Take ownership of the property value array, so calling code
  294.     // will not leak memory
  295.     LPSPropValue pProps = *pCfgDialog->ppProps;
  296.     *pCfgDialog->ppProps = NULL;
  297.     
  298.     // Retrieve the dialog title string
  299.     TCHAR szDialogTitle[64], szTimeString[32];
  300.     LoadString (pCfgDialog->hInst, IDS_SERVICE_PROPERTY_SHEETS_TITLE, szDialogTitle, 64);
  301.     CUIMAPIProp * pPropObj = NULL;
  302.     HRESULT hResult = S_OK;
  303.     try
  304.     {
  305.         pPropObj = new CUIMAPIProp (pCfgDialog->hInst,
  306.                                     gpfnAllocateBuffer,
  307.                                     gpfnAllocateMore,
  308.                                     gpfnFreeBuffer,
  309.                                     pCfgDialog->ulFlags & UI_READONLY);
  310.         if (!pPropObj)
  311.         {
  312.             hResult = E_OUTOFMEMORY;
  313.         }
  314.     }
  315.     catch (CException & Exception)
  316.     {
  317.         hResult = Exception.GetError();
  318.     }
  319.     if (hResult)
  320.     {
  321.         goto ErrorExit;
  322.     }
  323.  
  324.     ASSERT (PR_SMP_UPLOAD_TIME == pProps[UPLOAD_TIME].ulPropTag);
  325.     GetTimeString (szTimeString, pProps[UPLOAD_TIME].Value.ft);
  326.     pProps[UPLOAD_TIME].ulPropTag = PR_TMP_UPLOAD_TIME;
  327.     pProps[UPLOAD_TIME].Value.LPSZ = szTimeString;
  328.  
  329.     hResult = pPropObj->SetProps (NUM_LOGON_PROPERTIES, pProps, NULL);
  330.     if (hResult)
  331.     {
  332.         TraceResult ("DoLogonDlg: Failed to set the properties", hResult);
  333.         goto ErrorExit;
  334.     }
  335.     DTPAGE DtPropPages[2];
  336.     DtPropPages[0].cctl = NUM_CFG_USERINFO_PAGE_CTLS;   // Count of controls in the ConfigPage array
  337.     DtPropPages[0].lpszComponent = szBlank;
  338.     DtPropPages[0].lpszResourceName = MAKEINTRESOURCE (IDD_CFG_USERINFO);
  339.     DtPropPages[0].lpctl = UserConfigPage;
  340.  
  341.     DtPropPages[1].cctl = sizeof(XPConfigPage)/sizeof(DTCTL);   // Count of controls in the ConfigPage array
  342.     DtPropPages[1].lpszComponent = szBlank;
  343.     DtPropPages[1].lpszResourceName = MAKEINTRESOURCE (IDD_CFG_XPCONNECT);
  344.     DtPropPages[1].lpctl = XPConfigPage;
  345.  
  346.     // If the UI_READONLY flag is set, then we are being called from the 
  347.     // SettingDialog method in Read Only mode. Disable all of the controls
  348.     // on the property sheets, else Enable them
  349.     if (pCfgDialog->ulFlags & UI_READONLY)
  350.     {
  351.         // Disable the controls (make them read-only)
  352.         DtPropPages[0].lpctl[1].ulCtlFlags &= ~(DT_EDITABLE | DT_SET_IMMEDIATE);
  353.         DtPropPages[0].lpctl[7].ulCtlFlags &= ~(DT_EDITABLE | DT_SET_IMMEDIATE);
  354.         DtPropPages[1].lpctl[1].ulCtlFlags &= ~DT_EDITABLE;
  355.         DtPropPages[1].lpctl[2].ulCtlFlags &= ~DT_EDITABLE;
  356.     }
  357.     else
  358.     {
  359.         // Enable the controls (make them read/write)
  360.         DtPropPages[0].lpctl[1].ulCtlFlags |= (DT_EDITABLE | DT_SET_IMMEDIATE);
  361.         DtPropPages[0].lpctl[7].ulCtlFlags |= (DT_EDITABLE | DT_SET_IMMEDIATE);
  362.         DtPropPages[1].lpctl[1].ulCtlFlags |= DT_EDITABLE;
  363.         DtPropPages[1].lpctl[2].ulCtlFlags |= DT_EDITABLE;
  364.     }
  365.  
  366.     // Create the display table for the logon dialog. It is based on dialog
  367.     // resources plus the static information at the head of this module.
  368.     LPTABLEDATA pTableData;
  369.     hResult = BuildDisplayTable (gpfnAllocateBuffer,
  370.                                  gpfnAllocateMore,
  371.                                  gpfnFreeBuffer,
  372.                                  NULL,
  373.                                  pCfgDialog->hInst,
  374.                                  sizeof(DtPropPages)/sizeof(DTPAGE),
  375.                                  DtPropPages,
  376.                                  fMapiUnicode,
  377.                                  &pTableObj,
  378.                                  &pTableData);
  379.     if (!hResult)
  380.     {
  381.         pPropObj->SetTableData (pTableData);
  382.         pTableData->Release();
  383.  
  384.         // Display the dialog/property sheets
  385. DisplayPropsAgain:
  386.         hResult = pCfgDialog->pSupObj->DoConfigPropsheet ((ULONG)pCfgDialog->hWnd,
  387.                                                           0,
  388.                                                           szDialogTitle,
  389.                                                           pTableObj,
  390.                                                           pPropObj,
  391.                                                           0);     // Default index for the top property sheet
  392.         if (!hResult)
  393.         {
  394.             // Retrieve the altered data
  395.             gpfnFreeBuffer (pProps);
  396.             pProps = NULL;
  397.             hResult = pPropObj->GetProps ((LPSPropTagArray)&sptCfgProps, fMapiUnicode, &ulPropCount, &pProps);
  398.             if (hResult)
  399.             {
  400.                 if (MAPI_W_ERRORS_RETURNED == hResult)
  401.                 {
  402.                     if (PR_TMP_UPLOAD_TIME != pProps[UPLOAD_TIME].ulPropTag)
  403.                     {
  404.                         pProps[UPLOAD_TIME].ulPropTag = PR_TMP_UPLOAD_TIME;
  405.                         pProps[UPLOAD_TIME].Value.LPSZ = szDefaultTime;
  406.                     }
  407.                     hResult = S_OK;
  408.                 }
  409.                 else
  410.                 {
  411.                     TraceResult ("DoLogonDlg: GetProps failed", hResult);
  412.                     goto ErrorExit;
  413.                 }
  414.             }
  415.             // Check the Server name
  416.             if (!IsValidServerName (pProps[SERVER_NAME].Value.LPSZ))
  417.             {
  418.                 gpfnFreeBuffer (pProps);
  419.                 pProps = NULL;
  420.                 PrivateMessageBox (IDS_MSG_INVALID_SERVER_NAME, pCfgDialog->hWnd);
  421.                 goto DisplayPropsAgain;
  422.             }
  423.  
  424.             ASSERT (PR_TMP_UPLOAD_TIME == pProps[UPLOAD_TIME].ulPropTag);
  425.             SYSTEMTIME st;
  426.             GetLocalTime (&st);
  427.             if (ParseTime (pProps[UPLOAD_TIME].Value.LPSZ, &st.wHour, &st.wMinute))
  428.             {
  429.                 pProps[UPLOAD_TIME].ulPropTag = PR_SMP_UPLOAD_TIME;
  430.                 SystemTimeToFileTime (&st, &pProps[UPLOAD_TIME].Value.ft);
  431.             }
  432.             else
  433.             {
  434.                 gpfnFreeBuffer (pProps);
  435.                 pProps = NULL;
  436.                 PrivateMessageBox (IDS_MSG_BAD_TIME_FORMAT, pCfgDialog->hWnd);
  437.                 goto DisplayPropsAgain;
  438.             }
  439.  
  440.             // Return the new property array
  441.             *pCfgDialog->ppProps = pProps;
  442.             pProps = NULL;      // do not free this in cleanup code below
  443.         }
  444.     }
  445.  
  446. ErrorExit:
  447.     // Release objects
  448.     if (pTableObj)
  449.     {
  450.         pTableObj->Release();
  451.     }
  452.     if (pPropObj)
  453.     {
  454.         pPropObj->Release();
  455.     }    
  456.     gpfnFreeBuffer (pProps);
  457.     PrivUninitialize3DCtl (pCfgDialog->hInst);
  458.     ReleaseMutex (pCfgDialog->hUIMutex);
  459.     return hResult;
  460. }
  461.  
  462. ///////////////////////////////////////////////////////////////////////////////
  463. //    ParseTime()
  464. //
  465. //    Parameters                        
  466. //      [IN]    pszTime     String in the form HH:MM.
  467. //      [OUT]   pwHour      Hour of day, 0-23
  468. //      [OUT]   pwMinute    Minute of hour, 0-59
  469. //
  470. //    Purpose
  471. //      This function parses the string in pszTime and returns the numbers
  472. //      for the hour and minute of day in a 24 hour clock format.
  473. //      
  474. //    Return Value
  475. //      TRUE on success, FALSE if we failed or the string passed
  476. //      in is invalid.
  477. //      
  478. BOOL WINAPI ParseTime (LPTSTR pszTime, WORD * pwHour, WORD * pwMinute)
  479. {
  480.     TCHAR szTemp[6];
  481.     lstrcpy (szTemp, pszTime);
  482.     LPTSTR pszSubStr = strtok(szTemp, TEXT(":"));
  483.     if (!pszSubStr)
  484.     {
  485.         return FALSE;
  486.     }
  487.     *pwHour = atoi (pszSubStr);
  488.     if (*pwHour < 0 || *pwHour > 23)
  489.     {
  490.         return FALSE;
  491.     }
  492.     pszSubStr = strtok (NULL, TEXT(" "));
  493.     if (!pszSubStr)
  494.     {
  495.         return FALSE;
  496.     }
  497.     *pwMinute = atoi(pszSubStr);
  498.     if (*pwMinute < 0 || *pwMinute > 59)
  499.     {
  500.         return FALSE;
  501.     }
  502.     return TRUE;
  503. }
  504.  
  505. ///////////////////////////////////////////////////////////////////////////////
  506. //    GetTimeString()
  507. //
  508. //    Parameters
  509. //      [OUT]   pszTime     Pointer to a buffer where the function copies the
  510. //                          formatted time string. The buffer must have been
  511. //                          allocated by the caller.
  512. //      [IN]    FileTime    FILETIME structure with the time for the string.
  513. //
  514. //    Purpose
  515. //      This function returns a string formatted as "HH:MM"
  516. //      The formatted string is returned in a buffer supplied by the caller
  517. //      of the function.
  518. //      
  519. //    Return Value
  520. //      None.
  521. //
  522. void WINAPI GetTimeString (LPTSTR pszTime, FILETIME FileTime)
  523. {
  524.     // Convert the FILETIME structure to a more readable form
  525.     SYSTEMTIME sysTime;
  526.     FileTimeToSystemTime (&FileTime, &sysTime);
  527.     wsprintf (pszTime, TEXT("%d:%02d"), sysTime.wHour, sysTime.wMinute);
  528. }
  529.  
  530. ///////////////////////////////////////////////////////////////////////////////
  531. //    GetMAPIError()
  532. //
  533. //    Parameters
  534. //      ppMAPIError             Pointer to a location where the newly
  535. //                              allocated MAPIERROR structure is returened. 
  536. //      ulFlags                 Flags for the allocation of the structure
  537. //      hError                  Handle to the error for which a string will
  538. //                              be returned
  539. //      hInstance               Handle to instance of DLL where the resource
  540. //                              strings are located
  541. //
  542. //    Purpose
  543. //      This provider implements a shared function for the two different
  544. //      GetLastError methods in the IMAPIFolder and IMAPIStatus interfaces.
  545. //      These interfaces do not maintain (cached) the last error result, so
  546. //      we trust the client that the hError passed in is indeed the last error.
  547. //      This simplifies implementation of GetLastError, but it will give up
  548. //      giving error strings on the exact context of the actual last error
  549. //      in the case a client passes the wrong hResult.
  550. //      ISV's should weight the benefits and trade-off of this implementation.
  551. //
  552. //    Return Value
  553. //      An HRESULT
  554. //
  555. HRESULT WINAPI GetMAPIError (LPMAPIERROR *          ppMAPIError,
  556.                              ULONG                  ulFlags,
  557.                              HRESULT                hError,
  558.                              HINSTANCE              hInstance)
  559. {
  560.     // The following array maps a string identifier (IDS) to an hResult
  561.     // The order of HRESULTs in the array has an external dependency:
  562.     // the order of elements in the array is dictated by the IDS definitions
  563.     // in RESOURCE.H. This implicit association must be maintained for the 
  564.     // strings associated with string identifiers to make sense. Thus, if 
  565.     // either this structure or the RESOURCE.H defines changes, the other 
  566.     // must change to match it
  567.     static const HRESULT MapOfhResults[] =
  568.     {
  569.         S_OK,
  570.  
  571.         E_FAIL,
  572.         E_OUTOFMEMORY,
  573.         E_INVALIDARG,
  574.         E_NOINTERFACE,
  575.         E_ACCESSDENIED,
  576.  
  577.         MAPI_E_BUSY,
  578.         MAPI_E_NO_SUPPORT,
  579.         MAPI_E_NOT_FOUND,
  580.         MAPI_E_UNKNOWN_FLAGS,
  581.         MAPI_E_VERSION,
  582.         MAPI_E_INVALID_ENTRYID,
  583.         MAPI_E_USER_CANCEL,
  584.         MAPI_E_DISK_ERROR,
  585.         MAPI_E_CORRUPT_DATA,
  586.         MAPI_E_BAD_CHARWIDTH,
  587.         MAPI_E_UNCONFIGURED,
  588.         
  589.  
  590.         CO_E_NOTINITIALIZED,    // This error could only be comming from the server
  591.  
  592.         MAPI_W_ERRORS_RETURNED
  593.     };
  594.  
  595.     // Default the a return value in case we don't have the specified error
  596.     // Allocate the memory for the MAPIERROR structure. The caller is
  597.     // responsible for free this
  598.     HRESULT hResult = gpfnAllocateBuffer (sizeof(MAPIERROR), (LPVOID *)ppMAPIError);
  599.     if (hResult)
  600.     {
  601.         TraceResult ("GetMAPIError: Failed to allocate memory for the MAPIERROR structure", hResult);
  602.         return hResult;
  603.     }
  604.  
  605.     // Zero-out all the members in the structure
  606.     ZeroMemory (*ppMAPIError, sizeof(MAPIERROR));
  607.     (*ppMAPIError)->ulVersion = MAPI_ERROR_VERSION;
  608.     // See if we have the string for the error. If so, make a copy 
  609.     // and pass it back. The memory for the string will be linked to
  610.     // the memory of the structure so that the caller can make a
  611.     // single release on the structure
  612.     
  613.     // Search for the hResult in the HRESULT map
  614.     UINT i, uMaxNum, uStringID;
  615.     uStringID = 0;
  616.     uMaxNum = sizeof (MapOfhResults) / sizeof (HRESULT);
  617.     for (i=0; i<uMaxNum; i++ )
  618.     {
  619.         if (MapOfhResults[i] == hError)
  620.         {
  621.             break;
  622.         }
  623.     }
  624.  
  625.     if (i == uMaxNum)
  626.     {
  627.         (*ppMAPIError)->ulLowLevelError = LOWORD(hError);
  628.         if (HRESULT_FACILITY(hError) == FACILITY_RPC)
  629.         {
  630.             uStringID = IDS_RPC_ERROR;
  631.         }
  632.         else
  633.         {
  634.             if (HRESULT_FACILITY(hError) == FACILITY_WIN32 ||
  635.                 HRESULT_FACILITY(hError) == FACILITY_NULL)
  636.             {
  637.                 uStringID = IDS_SYSTEM_ERROR;
  638.             }
  639.             else
  640.             {
  641.                 uStringID = IDS_E_UNKNOWN_ERROR;
  642.             }
  643.         }
  644.     }
  645.     else
  646.     {
  647.         uStringID = i + IDS_SUCCESS;
  648.     }
  649.     
  650.     TCHAR szBuffer[512];
  651.     int nCharsRead = LoadString (hInstance, uStringID, szBuffer, sizeof(szBuffer) -1);
  652.     if (!nCharsRead)
  653.     {
  654.         TraceString1 ("GetMAPIError: Could not find error string for ID %d", uStringID);
  655.         hResult = MAPI_E_NOT_FOUND;
  656.     }
  657.     else
  658.     {
  659.         // Allocate memory for return variable and set it.
  660.         // The memory for this string is linked to the memory in the pMemBlock parameter
  661.         hResult = gpfnAllocateMore (Cbtszsize (szBuffer),
  662.                                     *ppMAPIError,
  663.                                     (LPVOID *)&(*ppMAPIError)->lpszError);
  664.         if (!hResult)
  665.         {
  666.             lstrcpy ((*ppMAPIError)->lpszError, szBuffer);
  667.             hResult = gpfnAllocateMore (Cbtszsize (TRANSPORT_DISPLAY_NAME_STRING),
  668.                                         *ppMAPIError,
  669.                                         (LPVOID *)&(*ppMAPIError)->lpszComponent);
  670.             if (!hResult)
  671.             {
  672.                 lstrcpy ((*ppMAPIError)->lpszComponent, TRANSPORT_DISPLAY_NAME_STRING);
  673.             }
  674.             else
  675.             {
  676.                 TraceResult ("GetMAPIError: Failed to allocate the memory for the component string", hResult);
  677.             }
  678.         }
  679.         else
  680.         {
  681.             TraceResult ("GetMAPIError: Failed to allocate the memory for the error string", hResult);
  682.         }
  683.     }
  684.  
  685.     if (hResult)
  686.     {
  687.         gpfnFreeBuffer (*ppMAPIError);
  688.         *ppMAPIError = NULL;
  689.     }
  690.     return hResult;
  691. }
  692.  
  693. ///////////////////////////////////////////////////////////////////////////////
  694. //    XPProviderInit()
  695. //
  696. //    Parameters
  697. //      { Refer to MAPI Documentation on this method }
  698. //
  699. //    Purpose
  700. //      Entry point called by the MAPI spooler when a profile uses this 
  701. //      transport. The spooler calls this method and expects a pointer to an
  702. //      implementation of the IXPProvider interface. MAPI uses the returned
  703. //      IXPProvider interface pointer to logon on the transport provider
  704. //
  705. //    Return Value
  706. //      An HRESULT
  707. //
  708. STDINITMETHODIMP XPProviderInit (HINSTANCE          hInstance, 
  709.                                  LPMALLOC           pMallocObj,
  710.                                  LPALLOCATEBUFFER   pfnAllocateBuffer,
  711.                                  LPALLOCATEMORE     pfnAllocateMore,
  712.                                  LPFREEBUFFER       pfnFreeBuffer,
  713.                                  ULONG              ulFlags,
  714.                                  ULONG              ulMAPIVer,
  715.                                  ULONG *            pulProviderVer,
  716.                                  LPXPPROVIDER *     ppXPProviderObj)
  717. {
  718.     // Look at TRACES.H and TRACES.CPP for more options to the InitTraces() function
  719.     //InitTraces (0);                                       // Send output only to the COM1 port
  720.     InitTraces (TRACES_CONSOLE | TRACES_NO_COM_OUTPUT);     // Send output to a console window BUT NOT to the COM1
  721.     //InitTraces (TRACES_CONSOLE | TRACES_LOG_FILE);        // Send output to COM1 port AND a console window AND to a log file in C:\MAPILOG.TXT
  722.     InfoTrace ("XPProviderInit function called");
  723.     *pulProviderVer = CURRENT_SPI_VERSION;
  724.     if (ulMAPIVer < CURRENT_SPI_VERSION)
  725.     {
  726.         TraceMessage ("XPProviderInit: The version of the subsystem cannot handle this version of the provider");
  727.         return MAPI_E_VERSION;
  728.     }
  729.     // Save the pointer to the allocation routines in global variables
  730.     gpfnAllocateBuffer = pfnAllocateBuffer;
  731.     gpfnAllocateMore   = pfnAllocateMore;
  732.     gpfnFreeBuffer     = pfnFreeBuffer;
  733.     ghInstance         = hInstance;
  734.     // Allocate a new XPProvider object, the constructor will initialize the data member
  735.     CXPProvider * pXPProvider = new CXPProvider (hInstance);
  736.     if (!pXPProvider)
  737.     {
  738.         TraceMessage ("XPProviderInit: Failed to allocate a new CXPProvider object");
  739.         return E_OUTOFMEMORY;
  740.     }
  741.     // Copy pointer to the allocated object back into the return IXPProvider object pointer
  742.     *ppXPProviderObj = (LPXPPROVIDER)pXPProvider;        
  743.     return S_OK;
  744. }
  745.  
  746. // End of file for XPSRVCE.CPP
  747.