Click here to Skip to main content
15,888,803 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 255.1K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// =================================================================
//  class: CUT_POP3Client
//  File:  pop3_c.cpp
//
//  Purpose:
//
//  POP3 Client Class 
//  Implementation of Post Office version 3 Protocol
//
//  RFC  1939
//      
// ===================================================================
// 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_c.h"

#include "ut_strop.h"

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


/********************************
*********************************/
CUT_POP3Client::CUT_POP3Client() : 
        m_nPort(110),               // Set default connection port to 110
        m_nConnectTimeout(5),       // Connection time out. Default 5 sec.
        m_nPOP3TimeOut(10),         // POP3 time out. Default 10 sec.
        m_bMsgOpen(FALSE),          // no mesage open for reading 
        m_bTopOpen(FALSE),          // No message open for TOP command 
        m_bReadMsgFinished(FALSE),
        m_bReadTopFinished(FALSE)
{
}
/********************************
*********************************/
CUT_POP3Client::~CUT_POP3Client(){
}
/********************************
POP3Connect()
    Connect to port 110 on a POP3 server informing it of the 
    user name and password. 
PARAM:
    mailHost    - server ip address or name.
    user        - user account id
    password    - account password
RETURN:
    UTE_SOCK_ALREADY_OPEN   - socket already open or in use
    UTE_SOCK_CREATE_FAILED  - socket creation failed
    UTE_SOCK_CONNECT_FAILED - socket connection failed
    UTE_INVALID_ADDRESS     - invalid address
    UTE_SUCCESS             - success
    UTE_CONNECT_TIMEOUT     - connect time out
    UTE_USER_FAILED         - user command has timed out or rejected 
    UTE_PASS_FAILED         - passwrod command Timed out or rejected
    UTE_ABORTED             - aborted
*********************************/
#if defined _UNICODE 
int CUT_POP3Client::POP3Connect(LPCWSTR mailHost, LPCWSTR user, LPCWSTR password) {
	return POP3Connect( AC(mailHost), AC(user), AC(password));}
#endif 
int CUT_POP3Client::POP3Connect(LPCSTR mailHost, LPCSTR user, LPCSTR password) {

    int     error;

    //close any open connection
    POP3Close();

    //connect
    if((error = Connect(m_nPort, mailHost, m_nConnectTimeout)) != UTE_SUCCESS) 
        return OnError(error);
    
    //get the response code
	if(GetResponseCode(m_nPOP3TimeOut) == FALSE)
		return OnError(UTE_CONNECT_TIMEOUT);

    //send the user name
    Send("USER ");
    Send(user);
    Send("\r\n");

    if(GetResponseCode(m_nPOP3TimeOut) == FALSE)
        return OnError(UTE_USER_FAILED);

    if(IsAborted())         // Test for abortion flag
        return OnError(UTE_ABORTED);

    //send the password
    Send("PASS ");
    Send(password);
    Send("\r\n");

    if(GetResponseCode(m_nPOP3TimeOut) == FALSE)
        return OnError(UTE_PASS_FAILED);


    return OnError(UTE_SUCCESS);
}
/********************************
POP3Close() 
    Close connection to the pop3 server by
    issuing a QUIT command
PARAM:
    NONE
RETURN:
    UTE_SUCCESS     - success
    UTE_ERROR       - failed
*********************************/
int CUT_POP3Client::POP3Close(){

	// v4.2 - update 02 - change suggested by Sergey Kolomenkin - (TD -  
	//                    careful here - IsConnected is not infallible
	//Send("Quit\r\n");
	if(IsConnected()) // QUIT command should be sent and reply should be read only if connected
	{
		Send("QUIT\r\n"); // Sergey Kolomenkin: upper case is more commonly used (but is not necessary by RFC 1939)+		
		// Sergey Kolomenkin: QUIT command needs response:
		if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
			return OnError(UTE_SVR_NO_RESPONSE);
	}
	return CloseConnection();
}

