home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / winnt / pop3 / pop3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-15  |  32.8 KB  |  1,229 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples.
  4. *       Copyright (C) 1992-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. //+---------------------------------------------------------------------------
  13. //
  14. //  File:       pop3.c
  15. //
  16. //  Contents:   This file contains the code to handle each pop command
  17. //
  18. //----------------------------------------------------------------------------
  19.  
  20. #include "pop3srvp.h"
  21. #pragma hdrstop
  22.  
  23. char *  PopCommands[] = {   POP3_HELO,
  24.                             POP3_USER,
  25.                             POP3_PASS,
  26.                             POP3_QUIT,
  27.                             POP3_STAT,
  28.                             POP3_LIST,
  29.                             POP3_RETR,
  30.                             POP3_DELE,
  31.                             POP3_LAST,
  32.                             POP3_RSET };
  33.  
  34. Pop3DispatchFn  Pop3DispatchTable[] = {
  35.                             HeloDispatch,
  36.                             UserDispatch,
  37.                             PassDispatch,
  38.                             QuitDispatch,
  39.                             StatDispatch,
  40.                             ListDispatch,
  41.                             RetrDispatch,
  42.                             DeleDispatch,
  43.                             LastDispatch,
  44.                             RsetDispatch };
  45.  
  46. #define POP3_STAT_RESPONSE  POP3_GOOD_RESPONSE " %d %d\r\n"
  47. #define POP3_GOOD_RESPLINE  POP3_GOOD_RESPONSE "\r\n"
  48. #define POP3_LIST_RESPLINE  "%d %d\r\n"
  49. #define POP3_TERMINATOR     ".\r\n"
  50. #define POP3_RETR_RESPONSE  POP3_GOOD_RESPONSE " %d octets\r\n"
  51. #define POP3_LAST_RESPONSE  POP3_GOOD_RESPONSE " %d\r\n"
  52.  
  53. #define BANNER_STRING   POP3_GOOD_RESPONSE " POP3 Example Server Ready\r\n"
  54. #define ERROR_POP3_INVALID_STATE     POP3_BAD_RESPONSE " Command not valid in this state\r\n"
  55. #define ERROR_INVALID_USERNAME  POP3_BAD_RESPONSE " Username not valid\r\n"
  56. #define ERROR_AUTH_FAILED       POP3_BAD_RESPONSE " Unable to log on\r\n"
  57. #define ERROR_LOCK_FAILED_S     POP3_BAD_RESPONSE " Unable to lock directory\r\n"
  58. #define ERROR_UNKNOWN_MESSAGE   POP3_BAD_RESPONSE " Unknown message\r\n"
  59. #define ERROR_READ_FAILED_S     POP3_BAD_RESPONSE " Unable to read directory\r\n"
  60. #define ERROR_SERVER_FAILURE    POP3_BAD_RESPONSE " General failure on server\r\n"
  61.  
  62.  
  63. //+---------------------------------------------------------------------------
  64. //
  65. //  Function:   Pop3CrackCommand
  66. //
  67. //  Synopsis:   Takes an input buffer as received from a client, and cracks
  68. //              it to determine the command to execute
  69. //
  70. //  Arguments:  [Request]    -- Input buffer
  71. //              [RequestLen] -- Input buffer length
  72. //
  73. //  History:    1-11-95   RichardW   Created
  74. //
  75. //  Notes:
  76. //
  77. //----------------------------------------------------------------------------
  78. int
  79. Pop3CrackCommand(
  80.     PUCHAR      Request,
  81.     DWORD       RequestLen)
  82. {
  83.     int i;
  84.  
  85.     if (RequestLen < 4)
  86.     {
  87.         return(-1);
  88.     }
  89.  
  90.     for (i = 0; i < MAX_POP3_COMMAND ; i++ )
  91.     {
  92.         if (_strnicmp((PCHAR) Request, PopCommands[i], 4) == 0 )
  93.         {
  94.             return(i);
  95.         }
  96.     }
  97.  
  98.     return(-1);
  99. }
  100.  
  101. //+---------------------------------------------------------------------------
  102. //
  103. //  Function:   CreatePop3Context
  104. //
  105. //  Synopsis:   Creates a client context to keep associated with the socket
  106. //
  107. //  Arguments:  (none)
  108. //
  109. //  History:    1-11-95   RichardW   Created
  110. //
  111. //  Notes:
  112. //
  113. //----------------------------------------------------------------------------
  114. PVOID
  115. CreatePop3Context(void)
  116. {
  117.     PPopContext pContext;
  118.  
  119.     pContext = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PopContext));
  120.     if (pContext)
  121.     {
  122.         pContext->State = PopAuthorization;
  123.         ReportServiceEvent(
  124.             EVENTLOG_INFORMATION_TYPE,
  125.             POP3EVENT_USER_CONNECT,
  126.             0, NULL, 0);
  127.     }
  128.     return(pContext);
  129. }
  130.  
  131. //+---------------------------------------------------------------------------
  132. //
  133. //  Function:   DeletePop3Context
  134. //
  135. //  Synopsis:   Gets rid of the context when the socket closes
  136. //
  137. //  Arguments:  [pvContext] --
  138. //
  139. //  History:    1-11-95   RichardW   Created
  140. //
  141. //  Notes:
  142. //
  143. //----------------------------------------------------------------------------
  144. VOID
  145. DeletePop3Context(PVOID pvContext)
  146. {
  147.     PPopContext pContext;
  148.  
  149.     pContext = (PPopContext) pvContext;
  150.  
  151.     if (pContext->pDirectory)
  152.     {
  153.         FreeMailDirectory(pContext->pDirectory);
  154.         UnlockMailDirectory(pContext->hDirectoryLock);
  155.         CloseHandle(pContext->hUserToken);
  156.     }
  157.  
  158.     LocalFree(pContext);
  159.  
  160. }
  161.  
  162.  
  163. //+---------------------------------------------------------------------------
  164. //
  165. //  Function:   AllocAndCopyString
  166. //
  167. //  Synopsis:   Copies a string into local alloc memory, so that socket code
  168. //              can send it off, then free it.
  169. //
  170. //  Arguments:  [pszString] -- string to copy
  171. //              [pcbString] -- returned length of string
  172. //
  173. //  History:    1-11-95   RichardW   Created
  174. //
  175. //  Notes:
  176. //
  177. //----------------------------------------------------------------------------
  178. PUCHAR
  179. AllocAndCopyString(
  180.     PCHAR   pszString,
  181.     PDWORD  pcbString)
  182. {
  183.     PCHAR   pszNewString;
  184.  
  185.     *pcbString = strlen(pszString);
  186.     pszNewString = LocalAlloc(LMEM_FIXED, *pcbString + 1);
  187.     if (pszNewString)
  188.     {
  189.         strcpy(pszNewString, pszString);
  190.     }
  191.     return((PUCHAR) pszNewString);
  192. }
  193.  
  194. //+---------------------------------------------------------------------------
  195. //
  196. //  Function:   HeloDispatch
  197. //
  198. //  Synopsis:   Handles the HELO command, which, perversely, never gets sent
  199. //              by most clients.
  200. //
  201. //  Arguments:  [pContext]        --
  202. //              [InputBuffer]     --
  203. //              [InputBufferLen]  --
  204. //              [SendHandle]      --
  205. //              [OutputBuffer]    --
  206. //              [OutputBufferLen] --
  207. //
  208. //  History:    1-11-95   RichardW   Created
  209. //
  210. //  Notes:
  211. //
  212. //----------------------------------------------------------------------------
  213. Pop3Disposition
  214. HeloDispatch(
  215.     PPopContext pContext,
  216.     PUCHAR      InputBuffer,
  217.     DWORD       InputBufferLen,
  218.     PHANDLE     SendHandle,
  219.     PUCHAR *    OutputBuffer,
  220.     PDWORD      OutputBufferLen)
  221. {
  222.     DebugLog((DEB_TRACE_PROT, "Received HELO\n"));
  223.  
  224.     //
  225.     // Verify context, and that the context says we can receive this command
  226.     //
  227.  
  228.     if (!pContext)
  229.     {
  230.         return(Pop3_Discard);
  231.     }
  232.  
  233.     if ((pContext->State == PopTransact) ||
  234.         (pContext->State == PopUpdate) )
  235.     {
  236.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  237.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  238.         return(Pop3_SendError);
  239.     }
  240.  
  241.     //
  242.     // Put us into Authorization state
  243.     //
  244.     pContext->State = PopAuthorization;
  245.  
  246.     //
  247.     // No file, but copy the banner string and return it.
  248.     //
  249.     *SendHandle = NULL;
  250.     *OutputBuffer = AllocAndCopyString(BANNER_STRING, OutputBufferLen);
  251.  
  252.     return(Pop3_SendBuffer);
  253.  
  254. }
  255.  
  256. //+---------------------------------------------------------------------------
  257. //
  258. //  Function:   UserDispatch
  259. //
  260. //  Synopsis:   Handles the USER command
  261. //
  262. //  Arguments:  [pContext]        --
  263. //              [InputBuffer]     --
  264. //              [InputBufferLen]  --
  265. //              [SendHandle]      --
  266. //              [OutputBuffer]    --
  267. //              [OutputBufferLen] --
  268. //
  269. //  History:    1-11-95   RichardW   Created
  270. //
  271. //  Notes:
  272. //
  273. //----------------------------------------------------------------------------
  274. Pop3Disposition
  275. UserDispatch(
  276.     PPopContext pContext,
  277.     PUCHAR      InputBuffer,
  278.     DWORD       InputBufferLen,
  279.     PHANDLE     SendHandle,
  280.     PUCHAR *    OutputBuffer,
  281.     PDWORD      OutputBufferLen)
  282. {
  283.     char * Src;
  284.     char * Dst;
  285.  
  286.     DebugLog((DEB_TRACE_PROT, "Received USER\n"));
  287.  
  288.  
  289.     //
  290.     // Verify context, and that the context says we can receive this command
  291.     //
  292.     if (!pContext)
  293.     {
  294.         return(Pop3_Discard);
  295.     }
  296.  
  297.     if (pContext->State != PopAuthorization)
  298.     {
  299.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  300.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  301.         return(Pop3_SendError);
  302.     }
  303.  
  304.     if (InputBufferLen - POP3_COMMAND_LENGTH > USERNAME_LENGTH)
  305.     {
  306.         *OutputBuffer = ERROR_INVALID_USERNAME;
  307.         *OutputBufferLen = sizeof(ERROR_INVALID_USERNAME);
  308.         return(Pop3_SendError);
  309.     }
  310.  
  311.     //
  312.     // Copy in the user name without trailing \r or \n.
  313.     //
  314.  
  315.     Src = InputBuffer + POP3_COMMAND_LENGTH;
  316.     Dst = pContext->UserName;
  317.     while (*Src && (*Src != '\r') && (*Src != '\n'))
  318.     {
  319.         *Dst++ = *Src++;
  320.     }
  321.     *Dst = '\0';
  322.  
  323.     //
  324.     // Set the state so that we are expecting the password
  325.     //
  326.     pContext->State = PopAuthorization2;
  327.  
  328.     *SendHandle = NULL;
  329.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  330.  
  331.     return(Pop3_SendBuffer);
  332.  
  333. }
  334.  
  335.  
  336. //+---------------------------------------------------------------------------
  337. //
  338. //  Function:   PassDispatch
  339. //
  340. //  Synopsis:   Handles the PASS command
  341. //
  342. //  Arguments:  [pContext]        --
  343. //              [InputBuffer]     --
  344. //              [InputBufferLen]  --
  345. //              [SendHandle]      --
  346. //              [OutputBuffer]    --
  347. //              [OutputBufferLen] --
  348. //
  349. //  History:    1-11-95   RichardW   Created
  350. //
  351. //  Notes:
  352. //
  353. //----------------------------------------------------------------------------
  354. Pop3Disposition
  355. PassDispatch(
  356.     PPopContext pContext,
  357.     PUCHAR      InputBuffer,
  358.     DWORD       InputBufferLen,
  359.     PHANDLE     SendHandle,
  360.     PUCHAR *    OutputBuffer,
  361.     PDWORD      OutputBufferLen)
  362. {
  363.     CHAR    pass[MAX_PATH];
  364.     char *  Dst;
  365.     char *  Src;
  366.  
  367.  
  368.     DebugLog((DEB_TRACE_PROT, "Received PASS\n"));
  369.  
  370.  
  371.     //
  372.     // Verify context, and that the context says we can receive this command
  373.     //
  374.  
  375.     if (!pContext)
  376.     {
  377.         return(Pop3_Discard);
  378.     }
  379.  
  380.     if (pContext->State != PopAuthorization2)
  381.     {
  382.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  383.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  384.         return(Pop3_SendError);
  385.     }
  386.  
  387.     //
  388.     // Copy in the password without trailing \r or \n.
  389.     //
  390.  
  391.     Src = InputBuffer + POP3_COMMAND_LENGTH;
  392.     Dst = pass;
  393.     while (*Src && (*Src != '\r') && (*Src != '\n'))
  394.     {
  395.         *Dst++ = *Src++;
  396.     }
  397.     *Dst = '\0';
  398.  
  399.  
  400. #ifdef SECURE_BUILD
  401.  
  402.     //
  403.     // Attempt to log the user on, meaning verify the name and password
  404.     // provided, and get a token back.  The "." we're passing in means
  405.     // use the domain if this machine is part of a domain, or use the local
  406.     // accounts domain.
  407.     //
  408.     if (!LogonUserA(    pContext->UserName,
  409.                         ".",
  410.                         pass,
  411.                         LOGON32_LOGON_INTERACTIVE,
  412.                         LOGON32_PROVIDER_DEFAULT,
  413.                         &pContext->hUserToken) )
  414.     {
  415.         pContext->State = PopAuthorization;
  416.         ReportServiceEvent(
  417.             EVENTLOG_WARNING_TYPE,
  418.             POP3EVENT_LOGON_FAILURE,
  419.             0, NULL,
  420.             0);
  421.  
  422.         *OutputBuffer = ERROR_AUTH_FAILED;
  423.         *OutputBufferLen = sizeof(ERROR_AUTH_FAILED);
  424.         return(Pop3_SendError);
  425.     }
  426.  
  427. #endif
  428.  
  429.     //
  430.     // Now, open and read the mail drop directory
  431.     //
  432.  
  433.     pContext->hDirectoryLock = LockMailDirectory(pContext->hUserToken,
  434.                                                  pContext->UserName);
  435.  
  436.     if (!pContext->hDirectoryLock)
  437.     {
  438.         //
  439.         // Could not lock directory.  Basically, we shut down this connection,
  440.         // and let it go.
  441.         //
  442.  
  443.         DebugLog((DEB_ERROR, "Unable to lock directory, %d\n", GetLastError()));
  444.  
  445.         pContext->State = PopAuthorization;
  446.  
  447.         //
  448.         // Close the token.  This logs the user off.
  449.         //
  450.         CloseHandle(pContext->hUserToken);
  451.         pContext->hUserToken = NULL;
  452.  
  453.         *OutputBuffer = ERROR_LOCK_FAILED_S;
  454.         *OutputBufferLen = sizeof(ERROR_LOCK_FAILED_S);
  455.         return(Pop3_SendError);
  456.     }
  457.  
  458.     pContext->pDirectory = ReadMailDirectory(pContext->hUserToken,
  459.                                              pContext->UserName);
  460.  
  461.     if (!pContext->pDirectory)
  462.     {
  463.         //
  464.         // Couldn't read the directory.  So, we panic and
  465.         // throw it all away.
  466.         //
  467.  
  468.         DebugLog((DEB_ERROR, "Unable to read directory!\n"));
  469.  
  470.         pContext->State = PopAuthorization;
  471.         UnlockMailDirectory(pContext->hDirectoryLock);
  472.         pContext->hDirectoryLock = NULL;
  473.         CloseHandle(pContext->hUserToken);
  474.  
  475.         *OutputBuffer = ERROR_READ_FAILED_S;
  476.         *OutputBufferLen = sizeof(ERROR_LOCK_FAILED_S);
  477.         return(Pop3_SendError);
  478.     }
  479.  
  480.     pContext->State = PopTransact;
  481.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  482.     return(Pop3_SendBuffer);
  483.  
  484. }
  485.  
  486. //+---------------------------------------------------------------------------
  487. //
  488. //  Function:   QuitDispatch
  489. //
  490. //  Synopsis:   Handles the QUIT command
  491. //
  492. //  Arguments:  [pContext]        --
  493. //              [InputBuffer]     --
  494. //              [InputBufferLen]  --
  495. //              [SendHandle]      --
  496. //              [OutputBuffer]    --
  497. //              [OutputBufferLen] --
  498. //
  499. //  History:    1-11-95   RichardW   Created
  500. //
  501. //  Notes:
  502. //
  503. //----------------------------------------------------------------------------
  504. Pop3Disposition
  505. QuitDispatch(
  506.     PPopContext pContext,
  507.     PUCHAR      InputBuffer,
  508.     DWORD       InputBufferLen,
  509.     PHANDLE     SendHandle,
  510.     PUCHAR *    OutputBuffer,
  511.     PDWORD      OutputBufferLen)
  512. {
  513.  
  514.     DebugLog((DEB_TRACE_PROT, "Received QUIT\n"));
  515.  
  516.     //
  517.     // Verify context, and that the context says we can receive this command
  518.     //
  519.  
  520.     if (!pContext)
  521.     {
  522.         return(Pop3_Discard);
  523.     }
  524.  
  525.     if (pContext->State == PopTransact)
  526.     {
  527.         pContext->State = PopUpdate;
  528.  
  529.         CommitMailDirectory(pContext->pDirectory, pContext->hUserToken);
  530.         FreeMailDirectory(pContext->pDirectory);
  531.         UnlockMailDirectory(pContext->hDirectoryLock);
  532.         CloseHandle(pContext->hUserToken);
  533.     }
  534.  
  535.     pContext->State = PopShutdown;
  536.  
  537.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  538.  
  539.     return(Pop3_SendBuffer);
  540.  
  541. }
  542.  
  543.  
  544. //+---------------------------------------------------------------------------
  545. //
  546. //  Function:   StatDispatch
  547. //
  548. //  Synopsis:   Handles the STAT command
  549. //
  550. //  Arguments:  [pContext]        --
  551. //              [InputBuffer]     --
  552. //              [InputBufferLen]  --
  553. //              [SendHandle]      --
  554. //              [OutputBuffer]    --
  555. //              [OutputBufferLen] --
  556. //
  557. //  History:    1-11-95   RichardW   Created
  558. //
  559. //  Notes:
  560. //
  561. //----------------------------------------------------------------------------
  562. Pop3Disposition
  563. StatDispatch(
  564.     PPopContext pContext,
  565.     PUCHAR      InputBuffer,
  566.     DWORD       InputBufferLen,
  567.     PHANDLE     SendHandle,
  568.     PUCHAR *    OutputBuffer,
  569.     PDWORD      OutputBufferLen)
  570. {
  571.  
  572.     char    StatResp[80];
  573.  
  574.     DebugLog((DEB_TRACE_PROT, "Received STAT\n"));
  575.  
  576.     //
  577.     // Verify context, and that the context says we can receive this command
  578.     //
  579.  
  580.     if (!pContext)
  581.     {
  582.         return(Pop3_Discard);
  583.     }
  584.  
  585.     if (pContext->State != PopTransact)
  586.     {
  587.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  588.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  589.         return(Pop3_SendError);
  590.     }
  591.  
  592.     //
  593.     // Print the response into the buffer, then copy it and return it.
  594.     //
  595.  
  596.     sprintf(StatResp, POP3_STAT_RESPONSE, pContext->pDirectory->cAvailMessages,
  597.                         pContext->pDirectory->AvailSize);
  598.  
  599.     *OutputBuffer = AllocAndCopyString(StatResp, OutputBufferLen);
  600.     *SendHandle = NULL;
  601.  
  602.     DebugLog((DEB_TRACE_PROT, "STAT: Sending %s\n", StatResp));
  603.  
  604.     return(Pop3_SendBuffer);
  605.  
  606. }
  607.  
  608.  
  609. //+---------------------------------------------------------------------------
  610. //
  611. //  Function:   ListDispatch
  612. //
  613. //  Synopsis:   Handles the LIST command
  614. //
  615. //  Arguments:  [pContext]        --
  616. //              [InputBuffer]     --
  617. //              [InputBufferLen]  --
  618. //              [SendHandle]      --
  619. //              [OutputBuffer]    --
  620. //              [OutputBufferLen] --
  621. //
  622. //  History:    1-11-95   RichardW   Created
  623. //
  624. //  Notes:
  625. //
  626. //----------------------------------------------------------------------------
  627. Pop3Disposition
  628. ListDispatch(
  629.     PPopContext pContext,
  630.     PUCHAR      InputBuffer,
  631.     DWORD       InputBufferLen,
  632.     PHANDLE     SendHandle,
  633.     PUCHAR *    OutputBuffer,
  634.     PDWORD      OutputBufferLen)
  635. {
  636.     PCHAR       pszBuffer;
  637.     PCHAR       pszWalk;
  638.     DWORD       TotalAlloc;
  639.     DWORD       UsedAlloc;
  640.     DWORD       CharCount;
  641.     DWORD       SingleMessage;
  642.     DWORD       i;
  643.     char        SingleLine[80];
  644.  
  645.  
  646.     DebugLog((DEB_TRACE_PROT, "Received LIST\n"));
  647.  
  648.     //
  649.     // Verify context, and that the context says we can receive this command
  650.     //
  651.  
  652.     if (!pContext)
  653.     {
  654.         return(Pop3_Discard);
  655.     }
  656.  
  657.     if (pContext->State != PopTransact)
  658.     {
  659.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  660.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  661.         return(Pop3_SendError);
  662.     }
  663.  
  664.     //
  665.     // If there is a parameter, process it so we can find out what specific
  666.     // message they want
  667.     //
  668.  
  669.     if (InputBufferLen > POP3_COMMAND_LENGTH)
  670.     {
  671.         SingleMessage = (DWORD) -1;
  672.         sscanf(&InputBuffer[POP3_COMMAND_LENGTH], " %d", &SingleMessage);
  673.  
  674.         //
  675.         // Pop is 1-based, we're 0-based
  676.         //
  677.         SingleMessage--;
  678.  
  679.         if ((SingleMessage > pContext->pDirectory->cMessages) ||
  680.             (pContext->pDirectory->Messages[SingleMessage].Flags & POP3_MESSAGE_DELETE))
  681.         {
  682.             *OutputBuffer = ERROR_UNKNOWN_MESSAGE;
  683.             *OutputBufferLen = sizeof(ERROR_UNKNOWN_MESSAGE);
  684.             return(Pop3_SendError);
  685.         }
  686.  
  687.         sprintf(SingleLine, POP3_STAT_RESPONSE, SingleMessage + 1,
  688.                     pContext->pDirectory->Messages[SingleMessage].Size);
  689.  
  690.         *OutputBuffer = AllocAndCopyString(SingleLine, OutputBufferLen);
  691.         DebugLog((DEB_TRACE_PROT, "LIST: Sending %s", SingleLine));
  692.         return(Pop3_SendBuffer);
  693.     }
  694.  
  695.     //
  696.     // If they want the whole list, send the whole list
  697.     //
  698.     TotalAlloc = pContext->pDirectory->cAvailMessages * 16 + 24;
  699.     pszBuffer = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, TotalAlloc);
  700.     if (!pszBuffer)
  701.     {
  702.         *OutputBuffer = ERROR_SERVER_FAILURE;
  703.         *OutputBufferLen = sizeof(ERROR_SERVER_FAILURE);
  704.         return(Pop3_SendError);
  705.         
  706.     }
  707.     pszWalk = pszBuffer;
  708.     UsedAlloc = 0;
  709.  
  710.     //
  711.     // Copy the header
  712.     //
  713.     CharCount = sprintf(pszWalk, POP3_STAT_RESPONSE,
  714.                         pContext->pDirectory->cAvailMessages,
  715.                         pContext->pDirectory->AvailSize);
  716.  
  717.     pszWalk += CharCount;
  718.     UsedAlloc += CharCount;
  719.     for (i = 0; i < pContext->pDirectory->cMessages ; i++ )
  720.     {
  721.         //
  722.         // For every message not marked deleted, copy it in
  723.         //
  724.         if ((pContext->pDirectory->Messages[i].Flags & POP3_MESSAGE_DELETE) == 0)
  725.         {
  726.             CharCount = sprintf(pszWalk, POP3_LIST_RESPLINE,
  727.                                 i+1, pContext->pDirectory->Messages[i].Size);
  728.             pszWalk += CharCount;
  729.             UsedAlloc += CharCount;
  730.         }
  731.     }
  732.  
  733.     strcpy(pszWalk, POP3_TERMINATOR);
  734.     UsedAlloc += 3;
  735.  
  736.     *OutputBuffer = pszBuffer;
  737.     *OutputBufferLen = UsedAlloc;
  738.  
  739.     DebugLog((DEB_TRACE_PROT, "LIST: Sending %s\n", pszBuffer));
  740.  
  741.     return(Pop3_SendBuffer);
  742.  
  743. }
  744.  
  745. //+---------------------------------------------------------------------------
  746. //
  747. //  Function:   RetrDispatch
  748. //
  749. //  Synopsis:   Handles the RETR command
  750. //
  751. //  Arguments:  [pContext]        --
  752. //              [InputBuffer]     --
  753. //              [InputBufferLen]  --
  754. //              [SendHandle]      --
  755. //              [OutputBuffer]    --
  756. //              [OutputBufferLen] --
  757. //
  758. //  History:    1-11-95   RichardW   Created
  759. //
  760. //  Notes:
  761. //
  762. //----------------------------------------------------------------------------
  763. Pop3Disposition
  764. RetrDispatch(
  765.     PPopContext pContext,
  766.     PUCHAR      InputBuffer,
  767.     DWORD       InputBufferLen,
  768.     PHANDLE     SendHandle,
  769.     PUCHAR *    OutputBuffer,
  770.     PDWORD      OutputBufferLen)
  771. {
  772.     DWORD   MessageId;
  773.     char    Line[40];
  774.  
  775.  
  776.     DebugLog((DEB_TRACE_PROT, "Received RETR\n"));
  777.  
  778.     //
  779.     // Verify context, and that the context says we can receive this command
  780.     //
  781.  
  782.     if (!pContext)
  783.     {
  784.         return(Pop3_Discard);
  785.     }
  786.  
  787.     if (pContext->State != PopTransact)
  788.     {
  789.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  790.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  791.         return(Pop3_SendError);
  792.     }
  793.  
  794.     MessageId = (DWORD) -1;
  795.  
  796.     if (InputBufferLen > POP3_COMMAND_LENGTH)
  797.     {
  798.         sscanf(&InputBuffer[POP3_COMMAND_LENGTH], "%d", &MessageId);
  799.     }
  800.  
  801.     //
  802.     // Pop is 1-based, we're 0-based
  803.     //
  804.     MessageId--;
  805.  
  806.     if ((MessageId > pContext->pDirectory->cMessages) ||
  807.         (pContext->pDirectory->Messages[MessageId].Flags & POP3_MESSAGE_DELETE))
  808.     {
  809.         *OutputBuffer = ERROR_UNKNOWN_MESSAGE;
  810.         *OutputBufferLen = sizeof(ERROR_UNKNOWN_MESSAGE);
  811.         return(Pop3_SendError);
  812.     }
  813.  
  814.  
  815.     //
  816.     // Open the mail message.  We pass in the user's token, so that
  817.     // we can impersonate when we do the open.
  818.     //
  819.  
  820.     *SendHandle = OpenMailMessage(  MessageId,
  821.                                     pContext->pDirectory,
  822.                                     pContext->hUserToken);
  823.  
  824.     if (*SendHandle)
  825.     {
  826.         sprintf(Line, POP3_RETR_RESPONSE,
  827.                 pContext->pDirectory->Messages[MessageId].Size);
  828.         *OutputBuffer = AllocAndCopyString(Line, OutputBufferLen);
  829.         if (pContext->pDirectory->NextMessage < MessageId)
  830.         {
  831.             pContext->pDirectory->NextMessage = MessageId;
  832.         }
  833.  
  834.         return(Pop3_SendBufferThenFile);
  835.  
  836.     }
  837.  
  838.     *OutputBuffer = ERROR_SERVER_FAILURE;
  839.     *OutputBufferLen = sizeof(ERROR_SERVER_FAILURE);
  840.     return(Pop3_SendError);
  841. }
  842.  
  843.  
  844. //+---------------------------------------------------------------------------
  845. //
  846. //  Function:   DeleDispatch
  847. //
  848. //  Synopsis:   Handles the DELE command
  849. //
  850. //  Arguments:  [pContext]        --
  851. //              [InputBuffer]     --
  852. //              [InputBufferLen]  --
  853. //              [SendHandle]      --
  854. //              [OutputBuffer]    --
  855. //              [OutputBufferLen] --
  856. //
  857. //  History:    1-11-95   RichardW   Created
  858. //
  859. //  Notes:
  860. //
  861. //----------------------------------------------------------------------------
  862. Pop3Disposition
  863. DeleDispatch(
  864.     PPopContext pContext,
  865.     PUCHAR      InputBuffer,
  866.     DWORD       InputBufferLen,
  867.     PHANDLE     SendHandle,
  868.     PUCHAR *    OutputBuffer,
  869.     PDWORD      OutputBufferLen)
  870. {
  871.     DWORD   MessageId;
  872.  
  873.  
  874.     DebugLog((DEB_TRACE_PROT, "Received DELE\n"));
  875.  
  876.     //
  877.     // Verify context, and that the context says we can receive this command
  878.     //
  879.  
  880.     if (!pContext)
  881.     {
  882.         return(Pop3_Discard);
  883.     }
  884.  
  885.     if (pContext->State != PopTransact)
  886.     {
  887.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  888.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  889.         return(Pop3_SendError);
  890.     }
  891.  
  892.     MessageId = (DWORD) -1;
  893.  
  894.     if (InputBufferLen > POP3_COMMAND_LENGTH)
  895.     {
  896.         sscanf(&InputBuffer[POP3_COMMAND_LENGTH], "%d", &MessageId);
  897.     }
  898.  
  899.     //
  900.     // Pop is 1-based, we're 0-based
  901.     //
  902.     MessageId--;
  903.  
  904.     if (MessageId > pContext->pDirectory->cMessages ||
  905.         (pContext->pDirectory->Messages[MessageId].Flags & POP3_MESSAGE_DELETE))
  906.     {
  907.         *OutputBuffer = ERROR_UNKNOWN_MESSAGE;
  908.         *OutputBufferLen = sizeof(ERROR_UNKNOWN_MESSAGE);
  909.         return(Pop3_SendError);
  910.     }
  911.  
  912.     //
  913.     // Update directory with "deleted" file
  914.     //
  915.     pContext->pDirectory->Messages[MessageId].Flags |= POP3_MESSAGE_DELETE;
  916.     pContext->pDirectory->cAvailMessages--;
  917.     pContext->pDirectory->AvailSize -= pContext->pDirectory->Messages[MessageId].Size;
  918.  
  919.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  920.     return(Pop3_SendBuffer);
  921. }
  922.  
  923. //+---------------------------------------------------------------------------
  924. //
  925. //  Function:   NoopDispatch
  926. //
  927. //  Synopsis:   Handles the NOOP command
  928. //
  929. //  Arguments:  [pContext]        --
  930. //              [InputBuffer]     --
  931. //              [InputBufferLen]  --
  932. //              [SendHandle]      --
  933. //              [OutputBuffer]    --
  934. //              [OutputBufferLen] --
  935. //
  936. //  History:    1-11-95   RichardW   Created
  937. //
  938. //  Notes:
  939. //
  940. //----------------------------------------------------------------------------
  941. Pop3Disposition
  942. NoopDispatch(
  943.     PPopContext pContext,
  944.     PUCHAR      InputBuffer,
  945.     DWORD       InputBufferLen,
  946.     PHANDLE     SendHandle,
  947.     PUCHAR *    OutputBuffer,
  948.     PDWORD      OutputBufferLen)
  949. {
  950.  
  951.     DebugLog((DEB_TRACE_PROT, "Received NOOP\n"));
  952.  
  953.     //
  954.     // Verify context, and that the context says we can receive this command
  955.     //
  956.  
  957.     if (!pContext)
  958.     {
  959.         return(Pop3_Discard);
  960.     }
  961.  
  962.     if (pContext->State != PopTransact)
  963.     {
  964.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  965.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  966.         return(Pop3_SendError);
  967.     }
  968.  
  969.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  970.     return(Pop3_SendBuffer);
  971. }
  972.  
  973.  
  974. //+---------------------------------------------------------------------------
  975. //
  976. //  Function:   LastDispatch
  977. //
  978. //  Synopsis:   Handles the LAST command
  979. //
  980. //  Arguments:  [pContext]        --
  981. //              [InputBuffer]     --
  982. //              [InputBufferLen]  --
  983. //              [SendHandle]      --
  984. //              [OutputBuffer]    --
  985. //              [OutputBufferLen] --
  986. //
  987. //  History:    1-11-95   RichardW   Created
  988. //
  989. //  Notes:
  990. //
  991. //----------------------------------------------------------------------------
  992. Pop3Disposition
  993. LastDispatch(
  994.     PPopContext pContext,
  995.     PUCHAR      InputBuffer,
  996.     DWORD       InputBufferLen,
  997.     PHANDLE     SendHandle,
  998.     PUCHAR *    OutputBuffer,
  999.     PDWORD      OutputBufferLen)
  1000. {
  1001.     char    Line[40];
  1002.  
  1003.     DebugLog((DEB_TRACE_PROT, "Received LAST\n"));
  1004.  
  1005.     if (!pContext)
  1006.     {
  1007.         return(Pop3_Discard);
  1008.     }
  1009.  
  1010.     if (pContext->State != PopTransact)
  1011.     {
  1012.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  1013.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  1014.         return(Pop3_SendError);
  1015.     }
  1016.  
  1017.     sprintf(Line, POP3_LAST_RESPONSE, pContext->pDirectory->NextMessage+1);
  1018.     *OutputBuffer = AllocAndCopyString(Line, OutputBufferLen);
  1019.  
  1020.     return(Pop3_SendBuffer);
  1021. }
  1022.  
  1023.  
  1024. //+---------------------------------------------------------------------------
  1025. //
  1026. //  Function:   RsetDispatch
  1027. //
  1028. //  Synopsis:   Handles the RSET command
  1029. //
  1030. //  Arguments:  [pContext]        --
  1031. //              [InputBuffer]     --
  1032. //              [InputBufferLen]  --
  1033. //              [SendHandle]      --
  1034. //              [OutputBuffer]    --
  1035. //              [OutputBufferLen] --
  1036. //
  1037. //  History:    1-11-95   RichardW   Created
  1038. //
  1039. //  Notes:
  1040. //
  1041. //----------------------------------------------------------------------------
  1042. Pop3Disposition
  1043. RsetDispatch(
  1044.     PPopContext pContext,
  1045.     PUCHAR      InputBuffer,
  1046.     DWORD       InputBufferLen,
  1047.     PHANDLE     SendHandle,
  1048.     PUCHAR *    OutputBuffer,
  1049.     PDWORD      OutputBufferLen)
  1050. {
  1051.     DWORD   i;
  1052.  
  1053.     DebugLog((DEB_TRACE_PROT, "Received LAST\n"));
  1054.  
  1055.     if (!pContext)
  1056.     {
  1057.         return(Pop3_Discard);
  1058.     }
  1059.  
  1060.     if (pContext->State != PopTransact)
  1061.     {
  1062.         *OutputBuffer = ERROR_POP3_INVALID_STATE;
  1063.         *OutputBufferLen = sizeof(ERROR_POP3_INVALID_STATE);
  1064.         return(Pop3_SendError);
  1065.     }
  1066.  
  1067.     for (i = 0; i < pContext->pDirectory->cMessages ; i++ )
  1068.     {
  1069.         pContext->pDirectory->Messages[i].Flags = 0;
  1070.     }
  1071.  
  1072.     pContext->pDirectory->NextMessage = 0;
  1073.     pContext->pDirectory->cAvailMessages = pContext->pDirectory->cMessages;
  1074.     pContext->pDirectory->AvailSize = pContext->pDirectory->TotalSize;
  1075.  
  1076.     *OutputBuffer = AllocAndCopyString(POP3_GOOD_RESPLINE, OutputBufferLen);
  1077.     return(Pop3_SendBuffer);
  1078. }
  1079.  
  1080.  
  1081.  
  1082. //+---------------------------------------------------------------------------
  1083. //
  1084. //  Function:   Pop3Dispatch
  1085. //
  1086. //  Synopsis:   Dispatch the command
  1087. //
  1088. //  Arguments:  [pContext]        --    Context for client connection
  1089. //              [InputBuffer]     --    Input Buffer (stuff from client)
  1090. //              [InputBufferLen]  --    How much stuff
  1091. //              [SendHandle]      --    Handle to Transmit, if so required
  1092. //              [OutputBuffer]    --    (returned) pointer of stuff to send
  1093. //              [OutputBufferLen] --    (returned) size of stuff to send
  1094. //
  1095. //  Returns:    a Pop3Disposition, which indicates what the socket code
  1096. //              should do with this stuff.  See pop3ctx.h for the dispositions
  1097. //
  1098. //  History:    1-11-95   RichardW   Created
  1099. //
  1100. //  Notes:
  1101. //
  1102. //----------------------------------------------------------------------------
  1103. Pop3Disposition
  1104. Pop3Dispatch(
  1105.     PVOID       pContext,
  1106.     PUCHAR      InputBuffer,
  1107.     DWORD       InputBufferLen,
  1108.     PHANDLE     SendHandle,
  1109.     PUCHAR *    OutputBuffer,
  1110.     PDWORD      OutputBufferLen
  1111.     )
  1112.  
  1113. {
  1114.     PPopContext pPopContext;
  1115.     int     Command;
  1116.  
  1117.     pPopContext = (PPopContext) pContext;
  1118.  
  1119.     //
  1120.     // Null terminate, so string functions won't get confused later.
  1121.     //
  1122.  
  1123.     InputBuffer[InputBufferLen] = L'\0';
  1124.  
  1125.     //
  1126.     // Figure the command out
  1127.     //
  1128.  
  1129.     Command = Pop3CrackCommand(InputBuffer, InputBufferLen);
  1130.  
  1131.     //
  1132.     // If it didn't parse, throw it away
  1133.     //
  1134.     if (Command == -1)
  1135.     {
  1136.         return(Pop3_Discard);
  1137.     }
  1138.  
  1139.     //
  1140.     // Let the command handlers do their thing
  1141.     //
  1142.     return(Pop3DispatchTable[Command](  pPopContext,
  1143.                                         InputBuffer,
  1144.                                         InputBufferLen,
  1145.                                         SendHandle,
  1146.                                         OutputBuffer,
  1147.                                         OutputBufferLen) );
  1148.  
  1149.  
  1150. }
  1151.  
  1152. #if DBG
  1153.  
  1154. //
  1155. // Interactive debug testing
  1156. //
  1157. void TestLoop(void)
  1158. {
  1159.     char    InputBuffer[256];
  1160.     DWORD   InputBufferLen;
  1161.     char *  OutputBuffer;
  1162.     DWORD   OutputBufferLen;
  1163.     HANDLE  hTest;
  1164.     PVOID   pContext;
  1165.     Pop3Disposition Disposition;
  1166.     extern WCHAR BaseDirectory[];
  1167.  
  1168.     printf("-------------------\n");
  1169.     printf("Interactive Test Mode\n");
  1170.  
  1171.     pContext = CreatePop3Context();
  1172.     do
  1173.     {
  1174.         gets(InputBuffer);
  1175.         InputBufferLen = strlen(InputBuffer);
  1176.         if (InputBufferLen)
  1177.         {
  1178.             Disposition = Pop3Dispatch( pContext,
  1179.                                         InputBuffer,
  1180.                                         InputBufferLen,
  1181.                                         &hTest,
  1182.                                         &OutputBuffer,
  1183.                                         &OutputBufferLen);
  1184.  
  1185.             switch (Disposition)
  1186.             {
  1187.                 case Pop3_Discard:
  1188.                     printf("[Discard message]\n");
  1189.                     break;
  1190.  
  1191.                 case Pop3_SendError:
  1192.                     printf("%s", OutputBuffer);
  1193.                     break;
  1194.  
  1195.                 case Pop3_SendBuffer:
  1196.                     printf("%s", OutputBuffer);
  1197.                     LocalFree(OutputBuffer);
  1198.                     break;
  1199.  
  1200.                 case Pop3_SendFile:
  1201.                     printf("Transmit file %x\n", hTest);
  1202.                     printf(".\r\n");
  1203.                     CloseHandle(hTest);
  1204.                     break;
  1205.  
  1206.                 case Pop3_SendBufferThenFile:
  1207.                     printf("%s", OutputBuffer);
  1208.                     printf("Transmit file %x\n", hTest);
  1209.                     printf(".\r\n");
  1210.                     CloseHandle(hTest);
  1211.                     LocalFree(OutputBuffer);
  1212.                     break;
  1213.  
  1214.                 case Pop3_SendFileThenBuffer:
  1215.                     printf("Transmit file %x\n", hTest);
  1216.                     printf("%s", OutputBuffer);
  1217.                     CloseHandle(hTest);
  1218.                     LocalFree(OutputBuffer);
  1219.                     break;
  1220.  
  1221.             }
  1222.  
  1223.         }
  1224.  
  1225.     } while (InputBufferLen);
  1226.  
  1227. }
  1228. #endif
  1229.