Click here to Skip to main content
15,894,646 members
Articles / Desktop Programming / MFC

The Ultimate TCP/IP Home Page

Rate me:
Please Sign up or sign in to vote.
4.98/5 (77 votes)
25 Aug 2007CPOL13 min read 2.6M   45.4K   267  
Ultimate TCP-IP is now Open Source
// =================================================================
//  class: CUT_POP3Server
//  class: CUT_POP3Thread
//  File:  pop3_s.cpp
//
//  Purpose:
//
//  Implementation of the POP3 server and thread classes.
//
// =================================================================
// Ultimate TCP/IP v4.2
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// =================================================================

#ifdef _WINSOCK_2_0_
#define _WINSOCKAPI_    /* Prevent inclusion of winsock.h in windows.h   */
/* Remove this line if you are using WINSOCK 1.1 */
#endif

#include "stdafx.h"

#include "pop3_s.h"
#include "UT_MailServer.h"

#include "ut_strop.h"

#ifdef UT_DISPLAYSTATUS
#include "uh_ctrl.h"
extern CUH_Control  *ctrlHistory;
#endif 

// Suppress warnings for non-safe str fns. Transitional, for VC6 support.
#pragma warning (push)
#pragma warning (disable : 4996)

// =================================================================
// CUT_POP3Server class
// =================================================================

/***************************************
Constructor
****************************************/
CUT_POP3Server::CUT_POP3Server(CUT_MailServer &ptrMailServer) : 
m_ptrMailServer(&ptrMailServer) // Initialize pointer to the Mail Server class
{
    m_nPort = 110; // Set default port number to 110

#ifdef CUT_SECURE_SOCKET
   m_bImmediateNegotiation = FALSE;
#endif
}

/***************************************
Destructor
****************************************/
CUT_POP3Server::~CUT_POP3Server(){

    m_bShutDown = TRUE;
    while(GetNumConnections())
	    Sleep(50);

}

/********************************
CreateInstance
Creates an Instance of a
CUT_POP3Thread class and return
a pointer to it
Params
none
Return
pointer to an instance of a 
CUT_POP3Thread
*********************************/
CUT_WSThread * CUT_POP3Server::CreateInstance(){
    return new CUT_POP3Thread;
}

/********************************
ReleaseInstance
Releases a given instance of a
CUT_POP3Thread class
Params
ptr - pointer to the instance
Return
none
*********************************/
void CUT_POP3Server::ReleaseInstance(CUT_WSThread *ptr){
    if(ptr != NULL)
        delete ptr;
}

/********************************
Start
Starts up the POP3 Server.
Opens the port and listens for connections.
Params
none
Return
UTE_SUCCESS         - success
UTE_CONNECT_FAILED  - connection failed
UTE_ACCEPT_FAILED   - start accepting connections failed
*********************************/
int CUT_POP3Server::Start(){
    if(ConnectToPort(m_nPort) != CUT_SUCCESS)
        return m_ptrMailServer->OnError(UTE_CONNECT_FAILED);
    if(StartAccept() != CUT_SUCCESS)
        return m_ptrMailServer->OnError(UTE_ACCEPT_FAILED);
    
    return m_ptrMailServer->OnError(CUT_SUCCESS);
}

/***************************************************
OnCanAccept
This virtual function is called each time the server 
accepting new connection.
Params
LPCSTR      - IP address of connecting user
Return
TRUE        - accept 
FALSE       - cancel
****************************************************/
long CUT_POP3Server::OnCanAccept(LPCSTR address){
    if(m_ptrMailServer == NULL)
        return TRUE;
    else
        return m_ptrMailServer->OnCanAccept(address);
}

#ifdef CUT_SECURE_SOCKET

/*******************************************
SetImmediateNegotiation
    Set immediate security negotiation flag
Params
    bFlag	- TRUE if security negotiation should
				start right after connection
Return
    none
*******************************************/
void CUT_POP3Server::SetImmediateNegotiation(BOOL bFlag)
{
   m_bImmediateNegotiation = bFlag;
}

#endif

// =================================================================
// CUT_POP3Thread class
// =================================================================