/********************************************************************
GetNumMsgs
    The objective of this function is to retrieve the number 
    of messages stored in the server for the user maildrop. 

NOTE: Server should not include any messages marked for deletion in the response

PARAM:
    int *number - pionter to the number of available messages
RETURN:
    UTE_NOCONNECTION        - NOT connected
    UTE_SVR_NO_RESPONSE     - no response from Server
    UTE_STAT_FAILED         - STAT command was not reponded to positivly
    UTE_INVALID_RESPONSE    - Malformed response
*********************************************************************/
int CUT_POP3Client::GetNumMsgs(int *number){

    char param[MAX_PATH+1];

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the STAT command
    Send("STAT\r\n");

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_STAT_FAILED);

    CUT_StrMethods::RemoveCRLF(m_szBuf);

    if(CUT_StrMethods::ParseString(m_szBuf," ",1,param,sizeof(param)) != UTE_SUCCESS)
        return OnError(UTE_INVALID_RESPONSE);

    *number = atoi(param);

    return OnError(UTE_SUCCESS);
}

/********************************
GetMsgSize()
    Retrieve the size of the message specified by the index.
    When this function is invoked on a valid connection and the message 
    specified by the Index is not marked for deletion, The POP3 server 
    issues a positive response with a line containing 
    information for the message.
PARAM
    int index - the message number 
    long *size - pointer to the message size
RETURN
    UTE_NOCONNECTION        - NOT connected
    UTE_SVR_NO_RESPONSE     - no response from Server
    UTE_LIST_FAILED         - LIST command was not reponded to positivly
    UTE_INVALID_RESPONSE    - Malformed response
*********************************/
int CUT_POP3Client::GetMsgSize(int index,long *size){

    char param[MAX_PATH+1];

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the LIST command
    _snprintf(m_szBuf,sizeof(m_szBuf)-1,"LIST %d\r\n",index);
    Send(m_szBuf);

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_LIST_FAILED);

    CUT_StrMethods::RemoveCRLF(m_szBuf);
    
    // a server response to a LIST command that includes an argument
    // should have +OK[SPACE]messageNumber[SPACE]size
    // Hence we will be looking for the third octet of the server response
    if(CUT_StrMethods::ParseString(m_szBuf," ()",2,param,sizeof(param)) != UTE_SUCCESS)
        return OnError(UTE_INVALID_RESPONSE);

    *size = atol(param);

    return OnError(UTE_SUCCESS);
}

/********************************
SaveMsg()
    Retrives (RETR) and Saves the specified message to disk storage
NOTE
    Message index is 1 based NOT zero based
PARAM   
    index       - Index of the message to be saved
    fileName    - name and path of the destination file to save the message to
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_FILE_OPEN_ERROR - Not able to open file for writing
    UTE_RETR_FAILED     - RETR command has timed out without a response from the server
    UTE_SOCK_TIMEOUT    - Timed out while receiving parts of the message
    UTE_ABORTED         - User canceled the Save to file process
*********************************/
int CUT_POP3Client::SaveMsg(int index, LPCTSTR fileName) {
    CUT_FileDataSource  dsFile(fileName);
    return SaveMsg(index, dsFile);
}

