Attempt to fix several flaws that prevented me from backing up my 650MB of mails from my BeOS partition:
- Select() didn't actually reselect even when asked to force things from AddMessage(), making the uploaded mail get an off-by-one unique id assigned and a second copy downloaded on subsequent fetching, though this would really need proofreading as I'm not really sure how it all works, - the allocated buffer wasn't freed, making mail_daemon allocate 650MB, which obviously crashed when out of physical ram, now it only uses 15MB :p, - try to find workable IMAP flags for sent and pending mails, or use custom ones when the server allows arbitrary flags, - the LIST command wasn't checked for correct response, making subsequent commands like CREATE mailbox fail from the OK answer of previous ones when syncing on a new accound, - try to read the creating time (actually modification time since creation time is reset when copying files around) and pass it to APPEND command so I won't get the whole 10000 mails all received as of today. Now I can put all my old mails on an imap server (tested on dovecot) to read it from other OSes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36995 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -114,6 +114,8 @@ class IMAP4Client : public BRemoteMailStorageProtocol {
|
|||||||
bool force_reselect;
|
bool force_reselect;
|
||||||
|
|
||||||
int32 fLastExists;
|
int32 fLastExists;
|
||||||
|
BString fSentFlag;
|
||||||
|
BString fPendingFlag;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoopWorker : public BHandler {
|
class NoopWorker : public BHandler {
|
||||||
@@ -386,6 +388,7 @@ void IMAP4Client::InitializeMailboxes() {
|
|||||||
hierarchy_delimiter = dem[2]();
|
hierarchy_delimiter = dem[2]();
|
||||||
if (hierarchy_delimiter == "" || hierarchy_delimiter == "NIL")
|
if (hierarchy_delimiter == "" || hierarchy_delimiter == "NIL")
|
||||||
hierarchy_delimiter = "/";
|
hierarchy_delimiter = "/";
|
||||||
|
WasCommandOkay(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mb_root.ByteAt(mb_root.Length() - 1) != hierarchy_delimiter.ByteAt(0)) {
|
if (mb_root.ByteAt(mb_root.Length() - 1) != hierarchy_delimiter.ByteAt(0)) {
|
||||||
@@ -433,17 +436,33 @@ status_t IMAP4Client::AddMessage(const char *mailbox, BPositionIO *data, BString
|
|||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
BString status;
|
BString status;
|
||||||
node->ReadAttrString(B_MAIL_ATTR_STATUS,&status);
|
node->ReadAttrString(B_MAIL_ATTR_STATUS,&status);
|
||||||
/*if (status == "Sent")
|
if (status == "Sent" && fSentFlag.Length())
|
||||||
attributes += " \\Sent";
|
attributes << " " << fSentFlag;
|
||||||
if (status == "Pending")
|
if (status == "Pending" && fPendingFlag.Length())
|
||||||
attributes += " \\Sent";*/
|
attributes << " " << fPendingFlag;
|
||||||
if (status == "Replied")
|
if (status == "Replied")
|
||||||
attributes += " \\Answered";
|
attributes += " \\Answered";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BString receivedDate;
|
||||||
|
BFile *file = dynamic_cast<BFile *> (data);
|
||||||
|
time_t creationTime;
|
||||||
|
// actually creation time is reset on file copy, modification time seems better...
|
||||||
|
if (file && file->GetModificationTime(&creationTime) == B_OK) {
|
||||||
|
struct tm tm;
|
||||||
|
localtime_r(&creationTime, &tm);
|
||||||
|
char *buffer = receivedDate.LockBuffer(256);
|
||||||
|
|
||||||
command << ((struct mailbox_info *)(box_info.ItemAt(box_index)))->server_mb_name << "\" (" << attributes << ") {" << size << '}';
|
strftime(buffer, 256, "%e-%b-%Y %H:%M:%S %z", &tm);
|
||||||
|
receivedDate.UnlockBuffer();
|
||||||
|
receivedDate.Prepend('"', 1);
|
||||||
|
receivedDate << "\" ";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
command << ((struct mailbox_info *)(box_info.ItemAt(box_index)))->server_mb_name
|
||||||
|
<< "\" (" << attributes << ") " << receivedDate << "{" << size << '}';
|
||||||
SendCommand(command.String());
|
SendCommand(command.String());
|
||||||
status_t err = ReceiveLine(command);
|
status_t err = ReceiveLine(command);
|
||||||
if (err < B_OK)
|
if (err < B_OK)
|
||||||
@@ -461,7 +480,10 @@ status_t IMAP4Client::AddMessage(const char *mailbox, BPositionIO *data, BString
|
|||||||
send(net,buffer,size,0);
|
send(net,buffer,size,0);
|
||||||
send(net,"\r\n",2,0);
|
send(net,"\r\n",2,0);
|
||||||
}
|
}
|
||||||
Select(mailbox,false,false,false,true);
|
delete [] buffer;
|
||||||
|
|
||||||
|
force_reselect = true;
|
||||||
|
Select(mailbox,true,false,false,false,false);
|
||||||
|
|
||||||
if (((struct mailbox_info *)(box_info.ItemAt(box_index)))->next_uid <= 0) {
|
if (((struct mailbox_info *)(box_info.ItemAt(box_index)))->next_uid <= 0) {
|
||||||
command = "FETCH ";
|
command = "FETCH ";
|
||||||
@@ -679,7 +701,7 @@ status_t IMAP4Client::Select(const char *mb, bool reselect, bool queue_new_messa
|
|||||||
|
|
||||||
const char *real_mb = info->server_mb_name.String();
|
const char *real_mb = info->server_mb_name.String();
|
||||||
|
|
||||||
if ((selected_mb != real_mb) || (noop) || (no_command)) {
|
if ((selected_mb != real_mb) || (noop) || (no_command) || (reselect)) {
|
||||||
if ((selected_mb != "") && (selected_mb != real_mb)){
|
if ((selected_mb != "") && (selected_mb != real_mb)){
|
||||||
BString trash;
|
BString trash;
|
||||||
if (SendCommand("CLOSE") < B_OK)
|
if (SendCommand("CLOSE") < B_OK)
|
||||||
@@ -689,7 +711,7 @@ status_t IMAP4Client::Select(const char *mb, bool reselect, bool queue_new_messa
|
|||||||
WasCommandOkay(trash);
|
WasCommandOkay(trash);
|
||||||
}
|
}
|
||||||
BString cmd;
|
BString cmd;
|
||||||
if (selected_mb == real_mb)
|
if (selected_mb == real_mb && !reselect)
|
||||||
cmd = "NOOP";
|
cmd = "NOOP";
|
||||||
else
|
else
|
||||||
cmd << "SELECT \"" << real_mb << '\"';
|
cmd << "SELECT \"" << real_mb << '\"';
|
||||||
@@ -720,6 +742,32 @@ status_t IMAP4Client::Select(const char *mb, bool reselect, bool queue_new_messa
|
|||||||
|
|
||||||
if ((response.CountItems() > 1) && (strcasecmp(response[1](),"RECENT") == 0))
|
if ((response.CountItems() > 1) && (strcasecmp(response[1](),"RECENT") == 0))
|
||||||
recent = atoi(response[0]());
|
recent = atoi(response[0]());
|
||||||
|
|
||||||
|
// search a workable Sent flag.
|
||||||
|
// cf.
|
||||||
|
// http://serverfault.com/questions/115769/which-imap-flags-are-reliably-supported-across-most-mail-servers
|
||||||
|
if (response[0].CountItems() == 2 && strcasecmp(response[0][0](),"PERMANENTFLAGS") == 0) {
|
||||||
|
//PRINT(("PERM FLAGS: '%s'\n", response[0][1]()));
|
||||||
|
for (int i = 0; i < response[0][1].CountItems(); i++) {
|
||||||
|
BString flag(response[0][1][i]());
|
||||||
|
//PRINT(("PERM FLAGS[%d]: '%s'\n", i, response[0][1][i]()));
|
||||||
|
// lucky you
|
||||||
|
if (flag == "\\Sent")
|
||||||
|
fSentFlag = "\\Sent";
|
||||||
|
// the server supports arbitrary flags, define our own;
|
||||||
|
else if (flag == "\\*")
|
||||||
|
fSentFlag = "$Sent";
|
||||||
|
// note $MDNSent is not the same, it's used for delivery notifications...
|
||||||
|
|
||||||
|
if (flag == "\\Pending")
|
||||||
|
fPendingFlag = "\\Pending";
|
||||||
|
// the server supports arbitrary flags, define our own;
|
||||||
|
else if (flag == "\\*")
|
||||||
|
fPendingFlag = "$Pending";
|
||||||
|
}
|
||||||
|
//PRINT(("Sent FLAG: '%s'\n", fSentFlag.String()));
|
||||||
|
//PRINT(("Pending FLAG: '%s'\n", fPendingFlag.String()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whenever the mailbox is updated, only EXISTS is sent so we have no
|
// Whenever the mailbox is updated, only EXISTS is sent so we have no
|
||||||
@@ -871,12 +919,18 @@ status_t IMAP4Client::GetMessage(const char *mailbox, const char *message, BPosi
|
|||||||
if (strcmp(response[2][1][i](),"\\Seen") == 0) {
|
if (strcmp(response[2][1][i](),"\\Seen") == 0) {
|
||||||
headers->AddString("STATUS","Read");
|
headers->AddString("STATUS","Read");
|
||||||
}
|
}
|
||||||
if (strcmp(response[2][1][i](),"\\Sent") == 0) {
|
if (fSentFlag.Length() && strcmp(response[2][1][i](),fSentFlag.String()) == 0) {
|
||||||
if (headers->HasString("STATUS"))
|
if (headers->HasString("STATUS"))
|
||||||
headers->ReplaceString("STATUS","Sent");
|
headers->ReplaceString("STATUS","Sent");
|
||||||
else
|
else
|
||||||
headers->AddString("STATUS","Sent");
|
headers->AddString("STATUS","Sent");
|
||||||
}
|
}
|
||||||
|
if (fPendingFlag.Length() && strcmp(response[2][1][i](),fPendingFlag.String()) == 0) {
|
||||||
|
if (headers->HasString("STATUS"))
|
||||||
|
headers->ReplaceString("STATUS","Pending");
|
||||||
|
else
|
||||||
|
headers->AddString("STATUS","Pending");
|
||||||
|
}
|
||||||
if (strcmp(response[2][1][i](),"\\Answered") == 0) {
|
if (strcmp(response[2][1][i](),"\\Answered") == 0) {
|
||||||
if (headers->HasString("STATUS"))
|
if (headers->HasString("STATUS"))
|
||||||
headers->ReplaceString("STATUS","Replied");
|
headers->ReplaceString("STATUS","Replied");
|
||||||
|
|||||||
Reference in New Issue
Block a user