* Fixed dumb uses of select() with a hardcoded number of file descriptors.

* Decreased the timeout from 60 to 30 seconds; somehow it seems it waits more
  than just once this time in case something fails over here.
* Cleaned up the messy SSL patch.
* Made the whole thing a bit more compliant to our coding style.
* Got rid of the useless pop3_error() macro.
* Fixed error reporting in ReceiveLine().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21765 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-07-31 16:00:26 +00:00
parent 2ae1709efb
commit b1c07d8165
2 changed files with 264 additions and 235 deletions
@@ -1,7 +1,11 @@
/* POP3Protocol - implementation of the POP3 protocol /*
** * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
** Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2007, Haiku Inc. All Rights Reserved.
*/ *
* Distributed under the terms of the MIT License.
*/
//! POP3Protocol - implementation of the POP3 protocol
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -35,19 +39,18 @@
#include "pop3.h" #include "pop3.h"
#define POP3_RETRIEVAL_TIMEOUT 60000000 #define POP3_RETRIEVAL_TIMEOUT 30000000
#define CRLF "\r\n" #define CRLF "\r\n"
#define pop3_error(string) runner->ShowError(string)
POP3Protocol::POP3Protocol(BMessage *settings, BMailChainRunner *status) POP3Protocol::POP3Protocol(BMessage *settings, BMailChainRunner *status)
: SimpleMailProtocol(settings,status), : SimpleMailProtocol(settings,status),
fNumMessages(-1), fNumMessages(-1),
fMailDropSize(0) fMailDropSize(0)
{ {
#ifdef USESSL #ifdef USESSL
use_ssl = (settings->FindInt32("flavor") == 1); fUseSSL = (settings->FindInt32("flavor") == 1);
#endif #endif
Init(); Init();
} }
@@ -55,25 +58,23 @@ POP3Protocol::POP3Protocol(BMessage *settings, BMailChainRunner *status)
POP3Protocol::~POP3Protocol() POP3Protocol::~POP3Protocol()
{ {
#ifdef USESSL #ifdef USESSL
if( (use_ssl && ssl) || !use_ssl) if (!fUseSSL || fSSL)
SendCommand("QUIT" CRLF);
#else
SendCommand("QUIT" CRLF);
#endif #endif
SendCommand("QUIT" CRLF);
#ifdef USESSL #ifdef USESSL
if(use_ssl) { if (fUseSSL) {
if(ssl) if (fSSL)
SSL_shutdown(ssl); SSL_shutdown(fSSL);
if(ctx) if (fSSLContext)
SSL_CTX_free(ctx); SSL_CTX_free(fSSLContext);
} }
#endif #endif
#ifndef HAIKU_TARGET_PLATFORM_BEOS #ifndef HAIKU_TARGET_PLATFORM_BEOS
close(conn); close(fSocket);
#else #else
closesocket(conn); closesocket(fSocket);
#endif #endif
} }
@@ -81,14 +82,16 @@ POP3Protocol::~POP3Protocol()
status_t status_t
POP3Protocol::Open(const char *server, int port, int) POP3Protocol::Open(const char *server, int port, int)
{ {
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Connecting to POP3 Server...","POP3サーバに接続しています...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE("Connecting to POP3 Server...",
"POP3サーバに接続しています..."));
if (port <= 0) if (port <= 0) {
#ifdef USESSL #ifdef USESSL
port = use_ssl ? 995 : 110; port = fUseSSL ? 995 : 110;
#else #else
port = 110; port = 110;
#endif #endif
}
fLog = ""; fLog = "";
@@ -106,74 +109,73 @@ POP3Protocol::Open(const char *server, int port, int)
if (hostIP == 0) { if (hostIP == 0) {
error_msg << MDR_DIALECT_CHOICE (": Connection refused or host not found",": :接続が拒否されたかサーバーが見つかりません"); error_msg << MDR_DIALECT_CHOICE (": Connection refused or host not found",": :接続が拒否されたかサーバーが見つかりません");
pop3_error(error_msg.String()); runner->ShowError(error_msg.String());
return B_NAME_NOT_FOUND; return B_NAME_NOT_FOUND;
} }
#ifndef HAIKU_TARGET_PLATFORM_BEOS #ifndef HAIKU_TARGET_PLATFORM_BEOS
conn = socket(AF_INET, SOCK_STREAM, 0); fSocket = socket(AF_INET, SOCK_STREAM, 0);
#else #else
conn = socket(AF_INET, 2, 0); fSocket = socket(AF_INET, 2, 0);
#endif #endif
if (conn >= 0) { if (fSocket >= 0) {
struct sockaddr_in saAddr; struct sockaddr_in saAddr;
memset(&saAddr, 0, sizeof(saAddr)); memset(&saAddr, 0, sizeof(saAddr));
saAddr.sin_family = AF_INET; saAddr.sin_family = AF_INET;
saAddr.sin_port = htons(port); saAddr.sin_port = htons(port);
saAddr.sin_addr.s_addr = hostIP; saAddr.sin_addr.s_addr = hostIP;
int result = connect(conn, (struct sockaddr *) &saAddr, sizeof(saAddr)); int result = connect(fSocket, (struct sockaddr *) &saAddr, sizeof(saAddr));
if (result < 0) { if (result < 0) {
#ifndef HAIKU_TARGET_PLATFORM_BEOS #ifndef HAIKU_TARGET_PLATFORM_BEOS
close(conn); close(fSocket);
#else #else
closesocket(conn); closesocket(fSocket);
#endif #endif
conn = -1; fSocket = -1;
error_msg << ": " << strerror(errno); error_msg << ": " << strerror(errno);
pop3_error(error_msg.String()); runner->ShowError(error_msg.String());
return errno; return errno;
} }
} else { } else {
error_msg << ": Could not allocate socket."; error_msg << ": Could not allocate socket.";
pop3_error(error_msg.String()); runner->ShowError(error_msg.String());
return B_ERROR; return B_ERROR;
} }
#ifdef USESSL #ifdef USESSL
if (use_ssl) { if (fUseSSL) {
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
RAND_seed(this,sizeof(POP3Protocol)); RAND_seed(this,sizeof(POP3Protocol));
/*--- Because we're an add-on loaded at an unpredictable time, all /*--- Because we're an add-on loaded at an unpredictable time, all
the memory addresses and things contained in ourself are the memory addresses and things contained in ourself are
esssentially random. */ esssentially random. */
ctx = SSL_CTX_new(SSLv23_method()); fSSLContext = SSL_CTX_new(SSLv23_method());
ssl = SSL_new(ctx); fSSL = SSL_new(fSSLContext);
sbio=BIO_new_socket(conn,BIO_NOCLOSE); fSSLBio = BIO_new_socket(fSocket, BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio); SSL_set_bio(fSSL, fSSLBio, fSSLBio);
if (SSL_connect(ssl) <= 0) { if (SSL_connect(fSSL) <= 0) {
BString error; BString error;
error << "Could not connect to POP3 server " << settings->FindString("server"); error << "Could not connect to POP3 server "
<< settings->FindString("server");
if (port != 995) if (port != 995)
error << ":" << port; error << ":" << port;
error << ". (SSL Connection Error)"; error << ". (SSL Connection Error)";
runner->ShowError(error.String()); runner->ShowError(error.String());
SSL_CTX_free(ctx); SSL_CTX_free(fSSLContext);
#ifndef HAIKU_TARGET_PLATFORM_BEOS #ifndef HAIKU_TARGET_PLATFORM_BEOS
close(conn); close(fSocket);
#else #else
closesocket(conn); closesocket(fSocket);
#endif #endif
runner->Stop(true); runner->Stop(true);
return B_ERROR; return B_ERROR;
} }
} }
#endif
#endif
BString line; BString line;
status_t err; status_t err;
@@ -186,47 +188,48 @@ POP3Protocol::Open(const char *server, int port, int)
if (err < 0) { if (err < 0) {
#ifndef HAIKU_TARGET_PLATFORM_BEOS #ifndef HAIKU_TARGET_PLATFORM_BEOS
close(conn); close(fSocket);
#else #else
closesocket(conn); closesocket(fSocket);
#endif #endif
conn = -1; fSocket = -1;
error_msg << ": " << strerror(err); error_msg << ": " << strerror(err);
pop3_error(error_msg.String()); runner->ShowError(error_msg.String());
return B_ERROR; return B_ERROR;
} }
if (strncmp(line.String(), "+OK", 3) != 0) { if (strncmp(line.String(), "+OK", 3) != 0) {
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << line.String(); error_msg << MDR_DIALECT_CHOICE(". The server said:\n",
pop3_error(error_msg.String()); "サーバのメッセージです\n") << line.String();
runner->ShowError(error_msg.String());
return B_ERROR; return B_ERROR;
} }
fLog = line; fLog = line;
return B_OK; return B_OK;
} }
status_t POP3Protocol::Login(const char *uid, const char *password, int method) status_t
POP3Protocol::Login(const char *uid, const char *password, int method)
{ {
status_t err; status_t err;
BString error_msg; BString error_msg;
error_msg << MDR_DIALECT_CHOICE ("Error while authenticating user ","ユーザー認証中にエラーが発生しました ") << uid; error_msg << MDR_DIALECT_CHOICE("Error while authenticating user ",
"ユーザー認証中にエラーが発生しました ") << uid;
if (method == 1) { //APOP if (method == 1) { //APOP
int32 index = fLog.FindFirst("<"); int32 index = fLog.FindFirst("<");
if(index != B_ERROR) { if(index != B_ERROR) {
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending APOP authentication...","APOP認証情報を送信中...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE(
"Sending APOP authentication...", "APOP認証情報を送信中..."));
int32 end = fLog.FindFirst(">",index); int32 end = fLog.FindFirst(">",index);
BString timestamp(""); BString timestamp("");
fLog.CopyInto(timestamp,index,end-index+1); fLog.CopyInto(timestamp, index, end - index + 1);
timestamp += password; timestamp += password;
char md5sum[33]; char md5sum[33];
MD5Digest((unsigned char*)timestamp.String(),md5sum); MD5Digest((unsigned char*)timestamp.String(), md5sum);
BString cmd = "APOP "; BString cmd = "APOP ";
cmd += uid; cmd += uid;
cmd += " "; cmd += " ";
@@ -235,20 +238,22 @@ status_t POP3Protocol::Login(const char *uid, const char *password, int method)
err = SendCommand(cmd.String()); err = SendCommand(cmd.String());
if (err != B_OK) { if (err != B_OK) {
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog; error_msg << MDR_DIALECT_CHOICE(". The server said:\n",
pop3_error(error_msg.String()); "サーバのメッセージです\n") << fLog;
runner->ShowError(error_msg.String());
return err; return err;
} }
return B_OK; return B_OK;
} else { } else {
error_msg << MDR_DIALECT_CHOICE (": The server does not support APOP.","サーバはAPOPをサポートしていません"); error_msg << MDR_DIALECT_CHOICE(": The server does not support APOP.",
pop3_error(error_msg.String()); "サーバはAPOPをサポートしていません");
runner->ShowError(error_msg.String());
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
} }
} }
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending username...","ユーザーID送信中...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE("Sending username...",
"ユーザーID送信中..."));
BString cmd = "USER "; BString cmd = "USER ";
cmd += uid; cmd += uid;
@@ -256,22 +261,23 @@ status_t POP3Protocol::Login(const char *uid, const char *password, int method)
err = SendCommand(cmd.String()); err = SendCommand(cmd.String());
if (err != B_OK) { if (err != B_OK) {
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog; error_msg << MDR_DIALECT_CHOICE(". The server said:\n",
pop3_error(error_msg.String()); "サーバのメッセージです\n") << fLog;
runner->ShowError(error_msg.String());
return err; return err;
} }
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending password...","パスワード送信中...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE("Sending password...",
"パスワード送信中..."));
cmd = "PASS "; cmd = "PASS ";
cmd += password; cmd += password;
cmd += CRLF; cmd += CRLF;
err = SendCommand(cmd.String()); err = SendCommand(cmd.String());
if (err != B_OK) { if (err != B_OK) {
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog; error_msg << MDR_DIALECT_CHOICE(". The server said:\n",
pop3_error(error_msg.String()); "サーバのメッセージです\n") << fLog;
runner->ShowError(error_msg.String());
return err; return err;
} }
@@ -279,15 +285,17 @@ status_t POP3Protocol::Login(const char *uid, const char *password, int method)
} }
status_t POP3Protocol::Stat() status_t
POP3Protocol::Stat()
{ {
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Getting mailbox size...","メールボックスのサイズを取得しています...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE("Getting mailbox size...",
"メールボックスのサイズを取得しています..."));
if (SendCommand("STAT" CRLF) < B_OK) if (SendCommand("STAT" CRLF) < B_OK)
return B_ERROR; return B_ERROR;
int32 messages,dropSize; int32 messages,dropSize;
if (sscanf(fLog.String(),"+OK %ld %ld",&messages,&dropSize) < 2) if (sscanf(fLog.String(), "+OK %ld %ld", &messages, &dropSize) < 2)
return B_ERROR; return B_ERROR;
fNumMessages = messages; fNumMessages = messages;
@@ -297,7 +305,8 @@ status_t POP3Protocol::Stat()
} }
int32 POP3Protocol::Messages() int32
POP3Protocol::Messages()
{ {
if (fNumMessages < 0) if (fNumMessages < 0)
Stat(); Stat();
@@ -306,7 +315,8 @@ int32 POP3Protocol::Messages()
} }
size_t POP3Protocol::MailDropSize() size_t
POP3Protocol::MailDropSize()
{ {
if (fNumMessages < 0) if (fNumMessages < 0)
Stat(); Stat();
@@ -315,7 +325,8 @@ size_t POP3Protocol::MailDropSize()
} }
status_t POP3Protocol::Retrieve(int32 message, BPositionIO *write_to) status_t
POP3Protocol::Retrieve(int32 message, BPositionIO *write_to)
{ {
status_t returnCode; status_t returnCode;
BString cmd; BString cmd;
@@ -339,7 +350,8 @@ status_t POP3Protocol::Retrieve(int32 message, BPositionIO *write_to)
} }
status_t POP3Protocol::GetHeader(int32 message, BPositionIO *write_to) status_t
POP3Protocol::GetHeader(int32 message, BPositionIO *write_to)
{ {
BString cmd; BString cmd;
cmd << "TOP " << message + 1 << " 0" << CRLF; cmd << "TOP " << message + 1 << " 0" << CRLF;
@@ -347,7 +359,8 @@ status_t POP3Protocol::GetHeader(int32 message, BPositionIO *write_to)
} }
status_t POP3Protocol::RetrieveInternal(const char *command, int32 message, status_t
POP3Protocol::RetrieveInternal(const char *command, int32 message,
BPositionIO *write_to, bool post_progress) BPositionIO *write_to, bool post_progress)
{ {
const int bufSize = 1024 * 30; const int bufSize = 1024 * 30;
@@ -375,26 +388,22 @@ status_t POP3Protocol::RetrieveInternal(const char *command, int32 message,
return B_ERROR; return B_ERROR;
struct timeval tv; struct timeval tv;
struct fd_set fds; tv.tv_sec = POP3_RETRIEVAL_TIMEOUT / 1000000;
tv.tv_usec = POP3_RETRIEVAL_TIMEOUT % 1000000;
struct fd_set readSet;
FD_ZERO(&readSet);
FD_SET(fSocket, &readSet);
tv.tv_sec = long(POP3_RETRIEVAL_TIMEOUT / 1e6);
tv.tv_usec = long(POP3_RETRIEVAL_TIMEOUT-(tv.tv_sec * 1e6));
/* Initialize (clear) the socket mask. */
FD_ZERO(&fds);
/* Set the socket in the mask. */
FD_SET(conn, &fds);
while (cont) { while (cont) {
int result = 0; int result = 0;
#ifdef USESSL #ifdef USESSL
if ((use_ssl) && (SSL_pending(ssl))) if (fUseSSL && SSL_pending(fSSL))
result = 1; result = 1;
else else
#endif #endif
result = select(32, &fds, NULL, NULL, &tv); result = select(fSocket + 1, &readSet, NULL, NULL, &tv);
if (result == 0) { if (result == 0) {
// No data available, even after waiting a minute. // No data available, even after waiting a minute.
fLog = "POP3 timeout - no data received after a long wait."; fLog = "POP3 timeout - no data received after a long wait.";
@@ -403,21 +412,22 @@ status_t POP3Protocol::RetrieveInternal(const char *command, int32 message,
} }
if (amountToReceive > bufSize - 1 - amountInBuffer) if (amountToReceive > bufSize - 1 - amountInBuffer)
amountToReceive = bufSize - 1 - amountInBuffer; amountToReceive = bufSize - 1 - amountInBuffer;
#ifdef USESSL #ifdef USESSL
if (use_ssl) if (fUseSSL) {
amountReceived = SSL_read(ssl,buf + amountInBuffer, amountToReceive); amountReceived = SSL_read(fSSL, buf + amountInBuffer,
else amountToReceive);
#endif } else
amountReceived = recv(conn,buf + amountInBuffer, amountToReceive,0); #endif
amountReceived = recv(fSocket, buf + amountInBuffer, amountToReceive, 0);
if (amountReceived < 0) { if (amountReceived < 0) {
fLog = strerror(errno); fLog = strerror(errno);
return errno; return errno;
} }
if (amountReceived == 0) { if (amountReceived == 0) {
fLog = "POP3 data supposedly ready to receive but not received!"; fLog = "POP3 data supposedly ready to receive but not received!";
return B_ERROR; // Shouldn't happen, but... return B_ERROR;
} }
amountToReceive = bufSize - 1; // For next time, read a full buffer. amountToReceive = bufSize - 1; // For next time, read a full buffer.
amountInBuffer += amountReceived; amountInBuffer += amountReceived;
buf[amountInBuffer] = 0; // NUL stops tests past the end of buffer. buf[amountInBuffer] = 0; // NUL stops tests past the end of buffer.
@@ -490,12 +500,16 @@ status_t POP3Protocol::RetrieveInternal(const char *command, int32 message,
} }
status_t POP3Protocol::UniqueIDs() { status_t
POP3Protocol::UniqueIDs()
{
status_t ret = B_OK; status_t ret = B_OK;
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Getting UniqueIDs...","固有のIDを取得中...")); runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE("Getting UniqueIDs...",
"固有のIDを取得中..."));
ret = SendCommand("UIDL" CRLF); ret = SendCommand("UIDL" CRLF);
if (ret != B_OK) return ret; if (ret != B_OK)
return ret;
BString result; BString result;
int32 uid_offset; int32 uid_offset;
@@ -508,7 +522,7 @@ status_t POP3Protocol::UniqueIDs() {
unique_ids->AddItem(result.String()); unique_ids->AddItem(result.String());
} }
if (SendCommand("LIST"CRLF) != B_OK) if (SendCommand("LIST" CRLF) != B_OK)
return B_ERROR; return B_ERROR;
int32 b; int32 b;
@@ -521,73 +535,73 @@ status_t POP3Protocol::UniqueIDs() {
b = atol(&(result.String()[b])); b = atol(&(result.String()[b]));
else else
b = 0; b = 0;
sizes.AddItem((void *)(b)); fSizes.AddItem((void *)(b));
} }
return ret; return ret;
} }
void POP3Protocol::Delete(int32 num) { void
POP3Protocol::Delete(int32 num)
{
BString cmd = "DELE "; BString cmd = "DELE ";
cmd << (num+1) << CRLF; cmd << (num+1) << CRLF;
if (SendCommand(cmd.String()) != B_OK) { if (SendCommand(cmd.String()) != B_OK) {
// Error // Error
} }
#if DEBUG #if DEBUG
puts(fLog.String()); puts(fLog.String());
#endif #endif
} }
size_t POP3Protocol::MessageSize(int32 index) { size_t
return (size_t)(sizes.ItemAt(index)); POP3Protocol::MessageSize(int32 index)
{
return (size_t)fSizes.ItemAt(index);
} }
int32 int32
POP3Protocol::ReceiveLine(BString &line) POP3Protocol::ReceiveLine(BString &line)
{ {
int32 len = 0, rcv; int32 len = 0;
int8 c = 0;
bool flag = false; bool flag = false;
line = ""; line = "";
struct timeval tv;
struct fd_set fds;
tv.tv_sec = long(POP3_RETRIEVAL_TIMEOUT / 1e6); struct timeval tv;
tv.tv_usec = long(POP3_RETRIEVAL_TIMEOUT-(tv.tv_sec * 1e6)); tv.tv_sec = POP3_RETRIEVAL_TIMEOUT / 1000000;
tv.tv_usec = POP3_RETRIEVAL_TIMEOUT % 1000000;
/* Initialize (clear) the socket mask. */
FD_ZERO(&fds); struct fd_set readSet;
FD_ZERO(&readSet);
/* Set the socket in the mask. */ FD_SET(fSocket, &readSet);
FD_SET(conn, &fds);
int result = -1; int result;
#ifdef USESSL #ifdef USESSL
if ((use_ssl) && (SSL_pending(ssl))) if (fUseSSL && SSL_pending(fSSL))
result = 1; result = 1;
else else
#endif #endif
result = select(32, &fds, NULL, NULL, &tv); result = select(fSocket + 1, &readSet, NULL, NULL, &tv);
if (result < 0)
return B_TIMEOUT;
if (result > 0) { if (result > 0) {
while (true) { // Hope there's an end of line out there else this gets stuck. while (true) {
#ifdef USESSL // Hope there's an end of line out there else this gets stuck.
if (use_ssl) int32 bytesReceived;
rcv = SSL_read(ssl,&c,1); uint8 c = 0;
#ifdef USESSL
if (fUseSSL)
bytesReceived = SSL_read(fSSL, (char*)&c, 1);
else else
#endif #endif
rcv = recv(conn, &c, 1, 0); bytesReceived = recv(fSocket, &c, 1, 0);
if (rcv < 0) if (bytesReceived < 0)
return errno; //--An error! return errno;
//putchar(c);
if ((c == '\n') || (rcv == 0 /* EOF */)) if (c == '\n' || bytesReceived == 0 /* EOF */)
break; break;
if (c == '\r') { if (c == '\r') {
@@ -603,68 +617,72 @@ POP3Protocol::ReceiveLine(BString &line)
} }
} }
} else { } else {
fLog = "POP3 socket timeout."; status_t error = errno;
fLog = "POP3 ";
fLog << strerror(error) << ".";
runner->Stop(true); runner->Stop(true);
return error;
} }
return len; return len;
} }
status_t
status_t
POP3Protocol::SendCommand(const char *cmd) POP3Protocol::SendCommand(const char *cmd)
{ {
if (conn < 0 || conn > FD_SETSIZE) if (fSocket < 0 || fSocket > FD_SETSIZE)
return B_FILE_ERROR; return B_FILE_ERROR;
//printf(cmd); //printf(cmd);
// Flush any accumulated garbage data before we send our command, so we // Flush any accumulated garbage data before we send our command, so we
// don't misinterrpret responses from previous commands (that got left over // don't misinterrpret responses from previous commands (that got left over
// due to bugs) as being from this command. // due to bugs) as being from this command.
struct timeval tv; struct timeval tv;
tv.tv_sec = long(1000 / 1e6); tv.tv_sec = 0;
tv.tv_usec = long(1000-(tv.tv_sec * 1e6)); /* very short timeout, hangs with 0 in R5 */ tv.tv_usec = 1000;
/* very short timeout, hangs with 0 in R5 */
struct fd_set fds; struct fd_set readSet;
FD_ZERO(&readSet);
/* Initialize (clear) the socket mask. */ FD_SET(fSocket, &readSet);
FD_ZERO(&fds); int result;
#ifdef USESSL
/* Set the socket in the mask. */ if (fUseSSL && SSL_pending(fSSL))
FD_SET(conn, &fds); result = 1;
int result; else
#ifdef USESSL #endif
if ((use_ssl) && (SSL_pending(ssl))) result = select(fSocket + 1, &readSet, NULL, NULL, &tv);
result = 1;
else
#endif
result = select(32, &fds, NULL, NULL, &tv);
if (result > 0) { if (result > 0) {
int amountReceived; int amountReceived;
char tempString [1025]; char tempString [1025];
#ifdef USESSL #ifdef USESSL
if (use_ssl) if (fUseSSL)
amountReceived = SSL_read(ssl,tempString, sizeof (tempString) - 1); amountReceived = SSL_read(fSSL, tempString, sizeof(tempString) - 1);
else else
#endif #endif
amountReceived = recv (conn,tempString, sizeof (tempString) - 1,0); amountReceived = recv(fSocket, tempString, sizeof(tempString) - 1, 0);
if (amountReceived < 0) if (amountReceived < 0)
return errno; return errno;
tempString [amountReceived] = 0; tempString [amountReceived] = 0;
printf ("POP3Protocol::SendCommand Bug! Had to flush %d bytes: %s\n", printf ("POP3Protocol::SendCommand Bug! Had to flush %d bytes: %s\n",
amountReceived, tempString); amountReceived, tempString);
//if (amountReceived == 0) //if (amountReceived == 0)
// break; // break;
} }
#ifdef USESSL #ifdef USESSL
if (use_ssl) { if (fUseSSL) {
SSL_write(ssl,cmd,::strlen(cmd)); SSL_write(fSSL, cmd,::strlen(cmd));
//SSL_write(ssl,"\r\n",2);
} else } else
#endif #endif
if (send(conn, cmd, ::strlen(cmd), 0) < 0) { if (send(fSocket, cmd, ::strlen(cmd), 0) < 0) {
fLog = strerror(errno); fLog = strerror(errno);
printf ("POP3Protocol::SendCommand Send \"%s\" failed, code %d: %s\n", printf("POP3Protocol::SendCommand Send \"%s\" failed, code %d: %s\n",
cmd, errno, fLog.String()); cmd, errno, fLog.String());
return errno; return errno;
} }
@@ -685,7 +703,9 @@ POP3Protocol::SendCommand(const char *cmd)
} else { } else {
printf("POP3Protocol::SendCommand \"%s\" got nonsense message " printf("POP3Protocol::SendCommand \"%s\" got nonsense message "
"from server: %s\n", cmd, fLog.String()); "from server: %s\n", cmd, fLog.String());
err = B_BAD_VALUE; //-------If it's not +OK, and it's not -ERR, then what the heck is it? Presume an error err = B_BAD_VALUE;
// If it's not +OK, and it's not -ERR, then what the heck
// is it? Presume an error
break; break;
} }
} }
@@ -693,51 +713,59 @@ POP3Protocol::SendCommand(const char *cmd)
} }
void POP3Protocol::MD5Digest (unsigned char *in,char *ascii_digest) void
POP3Protocol::MD5Digest(unsigned char *in, char *asciiDigest)
{ {
unsigned char digest[16]; unsigned char digest[16];
#ifdef USESSL #ifdef USESSL
MD5(in, ::strlen((char*)in),digest); MD5(in, ::strlen((char*)in), digest);
#else #else
MD5_CTX context; MD5_CTX context;
MD5Init(&context); MD5Init(&context);
MD5Update(&context, in, ::strlen((char*)in)); MD5Update(&context, in, ::strlen((char*)in));
MD5Final(digest, &context); MD5Final(digest, &context);
#endif #endif
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++) {
sprintf(ascii_digest+2*i, "%02x", digest[i]); sprintf(asciiDigest + 2 * i, "%02x", digest[i]);
}
return; return;
} }
BMailFilter *instantiate_mailfilter(BMessage *settings, BMailChainRunner *runner) // #pragma mark -
BMailFilter *
instantiate_mailfilter(BMessage *settings, BMailChainRunner *runner)
{ {
return new POP3Protocol(settings,runner); return new POP3Protocol(settings,runner);
} }
BView* instantiate_config_panel(BMessage *settings,BMessage *) BView*
instantiate_config_panel(BMessage *settings, BMessage *)
{ {
BMailProtocolConfigView *view = new BMailProtocolConfigView(B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_AUTH_METHODS | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME | B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER BMailProtocolConfigView *view = new BMailProtocolConfigView(
#if USESSL B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_AUTH_METHODS
| B_MAIL_PROTOCOL_HAS_FLAVORS); | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME
#else | B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER
#if USESSL
| B_MAIL_PROTOCOL_HAS_FLAVORS
#endif
); );
#endif
view->AddAuthMethod("Plain Text"); view->AddAuthMethod("Plain Text");
view->AddAuthMethod("APOP"); view->AddAuthMethod("APOP");
#if USESSL #if USESSL
view->AddFlavor("No Encryption"); view->AddFlavor("No Encryption");
view->AddFlavor("SSL"); view->AddFlavor("SSL");
#endif #endif
view->SetTo(settings); view->SetTo(settings);
return view; return view;
} }
@@ -27,26 +27,27 @@ class POP3Protocol : public SimpleMailProtocol {
size_t MailDropSize(void); size_t MailDropSize(void);
protected: protected:
status_t RetrieveInternal(const char *command,int32 message, BPositionIO *write_to, bool show_progress); status_t RetrieveInternal(const char *command, int32 message,
BPositionIO *writeTo, bool showProgress);
int32 ReceiveLine(BString &line); int32 ReceiveLine(BString &line);
status_t SendCommand(const char* cmd); status_t SendCommand(const char* cmd);
void MD5Digest (unsigned char *in, char *out); // MD5 Digest void MD5Digest(unsigned char *in, char *out);
private: private:
int conn; int fSocket;
BString fLog; BString fLog;
int32 fNumMessages; int32 fNumMessages;
size_t fMailDropSize; size_t fMailDropSize;
BList sizes; BList fSizes;
#ifdef USESSL #ifdef USESSL
SSL_CTX *ctx; SSL_CTX* fSSLContext;
SSL *ssl; SSL* fSSL;
BIO *sbio; BIO* fSSLBio;
bool use_ssl; bool fUseSSL;
#endif #endif
}; };
#endif /* ZOIDBERG_POP3_H */ #endif /* ZOIDBERG_POP3_H */