/********************************
SaveMsg()
    Retrives (RETR) and Saves the specified message to 
    the data source
NOTE
    Message index is 1 based NOT zero based
PARAM   
    index       - Index of the message to be saved
    dest        - destination data source
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_FILE_OPEN_ERROR - Not able to open file for writing
    UTE_RETR_FAILED     - RETR command has timed out without a response from the server
    UTE_SOCK_TIMEOUT    - Timed out while receiving parts of the message
    UTE_ABORTED         - User canceled the Save to file process
*********************************/
int CUT_POP3Client::SaveMsg(int index, CUT_DataSource & dest) {

    int         error = UTE_SUCCESS;
    int         len;
    UINT        bytesReceived = 0;

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //open the destination file
    if(dest.Open(UTM_OM_WRITING) == -1)
        return OnError(UTE_FILE_OPEN_ERROR);

    //send the RETR command
    _snprintf(m_szBuf,sizeof(m_szBuf)-1,"RETR %d\r\n",index);
    Send(m_szBuf);
    

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf)-1, m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_RETR_FAILED);

    //read in and save the message
	// v4.2 change to eliminate C4127: conditional expression is constant
    for(;;) {
        if(IsAborted()) {       // Test for abortion flag
            error = UTE_ABORTED;
            break;
            }
    
        //read in a line
        len = ReceiveLine(m_szBuf,sizeof(m_szBuf)-1,m_nPOP3TimeOut);


        if( len  <= 0 ) {
            error = UTE_SOCK_TIMEOUT;
            break;
            }

        bytesReceived += len;

        if (OnSaveMsg(bytesReceived) != TRUE) {
            error = UTE_ABORTED;       // User cancel the save message
            break; // call status func
            }

        //if a period is found at the beginning of a line then
        //check to see if it is the end of the message
        if(m_szBuf[0] == '.') {
            //end of message
            if(len == 3)       
                break;
            
            //save line
            else
                dest.Write(&m_szBuf[1], len-1);
            }
        else
            dest.Write(m_szBuf, len);
    }

    // Close data source
    dest.Close();

    return OnError(error);
}

/********************************
OpenMsg(int index)
    To allow us read part of the message without having to download it all
    we will issue a RETR command and receive only the response from the server
    If the server response is positive then we will flag the MessageOpen.
    By doing so the message will be available to us on the receive buffer where we can 
    either read the whole message or receive it by line by line
NOTE 
    This function must be called prior to a call to ReadMsgLine(). 
    A message can't be opened if another message is already open. The other message should be closed first 
PARAM
    index   - The index of the message to be opened ( 1 based ) 
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_RETR_FAILED     - RETR command has timed out without a response from the server
*********************************/
int CUT_POP3Client::OpenMsg(int index){

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the RETR command
    _snprintf(m_szBuf,sizeof(m_szBuf)-1,"RETR %d\r\n",index);
    Send(m_szBuf);

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_RETR_FAILED);

    m_bMsgOpen = TRUE;
    m_bReadMsgFinished = FALSE;

    return OnError(UTE_SUCCESS);
}

/********************************
ReadMsgLine
    Read a single line of the Already open message
    A call to OpenMsg() should be made prior to calling this function
PARAM
    buf     - A string buffer to hold the received line
    bufLen  - Maximum length of the buffer
RETURN
    Number of bytes read
    -1 No message open 
*********************************/
#if defined _UNICODE
int CUT_POP3Client::ReadMsgLine(LPWSTR buf,int bufLen){
	char * bufA = (char*) alloca(bufLen+1);
	*bufA = '\0';
	int result = ReadMsgLine(bufA, bufLen);
	if (result != -1) {
		CUT_Str::cvtcpy(buf, bufLen, bufA);
	}
	return result;}
#endif
int CUT_POP3Client::ReadMsgLine(LPSTR buf,int bufLen){

    if(m_bMsgOpen == FALSE) 
        return -1;

    int     rt = ReceiveLine(buf,bufLen);

    if(buf[0] == '.' && rt <= 3) {
        m_bReadMsgFinished = TRUE;
        return 0;
        }

    return rt;
}

/********************************
CloseMsg()
    Close the currently open message by reading all
    availabe lines of the messages if any.
PARAM
    NONE
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
*********************************/
int CUT_POP3Client::CloseMsg(){

    int     error = UTE_SUCCESS;

    if(m_bMsgOpen == FALSE)
        return OnError(UTE_SUCCESS);

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);
        
    int len;

    while(!m_bReadMsgFinished) {

        if(IsAborted()) {       // Test for abortion flag
            error = UTE_ABORTED;
            break;
            }

        //read in a line
        len = ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut);
        
        if( len <= 0 ) 
            break;

        if(m_szBuf[0] == '.' && len <= 3)
            break;
        }

    m_bMsgOpen          = FALSE;
    m_bReadMsgFinished  = FALSE;

    return OnError(error);
}