/********************************
OnMaxConnect
This function is called when a
new connection is made and the
system has already reached its
max. number of allowed connections
Params
none
Return 
none
*********************************/
void CUT_POP3Thread::OnMaxConnect(){
    // Send too busy message
    Send("-ERR  System Too Busy Please Try Later\r\n");
    ((CUT_POP3Server *)(m_winsockclass_this))->m_ptrMailServer->OnStatus("-ERR  System Too Busy Please Try Later\r\n");
}

/********************************
OnConnect
This function is called when a new 
connection is made. This function
receives all of the POP3 commands
and processes them
Params
none
Return
none
*********************************/
void CUT_POP3Thread::OnConnect(){
    char            szUserName[WSS_BUFFER_SIZE + 1];
    char            szPassword[WSS_BUFFER_SIZE + 1];
    char            szBuffer[WSS_LINE_BUFFER_SIZE + 1];
    char            messageStatus[MAX_PATH + 1];
    char            ipbuf[32];
    int             nLength;
    BOOL            bLogInState     = FALSE;
    long            lUserHandle     = -1;
    POP3CommandID   nCommand        = CMD_UNKNOWN_POP3;
    BOOL            bQuit           = FALSE;
    CUT_MailServer  *ptrMailServer  = ((CUT_POP3Server *)m_winsockclass_this)->m_ptrMailServer;
    CUT_UserManager *ptrUserManager = ptrMailServer->m_ptrUserManager;

#ifdef CUT_SECURE_SOCKET

	BOOL            bHandshakeDone	= FALSE;	

	// Disable security while connecting
	BOOL bSecureFlag = GetSecurityEnabled();
	if(!ptrMailServer->GetPOP3Server()->m_bImmediateNegotiation)
		SetSecurityEnabled(FALSE);
	else
		bHandshakeDone = TRUE;

#endif

    // Initialize user name and password
    szUserName[0]   = 0;
    szPassword[0]   = 0;
    
    // Initialize client IP address
    _snprintf(ipbuf,sizeof(ipbuf)-1, "%d.%d.%d.%d", m_clientSocketAddr.sin_addr.S_un.S_un_b.s_b1,
        m_clientSocketAddr.sin_addr.S_un.S_un_b.s_b2,
        m_clientSocketAddr.sin_addr.S_un.S_un_b.s_b3,
        m_clientSocketAddr.sin_addr.S_un.S_un_b.s_b4);
    
    // Display status - client IP address 
    ptrMailServer->OnStatus( " " );
    ptrMailServer->OnStatus( ipbuf );
    
    // Send inital message
    Send("+OK  POP3 server ready\r\n");
    ptrMailServer->OnStatus("+OK  POP3 server ready");
    
    // Main loop
    while(bQuit == FALSE) {
        
        // Receive a line from the client
        nLength = ReceiveLine(szBuffer, WSS_LINE_BUFFER_SIZE);
        
        // Exit on an error
        if(nLength <= 0) {
            bQuit = TRUE;
            break;  
        }
        
        CUT_StrMethods::RemoveCRLF(szBuffer);
        if(0 == _strnicmp(szBuffer, "PASS", 4)) 
            ptrMailServer->OnStatus( "PASS *********" );
        else {
            ptrMailServer->OnStatus( "Command rec'd: " );
            ptrMailServer->OnStatus( szBuffer );
        }
        
        // Get the command that was sent
        nCommand = GetCommand(szBuffer);
        
        // Check to see if it is a command that can run without logging in
        switch(nCommand){
            
        case CMD_POP3USER:
			{
#ifdef CUT_SECURE_SOCKET

			if(!bHandshakeDone  && bSecureFlag )
			{
				if(!OnNonSecureConnection(GetClientAddress()))
				{
					Send("-ERR Secure connection required\r\n");
					ptrMailServer->OnStatus("Non secure connection rejected");
					bQuit = TRUE;
					continue;
				}
			}
            
#endif

            // Save the user name
            CUT_StrMethods::ParseString(szBuffer," ",1,szUserName, WSS_BUFFER_SIZE);
            
            // Send back a notification
            // always send OK even if the wrong user is entered
            // this way password cracking is harder
            Send("+OK\r\n");
            strcpy(messageStatus,szUserName);
            strcat(messageStatus," POP3: USER NAME OK");
            ptrMailServer->OnStatus(messageStatus);
            continue;
            }
            
        case CMD_POP3PASS:
			{
#ifdef CUT_SECURE_SOCKET

			if(!bHandshakeDone  && bSecureFlag )
			{
				if(!OnNonSecureConnection(GetClientAddress()))
				{
					Send("-ERR Secure connection required\r\n");
					ptrMailServer->OnStatus("Non secure connection rejected");
					bQuit = TRUE;
					continue;
				}
			}
				
#endif

			// Save the user name
            CUT_StrMethods::ParseString(szBuffer," ",1,szPassword,WSS_BUFFER_SIZE);
            
            // Check to see if the user exists
			// v4.2 using WC here - user info is now _TCHAR
            lUserHandle = ptrUserManager->User_OpenUser(WC(szUserName),WC(szPassword));
            
            if(lUserHandle < 0) {
                
                // Send back a access denied notification
                Send("-ERR\r\n");
                strcpy(messageStatus,szUserName);
                strcat(messageStatus," POP3: PASSWORD ERROR");
                ptrMailServer->OnStatus(messageStatus);
            }
            else {
                
                // Send back a notification
                Send("+OK\r\n");
                strcpy(messageStatus,szUserName);
                strcat(messageStatus," POP3:  PASSWORD OK");
                ptrMailServer->OnStatus(messageStatus);
                bLogInState = TRUE;
            }
            continue;
                          }
            
        case CMD_POP3NOOP: 
            {
                // Just send an OK notify
                Send("+OK\r\n");
                strcpy(messageStatus,szUserName);
                strcat(messageStatus," POP3: NOOP OK");
                ptrMailServer->OnStatus(messageStatus);
                continue;
            }
            
        case CMD_POP3QUIT:
            {
                // Send an OK command
                Send("+OK\r\n");
                strcpy(messageStatus,szUserName);
                strcat(messageStatus," POP3: QUIT OK");
                ptrMailServer->OnStatus(messageStatus);
                
                // Exit the message pump loop
                bQuit = TRUE;
                continue;
            }
		
		case CMD_CAPA:
			{
				// Start capabilties list
				Send("+OK Capability list follows\r\n");
				Send("TOP\r\n");
				Send("USER\r\n");
				Send("UIDL\r\n");

#ifdef CUT_SECURE_SOCKET

				// Add TLS in the secure server
				if(bSecureFlag && !bHandshakeDone)
					Send("STARTTLS\r\n");
				
#endif

				// End of capabilities list
				Send(".\r\n");

				continue;
			}

        case CMD_STLS:
            {

#ifdef CUT_SECURE_SOCKET

				if(bSecureFlag)
				{
					// Already done
					if(bHandshakeDone)
					{
						Send("-ERR Command not permitted when TLS active\r\n");
						continue;
					}

					// Send an OK command
					Send("+OK Begin TLS negotiation\r\n");

					// Set security flag
					SetSecurityEnabled(TRUE);

					// Start negotiation
					int nResult = CUT_SecureSocket::SocketOnConnected(m_clientSocket, "");
					if (nResult != UTE_SUCCESS)
					{
						SetSecurityEnabled(FALSE);									
						Send("-ERR  The SSL negotiation failed during the handshake");
						bQuit = TRUE;
						continue;
					} 
					else
					{
						Send("+OK\r\n");
						bHandshakeDone =  TRUE;
						continue;
					}
				}
				else
					Send("+ERR TLS is not supported\r\n");

#else

				Send("+ERR TLS is not supported\r\n");

#endif

                continue;
            }
		default:
                    {
                        if(bLogInState == FALSE) {
                            Send("-ERR authentication exchange failed\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus,"POP3 -ERR Unknown Command");
                            ptrMailServer->OnStatus(messageStatus);
						    continue;
                            }
                    }

        }
        
        // Check to see if the client is logged in
        if(bLogInState == TRUE) {
            
            // Check the rest of the commands
            switch(nCommand) {
                
            case CMD_POP3STAT:
                {
                    // Get the size of all messages
                    long totalSize =0;
                    long index;
                    long numDeleted = 0, numMsgs = ptrUserManager->User_GetFileCount(lUserHandle);
                    for(index = 0; index < numMsgs; index++)
                        if(!ptrUserManager->User_IsFileDeleted(lUserHandle,index))
                            totalSize += ptrUserManager->User_GetFileSize(lUserHandle,index);
                        else
                            ++numDeleted;
                        
                        _snprintf(szBuffer,sizeof(szBuffer)-1,"+OK %d %ld\r\n",numMsgs - numDeleted,totalSize);
                        Send(szBuffer);
                        
                        strcpy(messageStatus,szUserName);
                        strcat(messageStatus," POP3: STAT ");
                        ptrMailServer->OnStatus(messageStatus);
                        continue;
                }
            case CMD_POP3LIST:
                {
                    // Find which message to show
                    long param;
                    if(CUT_StrMethods::ParseString(szBuffer," ",1,&param) == CUT_SUCCESS){
                        param --;  // POP3 starts from one CDataManager starts from 0
                        
                        // Show the single message size
                        if(param < 0 || param >= ptrUserManager->User_GetFileCount(lUserHandle)) {
                            Send("-ERR  Invalid Message Number\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                        else if(ptrUserManager->User_IsFileDeleted(lUserHandle,param)) {
                            Send("-ERR  Message marked as deleted\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Message marked as deleted");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                        else {
                            _snprintf(szBuffer,sizeof(szBuffer)-1,"+OK %d %ld\r\n",param+1,
                                ptrUserManager->User_GetFileSize(lUserHandle,param));
                            Send(szBuffer);
                            
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: Message Size");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                    }
                    else {
                        // Show the total size for all the messages
                        long totalSize =0;
                        long index;
                        long numDeleted = 0, numMsgs = ptrUserManager->User_GetFileCount(lUserHandle);
                        for(index = 0; index < numMsgs; index++)
                            if(!ptrUserManager->User_IsFileDeleted(lUserHandle,index))
                                totalSize += ptrUserManager->User_GetFileSize(lUserHandle,index);
                            else
                                ++numDeleted;
                            
                            _snprintf(szBuffer,sizeof(szBuffer)-1,"+OK %d messages (%ld octets)\r\n",numMsgs - numDeleted,totalSize);
                            Send(szBuffer);
                            
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: Total size of all messages ");
                            ptrMailServer->OnStatus(messageStatus);  
                            
                            // Now show the size of each
                            for(index = 0; index < numMsgs; index++) {
                                if(!ptrUserManager->User_IsFileDeleted(lUserHandle,index)) {
                                    _snprintf(szBuffer,sizeof(szBuffer)-1,"%d %ld\r\n",index+1,
                                        ptrUserManager->User_GetFileSize(lUserHandle,index));
                                    Send(szBuffer);
                                }
                            }
                            
                            Send(".\r\n");
                    }
                    continue;
                }
                
            case CMD_POP3RETR:
                {
                    // Find which message to send
                    long param;
                    if(CUT_StrMethods::ParseString(szBuffer," ",1,&param) == CUT_SUCCESS) {
                        param --;  // POP3 starts from one CDataManager starts from 0
                        
                        // Check to see if the message is valid
                        if(param < 0 || param >= ptrUserManager->User_GetFileCount(lUserHandle)) {
                            Send("-ERR  Invalid Message Number\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);  
                            continue;
                        }
                        else if(ptrUserManager->User_IsFileDeleted(lUserHandle,param)) {
                            Send("-ERR  Message marked as deleted\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Message marked as deleted");
                            ptrMailServer->OnStatus(messageStatus);
                            continue;
                        }
                        
                        
                        // Send the message size
                        _snprintf(szBuffer,sizeof(szBuffer)-1,"+OK %ld octets\r\n",
                            ptrUserManager->User_GetFileSize(lUserHandle,param));
                        Send(szBuffer);
                        
                        strcpy(messageStatus,szUserName);
                        strcat(messageStatus,szBuffer);
                        ptrMailServer->OnStatus(messageStatus);
                        
                        // Send the message
                        long fileHandle;
                        int  len,lastLen = 0;
                        fileHandle = ptrUserManager->User_OpenFile(lUserHandle,param);
                        if(fileHandle < 0) {
                            Send("-ERR  Invalid Message Number\r\n");
                            
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                            continue;
                        }   
                        
						for (;;) {
							// Read with space for null...
                            len = ptrUserManager->User_ReadFile(fileHandle,(LPBYTE)szBuffer, WSS_LINE_BUFFER_SIZE);
                            if(len <= 0)
                                break;
                            Send(szBuffer,len);
                            lastLen = len;
                        }
                        
                        // Check for crlf.crlf - not foolproof, since we could have
                        // a small read ( < 5 bytes) 
                        if(lastLen >= 5) {
                            *(szBuffer+lastLen) = 0; // terminate string
                            if(!strstr(szBuffer, "\r\n.\r\n")) {
                                ptrMailServer->OnStatus( "ALERT: Malformed closure on message!");
                                Send("\r\n\r\n.\r\n");
                            }
                        }
                        
                        ptrUserManager->User_CloseFile(fileHandle);
                    }
                    else {
                        Send("-ERR  Invalid Message Number\r\n");
                        strcpy(messageStatus,szUserName);
                        strcat(messageStatus," POP3: -ERR  Invalid Message Number");
                        ptrMailServer->OnStatus(messageStatus);
                    }
                    continue;
                }
                
            case CMD_POP3UIDL: 
                {
                    // Client requests unique ID of message
                    // is there a second param?
                    long param;
                    if(CUT_StrMethods::ParseString(szBuffer," ",1,&param) == CUT_SUCCESS){
                        // Yes - send message id for this message..
                        param --;  // POP3 starts from one CDataManager starts from 0
                        
                        // Check to see if the message is valid
                        if(param < 0 || param >= ptrUserManager->User_GetFileCount(lUserHandle)) {
                            Send("-ERR  Invalid Message Number\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: TOP -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                            continue;
                        }
                        else if(ptrUserManager->User_IsFileDeleted(lUserHandle,param)) {
                            Send("-ERR  Message marked as deleted\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: -ERR  Message marked as deleted");
                            ptrMailServer->OnStatus(messageStatus);
                            continue;
                        }
                        
                        
                        long fileHandle;
                        fileHandle = ptrUserManager->User_OpenFile(lUserHandle,param);
                        if(fileHandle < 0) {
                            Send("-ERR  Invalid Message Number\r\n");
                            
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: UIDL -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                            continue;
                        }
                        
                        char buf[20];
                        if(CUT_SUCCESS == ptrMailServer->GetUIDL(fileHandle,param, (LPBYTE)szBuffer, WSS_LINE_BUFFER_SIZE)) {
                            _snprintf(buf,sizeof(buf)-1, "+OK %d ", param+1);
                            Send(buf);
                            Send(szBuffer);
                            Send("\r\n");
                            
                            ptrMailServer->OnStatus(buf);
                            ptrMailServer->OnStatus(szBuffer);
                        }
                        else {          
                            _snprintf(buf,sizeof(buf)-1, "-ERR %d ", param+1);      // should never happen!  Incoming mail
                            Send(buf);                              // has Message-ID: attached if none exists!
                            Send(" message ID not found\r\n");
                            ptrMailServer->OnStatus(buf);
                            ptrMailServer->OnStatus("POP3 UIDL N **Failed to get UIDL**");
                        }
                        
                        ptrUserManager->User_CloseFile(fileHandle);
                        
                    }
                    else {
                        // Get multiline response - message ids for all messages
                        // Get number of messages for user...
                        int fileCount = ptrUserManager->User_GetFileCount(lUserHandle);
                        
                        // Should always be at least one file if client calls this, 
                        // but...
                        if(-1 == fileCount) {
                            Send("-ERR no messages");
                            ptrMailServer->OnStatus("UIDL called with no mail on server");
                            continue;
                        }
                        else
                            Send("+OK unique-id listing follows\r\n");
                        
                        // Ok - loop through file count, sending id's
                        long fileHandle;
                        char buf[20];
                        for(int i = 0; i < fileCount; i++) {
                            
							// if the file is not deleted
                            if(!ptrUserManager->User_IsFileDeleted(lUserHandle,i)) {
                              
								// the following error should never happen
								// unless a file which is not six degits is being added to the users inbox
								// perhapse we should add some alert to the administrator
								// instead of shutting off the server
								// also it will not compile on an alpha machine
								// INTERNAL ERROR 
								if(-1 == (fileHandle = ptrUserManager->User_OpenFile(lUserHandle,i))) {
                                    ptrMailServer->OnStatus("Error processing UIDL...");
						
									
									_snprintf(buf,sizeof(buf)-1, "-ERR %d ", param+1);      
									Send(buf);                            
									Send(" system error in UIDL\r\n");
									ptrMailServer->OnStatus(buf);
									ptrMailServer->OnStatus("POP3 UIDL N **Failed to get UIDL - bad filename**");
									
						//			_asm int 3; // need to test...
                                    continue;
								}
                                
                                _snprintf(buf,sizeof(buf)-1, "%d ", i+1);
                                if(CUT_SUCCESS == ptrMailServer->GetUIDL(fileHandle, i,(LPBYTE) szBuffer, WSS_LINE_BUFFER_SIZE)) {
                                    Send(buf);
                                    Send(szBuffer);
                                    Send("\r\n");
                                    ptrMailServer->OnStatus(szBuffer);
                                }
                                else {
                                    Send(buf);
                                    Send("no message id");
                                    Send("\r\n");
                                    ptrMailServer->OnStatus("POP3 UIDL ERROR retrieving Message-ID");
                                }
                                
                                ptrUserManager->User_CloseFile(fileHandle);
                            }
                        }
                        
                        // End multiline response
                        Send(".\r\n");
                    }
                    continue;
                    }
                    
                case CMD_POP3TOP:
                    {
                        
                        // Find which message to send the top of 
                        long param;
                        long lines = 1;
                        if(CUT_StrMethods::ParseString(szBuffer," ",1,&param) == CUT_SUCCESS){
                            param --;  //POP3 starts from one CDataManager starts from 0
                            
                            // Check to see if the message is valid
                            if(param < 0 || param >= ptrUserManager->User_GetFileCount(lUserHandle)) {
                                Send("-ERR  Invalid Message Number\r\n");
                                strcpy(messageStatus,szUserName);
                                strcat(messageStatus," POP3: TOP -ERR  Invalid Message Number");
                                ptrMailServer->OnStatus(messageStatus);
                                continue;
                            }
                            else if(ptrUserManager->User_IsFileDeleted(lUserHandle,param)) {
                                Send("-ERR  Message marked as deleted\r\n");
                                strcpy(messageStatus,szUserName);
                                strcat(messageStatus," POP3: -ERR  Message marked as deleted");
                                ptrMailServer->OnStatus(messageStatus);
                                continue;
                            }
                            
                            // Get the number of message lines to send
                            if(CUT_StrMethods::ParseString(szBuffer," ",2,&lines) != CUT_SUCCESS)
                                lines = 0;
                            
                            // Send the message top
                            long fileHandle;
                            fileHandle = ptrUserManager->User_OpenFile(lUserHandle,param);
                            if(fileHandle < 0) {
                                Send("-ERR  Invalid Message Number\r\n");
                                strcpy(messageStatus,szUserName);
                                strcat(messageStatus," POP3: TOP -ERR  Invalid Message Number");
                                ptrMailServer->OnStatus(messageStatus);
                                continue;
                            }
                            
                            Send("+OK Top of Message Follows\r\n");
                            ptrMailServer->OnStatus("+OK Top of Message Follows\r\n");
                            
                            int  len = -2;
                            while (len != 0 && len != -1) { // crlf indicates blank line (EOH)
                                len = ptrMailServer->ReadLineFromFile(fileHandle,(LPBYTE)szBuffer, WSS_LINE_BUFFER_SIZE);
                                if(len > 0) {
                                    Send(szBuffer, len);   // avoid call to strlen
                                    Send("\r\n");       // readline strips these
                                }
                            }
                            
                            Send("\r\n");       // send blank line - header done
                            
                            // Ok - got header and blank - now simply send number of lines.
                            BOOL sentLast = false;
                            for (int i = 0; i < lines; i++) {
                                len = ptrMailServer->ReadLineFromFile(fileHandle,(LPBYTE)szBuffer, WSS_LINE_BUFFER_SIZE);
                                if(len > 0) {
                                    Send(szBuffer, len);
                                    Send("\r\n");
                                    if(!strcmp(szBuffer, "."))
                                        sentLast = true;
                                }
                                else if(len == 0) {
                                    Send("\r\n");
                                    }
                                else {
                                    break;  // may have asked for too many lines...
                                    }
                            }
                            
                            if(!sentLast) 
                                Send(".\r\n");
                            
                            
                            ptrUserManager->User_CloseFile(fileHandle);
                        }
                        else {
                            Send("-ERR  Invalid Message Number\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: TOP -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                        continue;
                    }
                    
                case CMD_POP3DELE:
                    {
                        // Find which message to delete
                        long param;
                        if(CUT_StrMethods::ParseString(szBuffer," ",1,&param) == CUT_SUCCESS){
                            param --;  //POP3 starts from one CDataManager starts from 0
                            
                            // Check to see if the message is valid
                            if(param < 0 || param >= ptrUserManager->User_GetFileCount(lUserHandle)){
                                Send("-ERR  Invalid Message Number\r\n");
                                strcpy(messageStatus,szUserName);
                                strcat(messageStatus," POP3: DELE -ERR  Invalid Message Number");
                                ptrMailServer->OnStatus(messageStatus);
                                continue;
                            }
                            else if(ptrUserManager->User_IsFileDeleted(lUserHandle,param)) {
                                Send("-ERR  Message marked as deleted\r\n");
                                strcpy(messageStatus,szUserName);
                                strcat(messageStatus," POP3: -ERR  Message marked as deleted");
                                ptrMailServer->OnStatus(messageStatus);
                                continue;
                            }
                            
                            // Mark the file for deletion
                            ptrUserManager->User_DeleteFile(lUserHandle,param);
                            
                            // Send a notify back
                            Send("+OK\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: DELE OK");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                        else {
                            Send("-ERR  Invalid Message Number\r\n");
                            strcpy(messageStatus,szUserName);
                            strcat(messageStatus," POP3: DELE -ERR  Invalid Message Number");
                            ptrMailServer->OnStatus(messageStatus);
                        }
                        continue;
                    }
                    
                case CMD_POP3RSET:
                    {
                        // Reset the deletion list
                        ptrUserManager->User_ResetDelete(lUserHandle);
                        Send("+OK\r\n");
                        continue;
                    }
                default:
                    {
                        Send("-ERR Unknown Command\r\n");
                        strcpy(messageStatus,szUserName);
                        strcat(messageStatus,"POP3 -ERR Unknown Command");
                        ptrMailServer->OnStatus(messageStatus);
                    }
                }
            }   
        }
        
        // Close the user, close also deletes all marked files
        if(lUserHandle >= 0)
            ptrUserManager->User_CloseUser(lUserHandle);
        
        _snprintf(messageStatus,sizeof(messageStatus)-1,"POP3  %s has disconnected" ,szUserName);    
        ptrMailServer->OnStatus(messageStatus);
        
}

/********************************
GetCommand
Returns a command ID from the given
command line
Params
data - command line
Return
CMD_UNKNOWN - Unknown command
valid commands:
CMD_POP3USER,CMD_POP3PASS,CMD_POP3STAT
CMD_POP3LIST,CMD_POP3RETR,CMD_POP3DELE
CMD_POP3NOOP,CMD_POP3RSET,CMD_POP3QUIT  
*********************************/
POP3CommandID CUT_POP3Thread::GetCommand(LPSTR data){
    
    char    buf[10];
    char    *lpszCommandsList[] = { "USER", "PASS", "STAT", "LIST", "RETR", 
        "DELE", "NOOP", "RSET", "QUIT", "TOP ", "UIDL", "STLS", "CAPA"};
    
    strncpy(buf, data, 5);
    buf[4] = 0;
    _strupr(buf);
    
    for(int i = (int)CMD_POP3USER; i <= (int)CMD_CAPA ; i++) 
        if(strcmp(buf, lpszCommandsList[i - (int)CMD_POP3USER]) == 0)
            return (POP3CommandID) i;
        
        return CMD_UNKNOWN_POP3;
}

#ifdef CUT_SECURE_SOCKET
/*******************************************
	When security is enabled some ftp clients may 
	try to connect to the secure FTP
	This flag attempt enable or disable non secure connection on a secure server

PARAM
	flag	-	 TRUE = allow non secure clients to connect
			-	 FALSE =	 Only secure clients allowed
*******************************************/
BOOL CUT_POP3Thread::OnNonSecureConnection(LPCSTR /* IpAddress */)
{
   return FALSE;
}

int CUT_POP3Thread::SocketOnConnected(SOCKET s, const char *lpszName)
{
	CUT_MailServer  *ptrMailServer  = ((CUT_POP3Server *)m_winsockclass_this)->m_ptrMailServer;
	if(ptrMailServer->GetPOP3Server()->m_bImmediateNegotiation) {
		// v4.2 note : notifications still taking char
		return CUT_SecureSocket::SocketOnConnected(s, lpszName);
	}
	else
		return UTE_SUCCESS;
}

#endif

#pragma warning ( pop )

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions