Collect emails from the POP3 Account (Conduct a POP3 session with the designated server). The emails are each placed in thier own file.
| Return Type | Function name | Arguments |
|---|---|---|
| hzEcode | hzPop3Acc::Collect | (hzVect<hzString>&,) |
Declared in file: hzMailer.h
Defined in file : hzPop3.cpp
Function Logic:
Function body:
hzEcode hzPop3Acc::Collect (hzVect<hzString>& messages)
{
// Collect emails from the POP3 Account (Conduct a POP3 session with the designated server). The emails are each placed in thier own file.
//
// Arguments: 1) messages A vector of strings that is populated with filename of collected emails.
//
// Returns: E_NOINIT The POP3 account is not initialized
// E_PROTOCOL The session message not as expected
// E_OK The email collection was successful
_hzfunc("hzPop3Acc::Collect") ;
hzMapS<int32_t,hzString> temp ; // Emails available from the POP3 server
ofstream os ; // Output stream
hzTcpClient P ; // POP3 client connection
chIter zi ; // For iterating server responses
hzChain Z ; // For sending commands and receiving responses
hzChain word ; // For capturing small strings (eg mail number and mail id)
hzChain msg ; // For garnering messages
hzString S ; // For conversion of 'word' into a string
hzString path ; // For email filenames
uint32_t mailId ; // Mail number as given by server
uint32_t nIndex ; // For iterating avail emails
hzEcode rc ; // Return code
m_Error.Clear() ;
if (!m_Repos)
{
threadLog("POP3 Account not initialized\n") ;
return E_NOINIT ;
}
rc = P.ConnectStd(m_Server, 110);
if (rc != E_OK)
{
threadLog("Cannot connect to email server %s (error=%s)\n", *m_Server, Err2Txt(rc)) ;
return rc ;
}
rc = P.SetSendTimeout(30);
if (rc != E_OK)
{
threadLog("Could not set send_timeout on connection to POP3 server (error=%s)\n", Err2Txt(rc)) ;
return rc ;
}
rc = P.SetRecvTimeout(30);
if (rc != E_OK)
{
threadLog("Could not set recv_timeout on connection to POP3 server (error=%s)\n", Err2Txt(rc)) ;
return rc ;
}
// Expect the server to talk first with a +OK
Z.Clear() ;
rc = P.Recv(Z) ;
if (rc != E_OK)
{
threadLog("Cannot recv server hello (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
S = Z ;
threadLog("Server: [%s]\n", *S) ;
zi = Z ;
if (zi != "+OK")
{
rc = E_PROTOCOL ;
threadLog("Expected +OK as hello from server. (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
// Send the initial username
Z.Clear() ;
Z.Printf("USER %s\r\n", *m_Username) ;
S = Z ;
threadLog("Client: [%s]\n", *S) ;
rc = P.Send(Z) ;
if (rc != E_OK)
{
threadLog("Cannot send username to email server (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
// Recv the +OK\r\n (to the username)
Z.Clear() ;
rc = P.Recv(Z) ;
if (rc != E_OK)
{
threadLog("Cannot recv response to username from email server (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
S = Z ;
threadLog("Server: [%s]\n", *S) ;
zi = Z ;
if (zi != "+OK")
{
rc = E_PROTOCOL ;
S = Z ;
threadLog("Expected +OK response to username (got=%s)\n", *S) ;
goto done ;
}
// Send the password
Z.Clear() ;
Z.Printf("PASS %s\r\n", *m_Password) ;
S = Z ;
threadLog("Client: [%s]\n", *S) ;
rc = P.Send(Z) ;
if (rc != E_OK)
{
threadLog("Cannot send password to email server (error=%s)\n", Err2Txt(rc)) ;
rc = E_PROTOCOL ;
goto done ;
}
// Recv the +OK\r\n (to the password)
Z.Clear() ;
rc = P.Recv(Z) ;
if (rc != E_OK)
{
threadLog("Cannot recv response to username from email server (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
S = Z ;
threadLog("Server: [%s]\n", *S) ;
zi = Z ;
if (zi != "+OK")
{
S = Z ;
threadLog("Expected +OK to password. (got=%s)\n", *S) ;
rc = E_PROTOCOL ;
goto done ;
}
// Send the UIDL command
Z.Clear() ;
Z.Printf("UIDL\r\n") ;
S = Z ;
threadLog("Client: [%s]\n", *S) ;
rc = P.Send(Z) ;
if (rc != E_OK)
{
threadLog("Cannot send UIDL command to email server (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
// Recv the +OK\r\n (to the UIDL command)
Z.Clear() ;
for (;;) // nIndex = 0 ; nIndex < 3 ; nIndex++)
{
rc = P.Recv(Z) ;
if (rc != E_OK)
{
threadLog("Cannot recv response to UIDL from email server (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
threadLog("Server - Response to UIDL of %d bytes\n", Z.Size()) ;
// Test for the \r\n.\r\n
zi = Z ;
zi += (Z.Size() - 5);
if (zi == "\r\n.\r\n")
break ;
}
S = Z ;
threadLog("Server: [%s]\n", *S) ;
zi = Z ;
if (zi != "+OK")
{
rc = E_PROTOCOL ;
threadLog("Expected +OK response to UIDL (error=%s)\n", Err2Txt(rc)) ;
goto done ;
}
// Recieve the list of available messages and place them in the temporary map
for (; !zi.eof() && *zi != CHAR_NL ; zi++) ;
zi++ ;
for (; !zi.eof() ; zi++)
{
for (; !zi.eof() && IsDigit(*zi) ; zi++)
word.AddByte(*zi) ;
if (!word.Size())
break ;
// zi.Skipwhite() ;
S = word ;
mailId = atoi(*S) ;
word.Clear() ;
for (zi++ ; !zi.eof() ; zi++)
{
if (*zi == CHAR_CR)
zi++ ;
if (*zi == CHAR_NL)
break ;
word.AddByte(*zi) ;
}
S = word ;
word.Clear() ;
if (!m_Already.Exists(S))
temp.Insert(mailId, S) ;
if (zi.eof())
break ;
}
for (nIndex = 0; nIndex < temp.Count() ; nIndex++)
{
mailId = temp.GetKey(nIndex) ;
S = temp.GetObj(nIndex) ;
threadLog("Mailbox has %d %d (%s)\n", nIndex, mailId, *S) ;
}
// Recv the email list. Some of these we may already have
for (nIndex = 0; rc == E_OK && nIndex < temp.Count() ; nIndex++)
{
mailId = temp.GetKey(nIndex) ;
S = temp.GetObj(nIndex) ;
// Send the RETR command
Z.Clear() ;
Z.Printf("RETR %d\r\n", mailId) ;
rc = P.Send(Z) ;
if (rc != E_OK)
{ threadLog("Cannot send RETR command to email server\n") ; break ; }
// Recv the +OK (to the RETR command). This involves repeated calls to Recv until the chain ends with a \r\n.\r\n sequence.
Z.Clear() ;
for (;;)
{
rc = P.Recv(Z) ;
if (rc != E_OK)
{ threadLog("Cannot recv response to RETR command\n") ; break ; }
threadLog("Server - Message of %d bytes\n", Z.Size()) ;
// Test for the \r\n.\r\n
zi = Z ;
zi += (Z.Size() - 5);
if (zi == "\r\n.\r\n")
break ;
}
// Go to end of line, then message body, the the CR/NL period CR/NL sequence
msg.Clear() ;
zi = Z ;
if (zi != "+OK")
{
rc = E_OK ;
S = Z ;
threadLog("Expected +OK in response to RETR command (got=%s)\n", *S) ;
continue ;
}
for (zi += 3; !zi.eof() && *zi != CHAR_NL ; zi++) ;
if (*zi != CHAR_NL)
{
threadLog("Malformed +OK response to RETR command\n") ;
continue ;
}
for (zi++ ; !zi.eof() ; zi++)
{
if (*zi == CHAR_CR)
{
if (zi == "\r\n.\r\n")
{
zi += 5;
if (zi.eof())
break ;
zi -= 5;
}
}
msg.AddByte(*zi) ;
}
path = m_Repos + "/" + S ;
os.open(*path) ;
if (os.fail())
threadLog("Cannot open file %s for writting\n", *path) ;
else
{
threadLog("Writing message file %s\n", *path) ;
os << msg ;
os.close() ;
os.clear() ;
messages.Add(S) ;
}
}
os.close() ;
done:
P.Close() ;
return rc ;
}