/********************************
OpenTop(int index)
    To allow us to read the top part of the message without having to download it all.
    We will issue a TOP command and receive only the response from the server
    If the server response is positive then we will flag the TopOpen.
    By doing so the message will be available to us on the receive buffer where we can 
    either read the whole message Top or receive it by line by line.
NOTE 
    This function must be called prior to a call to ReadTopLine(). 
    A message for TOP can't be opened if another message is already open for TOP.
    The other message should be closed first 
PARAM
    index - The index of the message to be opened ( 1 based ) 
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_TOP_FAILED      - TOP command has timed out without a response from the server
*********************************/
int CUT_POP3Client::OpenTop(int index,int msgLines){

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the TOP command
    _snprintf(m_szBuf,sizeof(m_szBuf)-1,"TOP %d %d\r\n",index,msgLines);
    Send(m_szBuf);

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')  // '-' response probably flags 'not implemented'.
        return OnError(UTE_TOP_FAILED);        // TOP was/is an optional POP3 option 

    m_bTopOpen = TRUE;
    m_bReadTopFinished = FALSE;

    return OnError(UTE_SUCCESS);
}

/********************************
RetrieveUID
    Retrieves the unique-id of one or all messages. You can use
    the GetUID(...) method to get the unique-id string.

    "The unique-id of a message is an arbitrary server-determined
    string, consisting of one to 70 characters in the range 0x21
    to 0x7E, which uniquely identifies a message within a
    maildrop and which persists across sessions.  This
    persistence is required even if a session ends without
    entering the UPDATE state.  The server should never reuse an
    unique-id in a given maildrop, for as long as the entity
    using the unique-id exists.

    Note that messages marked as deleted are not listed." RFC 1939

PARAM
    [msgNumber] - the number of message to get UID for.
                  If set to -1 (default) retieve UIDs for all messages
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_UIDL_FAILED     - UIDL command has timed out without a response from the server
*********************************/
int CUT_POP3Client::RetrieveUID(int msgNumber)
{
    int error = UTE_SUCCESS;

    // clear the current vector
    m_vecUID.erase(m_vecUID.begin(), m_vecUID.end());

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the UIDL command
    if(msgNumber >= 1)
        _snprintf(m_szBuf,sizeof(m_szBuf)-1,"UIDL %d\r\n", msgNumber);
    else 
        _snprintf(m_szBuf,sizeof(m_szBuf)-1,"UIDL\r\n");
    Send(m_szBuf);

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')  // '-' response probably flags 'not implemented'.
        return OnError(UTE_UIDL_FAILED);        // UIDL was/is an optional POP3 option 

    // If we are getting only one UID - get it from the response
    char        szBuffer[MAX_UID_STRING_LENGTH + 1];
    MessageUID  messageID;
    if(msgNumber >= 1) {
        if(CUT_StrMethods::ParseString(m_szBuf," \r\n", 2, szBuffer, MAX_UID_STRING_LENGTH) != UTE_SUCCESS)
            return OnError(UTE_INVALID_RESPONSE);

        // Initialize UID structure
        messageID.m_nMessageNumber = msgNumber;
        messageID.m_strUID = szBuffer;

        // Add UID structure to the vector
        m_vecUID.push_back(messageID);
        }

    // We should get the multiline response with UIDs
    else {
        int len;
        while(!m_bReadTopFinished) {
            if(IsAborted()) {       // Test for abortion flag
                error = UTE_ABORTED;
                break;
                }

            // read in a line
            len = ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut);
            if( len  <= 0 ) {
                error = UTE_SOCK_TIMEOUT;
                break;
                }

            // end of multiline response
            if(m_szBuf[0] == '.' && len <= 3)
                break;

            // Get message number
            if(CUT_StrMethods::ParseString(m_szBuf," \r\n", 0, &messageID.m_nMessageNumber) != UTE_SUCCESS) {
                error = UTE_INVALID_RESPONSE;
                break;
                }

            // Get message UID
            if(CUT_StrMethods::ParseString(m_szBuf," \r\n", 1, szBuffer, MAX_UID_STRING_LENGTH) != UTE_SUCCESS) {
                error = UTE_INVALID_RESPONSE;
                break;
                }

            // Initialize UID structure
            messageID.m_strUID = szBuffer;

            // Add UID structure to the vector
            m_vecUID.push_back(messageID);
            }
        }

    return OnError(error);
}

