Files
haiku-beta6/src/add-ons/mail_daemon/inbound_protocols/pop3/pop3.cpp
T

1007 lines
23 KiB
C++

/*
* Copyright 2007-2011, Haiku, Inc. All rights reserved.
* Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
*
* Distributed under the terms of the MIT License.
*/
//! POP3Protocol - implementation of the POP3 protocol
#include "pop3.h"
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
#if USE_SSL
#include <openssl/md5.h>
#else
#include "md5.h"
#endif
#include <Alert.h>
#include <Catalog.h>
#include <Debug.h>
#include <Directory.h>
#include <fs_attr.h>
#include <Path.h>
#include <SecureSocket.h>
#include <String.h>
#include <VolumeRoster.h>
#include <Query.h>
#include "crypt.h"
#include "MailSettings.h"
#include "MessageIO.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "pop3"
static void NotHere(BStringList &that, BStringList &otherList,
BStringList *results)
{
for (int32 i = 0; i < otherList.CountStrings(); i++) {
if (!that.HasString(otherList.StringAt(i)))
results->Add(otherList.StringAt(i));
}
}
#define POP3_RETRIEVAL_TIMEOUT 60000000
#define CRLF "\r\n"
POP3Protocol::POP3Protocol(BMailAccountSettings* settings)
:
InboundProtocol(settings),
fNumMessages(-1),
fMailDropSize(0),
fServerConnection(NULL)
{
printf("POP3Protocol::POP3Protocol(BMailAccountSettings* settings)\n");
fSettings = fAccountSettings.InboundSettings().Settings();
fUseSSL = fSettings.FindInt32("flavor") == 1 ? true : false;
if (fSettings.FindString("destination", &fDestinationDir) != B_OK)
fDestinationDir = "/boot/home/mail/in";
create_directory(fDestinationDir, 0777);
fFetchBodyLimit = 0;
if (fSettings.HasInt32("partial_download_limit"))
fFetchBodyLimit = fSettings.FindInt32("partial_download_limit");
}
POP3Protocol::~POP3Protocol()
{
Disconnect();
}
status_t
POP3Protocol::Connect()
{
status_t error = Open(fSettings.FindString("server"), fSettings.FindInt32("port"),
fSettings.FindInt32("flavor"));
if (error != B_OK)
return error;
char* password = get_passwd(&fSettings, "cpasswd");
error = Login(fSettings.FindString("username"), password,
fSettings.FindInt32("auth_method"));
delete[] password;
if (error != B_OK)
fServerConnection->Disconnect();
return error;
}
status_t
POP3Protocol::Disconnect()
{
if (fServerConnection == NULL)
return B_OK;
SendCommand("QUIT" CRLF);
fServerConnection->Disconnect();
delete fServerConnection;
fServerConnection = NULL;
return B_OK;
}
status_t
POP3Protocol::SyncMessages()
{
bool leaveOnServer;
if (fSettings.FindBool("leave_mail_on_server", &leaveOnServer) != B_OK)
leaveOnServer = true;
// create directory if not exist
create_directory(fDestinationDir, 0777);
printf("POP3Protocol::SyncMessages()\n");
_ReadManifest();
SetTotalItems(2);
ReportProgress(0, 1, B_TRANSLATE("Connect to server" B_UTF8_ELLIPSIS));
status_t error = Connect();
if (error < B_OK) {
ResetProgress();
return error;
}
ReportProgress(0, 1, B_TRANSLATE("Getting UniqueIDs" B_UTF8_ELLIPSIS));
error = _UniqueIDs();
if (error < B_OK) {
ResetProgress();
Disconnect();
return error;
}
BStringList toDownload;
NotHere(fManifest, fUniqueIDs, &toDownload);
int32 numMessages = toDownload.CountStrings();
if (numMessages == 0) {
CheckForDeletedMessages();
ResetProgress();
Disconnect();
return B_OK;
}
ResetProgress();
SetTotalItems(toDownload.CountStrings());
printf("POP3: Messages to download: %i\n", (int)toDownload.CountStrings());
for (int32 i = 0; i < toDownload.CountStrings(); i++) {
const char* uid = toDownload.StringAt(i);
int32 toRetrieve = fUniqueIDs.IndexOf(uid);
if (toRetrieve < 0) {
// should not happen!
error = B_NAME_NOT_FOUND;
printf("POP3: uid %s index %i not found in fUniqueIDs!\n", uid,
(int)toRetrieve);
continue;
}
BPath path(fDestinationDir);
BString fileName = "Downloading file... uid: ";
fileName += uid;
fileName.ReplaceAll("/", "_SLASH_");
path.Append(fileName);
BEntry entry(path.Path());
BFile file(&entry, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
error = file.InitCheck();
if (error != B_OK) {
printf("POP3: Can't create file %s\n ", path.Path());
break;
}
BMailMessageIO mailIO(this, &file, toRetrieve);
entry_ref ref;
entry.GetRef(&ref);
// the ref becomes invalid after renaming the file thus we already
// write the status here
MarkMessageAsRead(ref, B_UNREAD);
int32 size = MessageSize(toRetrieve);
if (fFetchBodyLimit < 0 || size <= fFetchBodyLimit) {
error = mailIO.Seek(0, SEEK_END);
if (error < 0) {
printf("POP3: Failed to download body %s\n ", uid);
break;
}
NotifyHeaderFetched(ref, &file);
NotifyBodyFetched(ref, &file);
if (!leaveOnServer)
Delete(toRetrieve);
} else {
int32 dummy;
error = mailIO.ReadAt(0, &dummy, 1);
if (error < 0) {
printf("POP3: Failed to download header %s\n ", uid);
break;
}
NotifyHeaderFetched(ref, &file);
}
ReportProgress(0, 1);
if (file.WriteAttr("MAIL:unique_id", B_STRING_TYPE, 0, uid,
strlen(uid)) < 0) {
error = B_ERROR;
}
file.WriteAttr("MAIL:size", B_INT32_TYPE, 0, &size, sizeof(int32));
// save manifest in case we get disturbed
fManifest.Add(uid);
_WriteManifest();
}
ResetProgress();
CheckForDeletedMessages();
Disconnect();
return error;
}
status_t
POP3Protocol::FetchBody(const entry_ref& ref)
{
ResetProgress("Fetch body");
SetTotalItems(1);
status_t error = Connect();
if (error < B_OK)
return error;
error = _UniqueIDs();
if (error < B_OK) {
Disconnect();
return error;
}
BFile file(&ref, B_READ_WRITE);
status_t status = file.InitCheck();
if (status != B_OK) {
Disconnect();
return status;
}
char uidString[256];
BNode node(&ref);
if (node.ReadAttr("MAIL:unique_id", B_STRING_TYPE, 0, uidString, 256) < 0) {
Disconnect();
return B_ERROR;
}
int32 toRetrieve = fUniqueIDs.IndexOf(uidString);
if (toRetrieve < 0) {
Disconnect();
return B_NAME_NOT_FOUND;
}
bool leaveOnServer;
if (fSettings.FindBool("leave_mail_on_server", &leaveOnServer) != B_OK)
leaveOnServer = true;
// TODO: get rid of this BMailMessageIO!
BMailMessageIO io(this, &file, toRetrieve);
// read body
status = io.Seek(0, SEEK_END);
if (status < 0) {
Disconnect();
return status;
}
NotifyBodyFetched(ref, &file);
if (!leaveOnServer)
Delete(toRetrieve);
ReportProgress(0, 1);
ResetProgress();
Disconnect();
return B_OK;
}
status_t
POP3Protocol::DeleteMessage(const entry_ref& ref)
{
status_t error = Connect();
if (error < B_OK)
return error;
error = _UniqueIDs();
if (error < B_OK) {
Disconnect();
return error;
}
char uidString[256];
BNode node(&ref);
if (node.ReadAttr("MAIL:unique_id", B_STRING_TYPE, 0, uidString, 256) < 0) {
Disconnect();
return B_ERROR;
}
#if DEBUG
printf("DeleteMessage: ID is %d\n", (int)fUniqueIDs.IndexOf(uidString));
// What should we use for int32 instead of %d?
#endif
Delete(fUniqueIDs.IndexOf(uidString));
Disconnect();
return B_OK;
}
status_t
POP3Protocol::Open(const char* server, int port, int)
{
ReportProgress(0, 0, B_TRANSLATE("Connecting to POP3 server"
B_UTF8_ELLIPSIS));
if (port <= 0)
port = fUseSSL ? 995 : 110;
fLog = "";
// Prime the error message
BString error_msg, servString;
error_msg << B_TRANSLATE("Error while connecting to server %serv");
servString << server;
error_msg.ReplaceFirst("%serv", servString);
if (port != 110)
error_msg << ":" << port;
uint32 hostIP = inet_addr(server);
// first see if we can parse it as a numeric address
if (hostIP == 0 || hostIP == ~0UL) {
struct hostent * he = gethostbyname(server);
hostIP = he ? *((uint32*)he->h_addr) : 0;
}
if (hostIP == 0) {
error_msg << B_TRANSLATE(": Connection refused or host not found");
ShowError(error_msg.String());
return B_NAME_NOT_FOUND;
}
delete fServerConnection;
fServerConnection = NULL;
if (fUseSSL) {
fServerConnection = new(std::nothrow) BSecureSocket(
BNetworkAddress(server, port));
} else {
fServerConnection = new(std::nothrow) BSocket(BNetworkAddress(
server, port));
}
if (fServerConnection == NULL)
return B_NO_MEMORY;
if (fServerConnection->InitCheck() != B_OK)
return fServerConnection->InitCheck();
BString line;
status_t err = ReceiveLine(line);
if (err < 0) {
fServerConnection->Disconnect();
error_msg << ": " << strerror(err);
ShowError(error_msg.String());
return B_ERROR;
}
if (strncmp(line.String(), "+OK", 3) != 0) {
if (line.Length() > 0) {
error_msg << B_TRANSLATE(". The server said:\n")
<< line.String();
} else
error_msg << B_TRANSLATE(": No reply.\n");
ShowError(error_msg.String());
fServerConnection->Disconnect();
return B_ERROR;
}
fLog = line;
return B_OK;
}
status_t
POP3Protocol::Login(const char *uid, const char *password, int method)
{
status_t err;
BString error_msg, userString;
error_msg << B_TRANSLATE("Error while authenticating user %user");
userString << uid;
error_msg.ReplaceFirst("%user", userString);
if (method == 1) { //APOP
int32 index = fLog.FindFirst("<");
if(index != B_ERROR) {
ReportProgress(0, 0, B_TRANSLATE("Sending APOP authentication"
B_UTF8_ELLIPSIS));
int32 end = fLog.FindFirst(">",index);
BString timestamp("");
fLog.CopyInto(timestamp, index, end - index + 1);
timestamp += password;
char md5sum[33];
MD5Digest((unsigned char*)timestamp.String(), md5sum);
BString cmd = "APOP ";
cmd += uid;
cmd += " ";
cmd += md5sum;
cmd += CRLF;
err = SendCommand(cmd.String());
if (err != B_OK) {
error_msg << B_TRANSLATE(". The server said:\n") << fLog;
ShowError(error_msg.String());
return err;
}
return B_OK;
} else {
error_msg << B_TRANSLATE(": The server does not support APOP.");
ShowError(error_msg.String());
return B_NOT_ALLOWED;
}
}
ReportProgress(0, 0, B_TRANSLATE("Sending username" B_UTF8_ELLIPSIS));
BString cmd = "USER ";
cmd += uid;
cmd += CRLF;
err = SendCommand(cmd.String());
if (err != B_OK) {
error_msg << B_TRANSLATE(". The server said:\n") << fLog;
ShowError(error_msg.String());
return err;
}
ReportProgress(0, 0, B_TRANSLATE("Sending password" B_UTF8_ELLIPSIS));
cmd = "PASS ";
cmd += password;
cmd += CRLF;
err = SendCommand(cmd.String());
if (err != B_OK) {
error_msg << B_TRANSLATE(". The server said:\n") << fLog;
ShowError(error_msg.String());
return err;
}
return B_OK;
}
status_t
POP3Protocol::Stat()
{
ReportProgress(0, 0, B_TRANSLATE("Getting mailbox size" B_UTF8_ELLIPSIS));
if (SendCommand("STAT" CRLF) < B_OK)
return B_ERROR;
int32 messages, dropSize;
if (sscanf(fLog.String(), "+OK %" B_SCNd32" %" B_SCNd32, &messages,
&dropSize) < 2)
return B_ERROR;
fNumMessages = messages;
fMailDropSize = dropSize;
return B_OK;
}
int32
POP3Protocol::Messages()
{
if (fNumMessages < 0)
Stat();
return fNumMessages;
}
size_t
POP3Protocol::MailDropSize()
{
if (fNumMessages < 0)
Stat();
return fMailDropSize;
}
void
POP3Protocol::CheckForDeletedMessages()
{
{
//---Delete things from the manifest no longer on the server
BStringList temp;
NotHere(fUniqueIDs, fManifest, &temp);
fManifest.Remove(temp);
}
if (!fSettings.FindBool("delete_remote_when_local")
|| fManifest.CountStrings() == 0)
return;
BStringList toDelete;
BStringList queryContents;
BVolumeRoster volumes;
BVolume volume;
while (volumes.GetNextVolume(&volume) == B_OK) {
BQuery fido;
entry_ref entry;
fido.SetVolume(&volume);
fido.PushAttr(B_MAIL_ATTR_ACCOUNT_ID);
fido.PushInt32(fAccountSettings.AccountID());
fido.PushOp(B_EQ);
fido.Fetch();
BString uid;
while (fido.GetNextRef(&entry) == B_OK) {
BNode(&entry).ReadAttrString("MAIL:unique_id", &uid);
queryContents.Add(uid);
}
}
NotHere(queryContents, fManifest, &toDelete);
for (int32 i = 0; i < toDelete.CountStrings(); i++) {
printf("delete mail on server uid %s\n", toDelete.StringAt(i).String());
Delete(fUniqueIDs.IndexOf(toDelete.StringAt(i)));
}
// Don't remove ids from fUniqueIDs, the indices have to stay the same when
// retrieving new messages.
fManifest.Remove(toDelete);
// TODO: at some point the purged manifest should be written to disk
// otherwise it will grow forever
}
status_t
POP3Protocol::Retrieve(int32 message, BPositionIO *write_to)
{
status_t returnCode;
BString cmd;
cmd << "RETR " << message + 1 << CRLF;
returnCode = RetrieveInternal(cmd.String(), message, write_to, true);
ReportProgress(0 /* bytes */, 1 /* messages */);
if (returnCode == B_OK) { // Some debug code.
int32 message_len = MessageSize(message);
write_to->Seek (0, SEEK_END);
if (write_to->Position() != message_len) {
printf ("POP3Protocol::Retrieve Note: message size is %" B_PRIdOFF
", was expecting %" B_PRId32 ", for message #%" B_PRId32 ". "
"Could be a transmission error or a bad POP server "
"implementation (does it remove escape codes when it counts "
"size?).\n", write_to->Position(), message_len, message);
}
}
return returnCode;
}
status_t
POP3Protocol::GetHeader(int32 message, BPositionIO *write_to)
{
BString cmd;
cmd << "TOP " << message + 1 << " 0" << CRLF;
return RetrieveInternal(cmd.String(),message,write_to, false);
}
status_t
POP3Protocol::RetrieveInternal(const char *command, int32 message,
BPositionIO *write_to, bool post_progress)
{
const int bufSize = 1024 * 30;
// To avoid waiting for the non-arrival of the next data packet, try to
// receive only the message size, plus the 3 extra bytes for the ".\r\n"
// after the message. Of course, if we get it wrong (or it is a huge
// message or has lines starting with escaped periods), it will then switch
// back to receiving full buffers until the message is done.
int amountToReceive = MessageSize (message) + 3;
if (amountToReceive >= bufSize || amountToReceive <= 0)
amountToReceive = bufSize - 1;
BString bufBString; // Used for auto-dealloc on return feature.
char *buf = bufBString.LockBuffer (bufSize);
int amountInBuffer = 0;
int amountReceived;
int testIndex;
char *testStr;
bool cont = true;
bool flushWholeBuffer = false;
write_to->Seek(0,SEEK_SET);
if (SendCommand(command) != B_OK)
return B_ERROR;
while (cont) {
status_t result = fServerConnection->WaitForReadable(
POP3_RETRIEVAL_TIMEOUT);
if (result == B_TIMED_OUT) {
// No data available, even after waiting a minute.
fLog = "POP3 timeout - no data received after a long wait.";
return B_ERROR;
}
if (amountToReceive > bufSize - 1 - amountInBuffer)
amountToReceive = bufSize - 1 - amountInBuffer;
amountReceived = fServerConnection->Read(buf + amountInBuffer,
amountToReceive);
if (amountReceived < 0) {
fLog = strerror(errno);
return errno;
}
if (amountReceived == 0) {
fLog = "POP3 data supposedly ready to receive but not received!";
return B_ERROR;
}
amountToReceive = bufSize - 1; // For next time, read a full buffer.
amountInBuffer += amountReceived;
buf[amountInBuffer] = 0; // NUL stops tests past the end of buffer.
// Look for lines starting with a period. A single period by itself on
// a line "\r\n.\r\n" marks the end of the message (thus the need for
// at least five characters in the buffer for testing). A period
// "\r\n.Stuff" at the start of a line get deleted "\r\nStuff", since
// POP adds one as an escape code to let you have message text with
// lines starting with a period. For convenience, assume that no
// messages start with a period on the very first line, so we can
// search for the previous line's "\r\n".
for (testIndex = 0; testIndex <= amountInBuffer - 5; testIndex++) {
testStr = buf + testIndex;
if (testStr[0] == '\r' && testStr[1] == '\n' && testStr[2] == '.') {
if (testStr[3] == '\r' && testStr[4] == '\n') {
// Found the end of the message marker. Ignore remaining data.
if (amountInBuffer > testIndex + 5)
printf ("POP3Protocol::RetrieveInternal Ignoring %d bytes "
"of extra data past message end.\n",
amountInBuffer - (testIndex + 5));
amountInBuffer = testIndex + 2; // Don't include ".\r\n".
buf[amountInBuffer] = 0;
cont = false;
} else {
// Remove an extra period at the start of a line.
// Inefficient, but it doesn't happen often that you have a
// dot starting a line of text. Of course, a file with a
// lot of double period lines will get processed very
// slowly.
memmove (buf + testIndex + 2, buf + testIndex + 3,
amountInBuffer - (testIndex + 3) + 1 /* for NUL at end */);
amountInBuffer--;
// Watch out for the end of buffer case, when the POP text
// is "\r\n..X". Don't want to leave the resulting
// "\r\n.X" in the buffer (flush out the whole buffer),
// since that will get mistakenly evaluated again in the
// next loop and delete a character by mistake.
if (testIndex >= amountInBuffer - 4 && testStr[2] == '.') {
printf ("POP3Protocol::RetrieveInternal: Jackpot! "
"You have hit the rare situation with an escaped "
"period at the end of the buffer. Aren't you happy"
"it decodes it correctly?\n");
flushWholeBuffer = true;
}
}
}
}
if (cont && !flushWholeBuffer) {
// Dump out most of the buffer, but leave the last 4 characters for
// comparison continuity, in case the line starting with a period
// crosses a buffer boundary.
if (amountInBuffer > 4) {
write_to->Write(buf, amountInBuffer - 4);
if (post_progress)
ReportProgress(amountInBuffer - 4,0);
memmove (buf, buf + amountInBuffer - 4, 4);
amountInBuffer = 4;
}
} else { // Dump everything - end of message or flushing the whole buffer.
write_to->Write(buf, amountInBuffer);
if (post_progress)
ReportProgress(amountInBuffer,0);
amountInBuffer = 0;
}
}
return B_OK;
}
void
POP3Protocol::Delete(int32 num)
{
BString cmd = "DELE ";
cmd << (num+1) << CRLF;
if (SendCommand(cmd.String()) != B_OK) {
// Error
}
#if DEBUG
puts(fLog.String());
#endif
/* The mail is just marked as deleted and removed from the server when
sending the QUIT command. Because of that the message number stays the same
and we keep the uid in the uid list. */
}
size_t
POP3Protocol::MessageSize(int32 index)
{
return (size_t)fSizes.ItemAt(index);
}
int32
POP3Protocol::ReceiveLine(BString &line)
{
int32 len = 0;
bool flag = false;
line = "";
status_t result = fServerConnection->WaitForReadable(
POP3_RETRIEVAL_TIMEOUT);
if (result == B_TIMED_OUT)
return errno;
while (true) {
// Hope there's an end of line out there else this gets stuck.
int32 bytesReceived;
uint8 c = 0;
bytesReceived = fServerConnection->Read((char*)&c, 1);
if (bytesReceived < 0)
return errno;
if (c == '\n' || bytesReceived == 0 /* EOF */)
break;
if (c == '\r') {
flag = true;
} else {
if (flag) {
len++;
line += '\r';
flag = false;
}
len++;
line += (char)c;
}
}
return len;
}
status_t
POP3Protocol::SendCommand(const char* cmd)
{
//printf(cmd);
// Flush any accumulated garbage data before we send our command, so we
// don't misinterrpret responses from previous commands (that got left over
// due to bugs) as being from this command.
while (fServerConnection->WaitForReadable(1000) == B_OK) {
int amountReceived;
char tempString [1024];
amountReceived = fServerConnection->Read(tempString,
sizeof(tempString) - 1);
if (amountReceived < 0)
return errno;
tempString [amountReceived] = 0;
printf ("POP3Protocol::SendCommand Bug! Had to flush %d bytes: %s\n",
amountReceived, tempString);
//if (amountReceived == 0)
// break;
}
if (fServerConnection->Write(cmd, ::strlen(cmd)) < 0) {
fLog = strerror(errno);
printf("POP3Protocol::SendCommand Send \"%s\" failed, code %d: %s\n",
cmd, errno, fLog.String());
return errno;
}
fLog = "";
status_t err = B_OK;
while (true) {
int32 len = ReceiveLine(fLog);
if (len <= 0 || fLog.ICompare("+OK", 3) == 0)
break;
if (fLog.ICompare("-ERR", 4) == 0) {
printf("POP3Protocol::SendCommand \"%s\" got error message "
"from server: %s\n", cmd, fLog.String());
err = B_ERROR;
break;
} else {
printf("POP3Protocol::SendCommand \"%s\" got nonsense message "
"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
break;
}
}
return err;
}
void
POP3Protocol::MD5Digest(unsigned char *in, char *asciiDigest)
{
unsigned char digest[16];
#ifdef USE_SSL
MD5(in, ::strlen((char*)in), digest);
#else
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, in, ::strlen((char*)in));
MD5Final(digest, &context);
#endif
for (int i = 0; i < 16; i++) {
sprintf(asciiDigest + 2 * i, "%02x", digest[i]);
}
return;
}
status_t
POP3Protocol::_UniqueIDs()
{
fUniqueIDs.MakeEmpty();
status_t ret = B_OK;
ret = SendCommand("UIDL" CRLF);
if (ret != B_OK)
return ret;
BString result;
int32 uidOffset;
while (ReceiveLine(result) > 0) {
if (result.ByteAt(0) == '.')
break;
uidOffset = result.FindFirst(' ') + 1;
result.Remove(0, uidOffset);
fUniqueIDs.Add(result);
}
if (SendCommand("LIST" CRLF) != B_OK)
return B_ERROR;
int32 b;
while (ReceiveLine(result) > 0) {
if (result.ByteAt(0) == '.')
break;
b = result.FindLast(" ");
if (b >= 0)
b = atol(&(result.String()[b]));
else
b = 0;
fSizes.AddItem((void *)(addr_t)b);
}
return ret;
}
void
POP3Protocol::_ReadManifest()
{
fManifest.MakeEmpty();
BString attr_name = "MAIL:";
attr_name << fAccountSettings.AccountID() << ":manifest";
//--- In case someone puts multiple accounts in the same directory
BNode node(fDestinationDir);
if (node.InitCheck() != B_OK)
return;
// We already have a directory so we can try to read metadata
// from it. Note that it is normal for this directory not to
// be found on the first run as it will be later created by
// the INBOX system filter.
attr_info info;
/*status_t status = node.GetAttrInfo(attr_name.String(), &info);
printf("read manifest3 status %i\n", (int)status);
status = node.GetAttrInfo(attr_name.String(), &info);
printf("read manifest3 status2 %i\n", (int)status);*/
if (node.GetAttrInfo(attr_name.String(), &info) != B_OK)
return;
void* flatmanifest = malloc(info.size);
node.ReadAttr(attr_name.String(), fManifest.TypeCode(), 0,
flatmanifest, info.size);
fManifest.Unflatten(fManifest.TypeCode(), flatmanifest, info.size);
free(flatmanifest);
}
void
POP3Protocol::_WriteManifest()
{
BString attr_name = "MAIL:";
attr_name << fAccountSettings.AccountID() << ":manifest";
//--- In case someone puts multiple accounts in the same directory
BNode node(fDestinationDir);
if (node.InitCheck() != B_OK) {
ShowError("Error while saving account manifest: cannot use "
"destination directory.");
return;
}
node.RemoveAttr(attr_name.String());
ssize_t manifestsize = fManifest.FlattenedSize();
void* flatmanifest = malloc(manifestsize);
fManifest.Flatten(flatmanifest, manifestsize);
status_t err = node.WriteAttr(attr_name.String(),
fManifest.TypeCode(), 0, flatmanifest, manifestsize);
if (err < 0) {
BString error = "Error while saving account manifest: ";
error << strerror(err);
printf("moep error\n");
ShowError(error.String());
}
free(flatmanifest);
}
// #pragma mark -
InboundProtocol*
instantiate_inbound_protocol(BMailAccountSettings* settings)
{
return new POP3Protocol(settings);
}
status_t
pop3_smtp_auth(BMailAccountSettings* settings)
{
POP3Protocol protocol(settings);
protocol.Connect();
protocol.Disconnect();
return B_OK;
}