/********************************
GetUID
    Returns the message unique-id. You MUST retrieve these
    UID first using RetrieveUID(...) method
PARAM
    msgNumber - the number of message to get UID string for.
RETURN
    NULL    - no UID string was retrieved for this message
    string  - UID string of the message
*********************************/
LPCSTR CUT_POP3Client::GetUID(int msgNumber) 
{
    MESSAGE_UID_VEC::iterator theIterator;
    for (theIterator = m_vecUID.begin(); theIterator != m_vecUID.end(); theIterator++) {
        if(msgNumber == theIterator->m_nMessageNumber)
            return theIterator->m_strUID.c_str();
        }
    return NULL;
}

/*************************************************
GetUID()
Get the UID of the message specified by message number - 
	- call RetrieveUID before callin this function.
PARAM
uid		- [out] pointer to buffer to receive uid
maxSize - length of buffer
msgNumber   - index of the message
size    - [out] length of title

  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- uid and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - uid not found
  UTE_BUFFER_TOO_SHORT  - space in uid buffer indicated by maxSize insufficient, realloc 
  based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload
**************************************************/
int CUT_POP3Client::GetUID(LPSTR uid, size_t maxSize, int msgNumber, size_t *size) {

	int retval = UTE_SUCCESS;
	
	if(uid == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetUID(msgNumber);
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				strcpy(uid, str);
			}
		}
	}
	return retval;

}
#if defined _UNICODE
int CUT_POP3Client::GetUID(LPWSTR uid, size_t maxSize, int msgNumber, size_t *size) {

	int retval;
	
	if(maxSize > 0) {
		char * uidA = new char [maxSize];
		
		if(uidA != NULL) {
			retval = GetUID( uidA, maxSize, msgNumber, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(uid, maxSize, uidA);
			}
			
			delete [] uidA;
			
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetUID(msgNumber);
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;

}
#endif

/********************************
ReadTopLine()
    Read a single line of the already open message Top.
    A call to OpenTop() should be made prior to calling this function
PARAM
    buf     - A string buffer to hold the received line
    bufLen  - Maximum length of the buffer
RETURN
    Number of bytes read
    -1 No message Top open 
*********************************/
#if defined _UNICODE
int CUT_POP3Client::ReadTopLine(LPWSTR buf,int bufLen){
	char * bufA = (char*) alloca(bufLen+1);
	*bufA = '\0';
	int result = ReadTopLine(bufA, bufLen);
	if (result != -1) {
		CUT_Str::cvtcpy(buf, bufLen, bufA);
	}
	return result;}
#endif
int CUT_POP3Client::ReadTopLine(LPSTR buf,int bufLen){

    if (m_bTopOpen == FALSE) 
        return -1;

    int rt = ReceiveLine(buf,bufLen);
    if(buf[0] == '.' && rt <= 3) {
        m_bReadTopFinished = TRUE;
        return 0;
        }

    return rt;
}

/********************************
CloseTop()
    Close the currently open message by reading all
    availabe lines of the Top response if any.
PARAM
    NONE
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
*********************************/
int CUT_POP3Client::CloseTop(){
    int     error = UTE_SUCCESS;

    if(m_bTopOpen == FALSE)
        return OnError(UTE_SUCCESS);

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);
    
    int len;

    while(!m_bReadTopFinished) {
        if(IsAborted()) {       // Test for abortion flag
            error = UTE_ABORTED;
            break;
            }

        //read in a line
        len = ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut);
        
        if( len  <= 0 )
            break;
        
        if(m_szBuf[0] == '.' && len <= 3)
            break;
        }

    m_bTopOpen = FALSE;
    m_bReadTopFinished = FALSE;

    return OnError(error);
}

/********************************
DeleteMsg()
  Mark a message for deletion.
  the message will be deleted after the transaction closure
PARAM
    index   - index of the message to be marked for deletion
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_DELE_FAILED     - DELE command has timed out without a response from the server
*********************************/
int CUT_POP3Client::DeleteMsg(int index){

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);
    
    //send the DELE command
    _snprintf(m_szBuf,sizeof(m_szBuf)-1,"DELE %d\r\n",index);
    Send(m_szBuf);

    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_DELE_FAILED);

    return OnError(UTE_SUCCESS);
}

/********************************
ResetDelete()
     If any messages have been marked as deleted 
    by the pop3 server they are unmarked.
PARAM
    NONE
RETURN
    UTE_SUCCESS         - Success
    UTE_NOCONNECTION    - NOT connected
    UTE_SVR_NO_RESPONSE - no response from Server
    UTE_RSET_FAILED     - RSET command has timed out without a response from the server
*********************************/
int CUT_POP3Client::ResetDelete(){

    //check to see if the connection is made
    if(!IsConnected())
        return OnError(UTE_NOCONNECTION);

    //send the DELE command
    Send("RSET\r\n");
    
    //get the response
    if(ReceiveLine(m_szBuf,sizeof(m_szBuf),m_nPOP3TimeOut) <= 0)
        return OnError(UTE_SVR_NO_RESPONSE);

    if(m_szBuf[0] != '+')
        return OnError(UTE_RSET_FAILED);

    return OnError(UTE_SUCCESS);
}

/********************************
    Virtual function designed to be overridden to  
    receive report of progress of save message process.

    To abort the Save Message process return false

PARAM
    bytesRetrieved - Number of bytes received so far
RETURN
    TRUE    - to continue
    FALSE   - to cancel
*********************************/
BOOL CUT_POP3Client::OnSaveMsg(long /*  bytesRetrieved */ ){
    return !IsAborted();
}

/********************************
*********************************/
BOOL CUT_POP3Client::GetResponseCode(int timeOut){

    if(ReceiveLine(m_szBuf,sizeof(m_szBuf), timeOut) <=0)
        return FALSE;

    if(m_szBuf[0] == '+')
        return TRUE;
    
    return FALSE;
}
/*********************************************
SetPort
    Sets the port number to connect to
Params
    newPort     - connect port
Return
    UTE_SUCCESS - success
**********************************************/
int CUT_POP3Client::SetPort(unsigned int newPort) {
    m_nPort = newPort;
    return OnError(UTE_SUCCESS);
}
/*********************************************
GetPort
    Sets the port number to connect to
Params
    none
Return
    connect port
**********************************************/
unsigned int  CUT_POP3Client::GetPort() const
{
    return m_nPort;
}
/*********************************************
SetConnectTimeout
    Sets the time to wait for a connection 
    in seconds
    5 seconds is the default time
Params
    secs - seconds to wait
Return
    UTE_SUCCESS - success
    UTE_ERROR   - invalid input value
**********************************************/
int CUT_POP3Client::SetConnectTimeout(int secs){
    
    if(secs <= 0)
        return OnError(UTE_ERROR);

    m_nConnectTimeout = secs;

    return OnError(UTE_SUCCESS);
}
/*********************************************
GetConnectTimeout
    Gets the time to wait for a connection 
    in seconds
Params
    none
Return
    current time out value in seconds
**********************************************/
int CUT_POP3Client::GetConnectTimeout() const
{
    return m_nConnectTimeout;
}
/********************************
SetPOP3TimeOut
    Sets POP3 time out value
PARAM:
    timeout 
RETURN:
    UTE_SUCCESS - success
    UTE_ERROR   - invalid input value
*********************************/
int CUT_POP3Client::SetPOP3TimeOut(int timeout) {
    if(timeout <= 0)
        return OnError(UTE_ERROR);

    m_nPOP3TimeOut = timeout;

    return OnError(UTE_SUCCESS);
}
/********************************
GetPOP3TimeOut
    Gets POP3 time out value
PARAM:
    none
RETURN:
    timeout 
*********************************/
int CUT_POP3Client::GetPOP3TimeOut() const
{
    return m_nPOP3TimeOut;
}



/**************************************************************
SocketOnConnected(SOCKET s, const char *lpszName)
	
		If the security is enabled then perform te SSL neogotiation
		otherwise just return a success and let the plain text FTP handles
		the comunication

		To let the server know that we are looking for SSL or TLS we need to
		send the following command
		FEAT  
		The Feature negotiation mechanism for the File Transfer Protocol 
		
		To ask the server for SSL or TLS negotiation 
		we will send the AUTH command.

		A parameter for the AUTH command to indicate that TLS is
		required.  It is recommended that 'TLS', 'TLS-C', 'SSL' and 'TLS-P'
		are acceptable, and mean the following :-

		 'TLS' or 'TLS-C' - the TLS protocol or the SSL protocol will be
			negotiated on the control connection.  The default protection
			setting for the Data connection is 'Clear'.

			'SSL' or 'TLS-P' - the TLS protocol or the SSL protocol will be
			negotiated on the control connection.  The default protection
			setting for the Data connection is 'Private'.  This is primarily
			for backward compatibility.

	Notice that we will first send a TLS P to select The highest implementation.
	the server might response with the response
	503 unknown security mechanism 

	if this happened we will issue an Auth SSL command.

Param:
	SOCKET s		- The newly created socket 
	lpszName		- apointer to the host name we are attempting to connect to


Return:
	UTE_NO_RESPONSE - Server did not response to our command
	UTE_CONNECT_FAIL_NO_SSL_SUPPORT - Server does not support SSL.
	UTE_CONNECT_FAILED	-	 The connection have failed
	security  errors   - This function may fail with other error
			UTE_LOAD_SECURITY_LIBRARIES_FAILED
			UTE_OUT_OF_MEMORY
			UTE_FAILED_TO_GET_SECURITY_STREAM_SIZE
			UTE_OUT_OF_MEMORY
			UTE_FAILED_TO_QUERY_CERTIFICATE
			UTE_NULL_PARAM
			UTE_PARAMETER_INVALID_VALUE
			UTE_FAILED_TO_GET_CERTIFICATE_CHAIN
			UTE_FAILED_TO_VERIFY_CERTIFICATE_CHAIN
			UTE_FAILED_TO_VERIFY_CERTIFICATE_TRUST
	UTE_POP3_TLS_NOT_SUPPORTED - server does not support the STLS command	
**************************************************************/
int CUT_POP3Client::SocketOnConnected(SOCKET s, const char *lpszName){

	int		rt = UTE_SUCCESS;	

#ifdef CUT_SECURE_SOCKET
	
	BOOL bSecFlag = GetSecurityEnabled();
	
	if(bSecFlag)
	{
		// v4.2 - update 02 - connect using SSL for pop3s on port 995
		//        no one likes the inelegance if this, but haven't 
		//        seen an instance of STLS and SSL together for pop3
		if (995 == GetPort ()) // Make it work for Gmail.
        {
               return CUT_SecureSocketClient::SocketOnConnected(s, lpszName);
        }
		else {
			// disable the secure comunication so we can send the plain data 
			SetSecurityEnabled(FALSE);
			
			// get server response
			if( !GetResponseCode(m_nPOP3TimeOut))
				rt = UTE_CONNECT_FAILED;
			else{
				
				
				Send("STLS\r\n");
				
				// get response
				if( GetResponseCode(m_nPOP3TimeOut))
				{
					// reset back the security so we can proceed with negotiation
					SetSecurityEnabled(bSecFlag);
					rt =  CUT_SecureSocketClient::SocketOnConnected(s, lpszName);
				}
				else
					rt = UTE_POP3_TLS_NOT_SUPPORTED;
			}
				
			return rt;
		}
	}
	else {
		
		return UTE_SUCCESS;
	}

#else 
// v4.2 non-secure builds result in unref'd param warns VC6
	UNREFERENCED_PARAMETER(s);
	UNREFERENCED_PARAMETER(lpszName);

// v4.2 unreachable code in secure build
	return OnError(rt);
// v4.22 check this - was retuning 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