00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qfileinfo.h>
00021 #include <stdlib.h>
00022 #include <qapplication.h>
00023 #include <qmessagebox.h>
00024 #include <qcstring.h>
00025 #include "emailhandler.h"
00026 #include <qpe/applnk.h>
00027 #include <qpe/filemanager.h>
00028
00029 QCollection::Item EnclosureList::newItem(QCollection::Item d)
00030 {
00031 return dupl( (Enclosure *) d);
00032 }
00033
00034 Enclosure* EnclosureList::dupl(Enclosure *in)
00035 {
00036 ac = new Enclosure(*in);
00037 return ac;
00038 }
00039
00040 EmailHandler::EmailHandler()
00041 {
00042 qDebug("EMailHandler::EmailHandler");
00043
00044 smtpClient = new SmtpClient();
00045 popClient = new PopClient();
00046
00047 connect(smtpClient, SIGNAL(errorOccurred(int,const QString&)), this,
00048 SIGNAL(smtpError(int,const QString&)) );
00049 connect(smtpClient, SIGNAL(mailSent()), this, SIGNAL(mailSent()) );
00050 connect(smtpClient, SIGNAL(updateStatus(const QString&)), this,
00051 SIGNAL(updateSmtpStatus(const QString&)) );
00052
00053 connect(popClient, SIGNAL(errorOccurred(int,const QString&)), this,
00054 SIGNAL(popError(int,const QString&)) );
00055 connect(popClient, SIGNAL(newMessage(const QString&,int,uint,bool)),
00056 this, SLOT(messageArrived(const QString&,int,uint,bool)) );
00057 connect(popClient, SIGNAL(updateStatus(const QString&)), this,
00058 SIGNAL(updatePopStatus(const QString&)) );
00059 connect(popClient, SIGNAL(mailTransfered(int)), this,
00060 SIGNAL(mailTransfered(int)) );
00061
00062
00063
00064 connect(popClient, SIGNAL(currentMailSize(int)),
00065 this, SIGNAL(currentMailSize(int)) );
00066 connect(popClient, SIGNAL(downloadedSize(int)),
00067 this, SIGNAL(downloadedSize(int)) );
00068 }
00069
00070 void EmailHandler::sendMail(QList<Email> *mailList)
00071 {
00072 Email *currentMail;
00073 QString temp;
00074 QString userName = QString::null;
00075
00076
00077 userName += "<" + mailAccount.emailAddress + ">";
00078
00079 for (currentMail = mailList->first(); currentMail != 0;
00080 currentMail = mailList->next()) {
00081
00082 if (encodeMime(currentMail) == 0) {
00083 smtpClient->addMail(userName, currentMail->subject,
00084 currentMail->recipients, currentMail->rawMail);
00085 } else {
00086 temp = tr("Could not locate all files in \nmail with subject: ") +
00087 currentMail->subject;
00088 temp += tr("\nMail has NOT been sent");
00089 QMessageBox::warning(qApp->activeWindow(), tr("Attachment error"), temp, tr("OK\n"));
00090
00091 }
00092 }
00093 smtpClient->newConnection(mailAccount.smtpServer, 25);
00094 }
00095
00096 void EmailHandler::setAccount(MailAccount account)
00097 {
00098 mailAccount = account;
00099 }
00100
00101 void EmailHandler::getMail()
00102 {
00103 popClient->setAccount(mailAccount.popUserName, mailAccount.popPasswd);
00104 if (mailAccount.synchronize) {
00105 popClient->setSynchronize(mailAccount.lastServerMailCount);
00106 } else {
00107 popClient->removeSynchronize();
00108 }
00109
00110 headers = FALSE;
00111
00112 popClient->newConnection(mailAccount.popServer, 110);
00113 }
00114
00115 void EmailHandler::getMailHeaders()
00116 {
00117 popClient->setAccount(mailAccount.popUserName, mailAccount.popPasswd);
00118 mailAccount.synchronize ? popClient->setSynchronize(mailAccount.lastServerMailCount): popClient->removeSynchronize();
00119
00120 headers = TRUE;
00121 popClient->headersOnly(headers, mailAccount.syncLimit);
00122 qDebug("Initiating connection");
00123 popClient->newConnection(mailAccount.popServer, 110);
00124 }
00125
00126 void EmailHandler::getMailByList(MailList *mailList)
00127 {
00128 if (mailList->count() == 0) {
00129 emit mailTransfered(0);
00130 return;
00131 }
00132
00133 headers = FALSE;
00134 popClient->headersOnly(FALSE, 0);
00135
00136 popClient->setAccount(mailAccount.popUserName,mailAccount.popPasswd);
00137 popClient->setSelectedMails(mailList);
00138 popClient->newConnection(mailAccount.popServer, 110);
00139 }
00140
00141 void EmailHandler::messageArrived(const QString &message, int id, uint size, bool complete)
00142 {
00143 Email mail;
00144
00145 mail.rawMail = message;
00146 mail.serverId = id;
00147 mail.size = size;
00148 mail.downloaded = complete;
00149
00150 emit mailArrived(mail, FALSE);
00151 }
00152
00153 bool EmailHandler::parse(const QString &in, const QString &lineShift, Email *mail)
00154 {
00155 QString temp, boundary;
00156 int pos;
00157 QString delimiter, header, body, mimeHeader, mimeBody;
00158 QString content, contentType, contentAttribute, id, encoding;
00159 QString fileName, storedName;
00160 int enclosureId = 0;
00161
00162 mail->rawMail = in;
00163 mail->received = TRUE;
00164 mail->files.setAutoDelete(TRUE);
00165
00166 temp = lineShift + "." + lineShift;
00167
00168 if (in.right(temp.length()) != temp) {
00169 mail->rawMail += temp;
00170 }
00171
00172
00173 delimiter = lineShift + lineShift;
00174 pos = in.find(delimiter, 0, FALSE);
00175 header = in.left(pos);
00176 body = in.right(in.length() - pos - delimiter.length());
00177 if ((body.at(body.length()-2) == '.') && (body.at(body.length()-3) == '\n'))
00178 body.truncate(body.length()-2);
00179
00180
00181 TextParser * lp = new TextParser(header, lineShift);
00182 #define p (*lp)
00183
00184 if ((pos = p.find("FROM",':', 0, TRUE)) != -1) {
00185 pos++;
00186 if (p.separatorAt(pos) == ' ') {
00187 mail->from = p.getString(&pos, '<', false);
00188 mail->from = mail->from.stripWhiteSpace();
00189 if ( (mail->from.length() > 2) && (mail->from[0] == '"') ) {
00190 mail->from = mail->from.left(mail->from.length() - 1);
00191 mail->from = mail->from.right(mail->from.length() - 1);
00192 }
00193 pos++;
00194 mail->fromMail = p.getString(&pos, '>', false);
00195 } else {
00196 if (p.separatorAt(pos) == '<')
00197 pos++;
00198
00199 mail->fromMail = p.getString(&pos, 'z', TRUE);
00200 if (mail->fromMail.at(mail->fromMail.length()-1) == '>')
00201 mail->fromMail.truncate(mail->fromMail.length() - 1);
00202 mail->from=mail->fromMail;
00203 }
00204 }
00205
00206 pos=0;
00207
00208
00209 while((pos = p.find("TO",':', pos+1, TRUE))!=-1)
00210 {
00211 QString rec;
00212
00213 if (p.separatorAt(pos-1)!='-')
00214 {
00215 pos++;
00216 mail->recipients.append(p.getString(&pos, '\r', TRUE));
00217 }
00218 }
00219
00220
00221
00222 if ((pos = p.find("CC",':', 0, TRUE)) != -1)
00223 {
00224 pos++;
00225 mail->carbonCopies.append (p.getString(&pos, 'z', TRUE) );
00226 }
00227
00228 if ((pos = p.find("SUBJECT",':', 0, TRUE)) != -1) {
00229 pos++;
00230 mail->subject = p.getString(&pos, 'z', TRUE);
00231 }
00232
00233 if ((pos = p.find("DATE",':', 0, TRUE)) != -1) {
00234 pos++;
00235 mail->date = p.getString(&pos, 'z', TRUE);
00236 }
00237
00238
00239
00240 if ((pos = p.find("MESSAGE",'-', 0, TRUE)) != -1) {
00241 pos++;
00242 if ( (p.wordAt(pos).upper() == "ID") &&
00243 (p.separatorAt(pos) == ':') ) {
00244
00245 id = p.getString(&pos, 'z', TRUE);
00246 mail->id = id;
00247 }
00248 }
00249
00250 pos = 0;
00251 while ( ((pos = p.find("MIME",'-', pos, TRUE)) != -1) ) {
00252 pos++;
00253 if ( (p.wordAt(pos).upper() == "VERSION") &&
00254 (p.separatorAt(pos) == ':') ) {
00255 pos++;
00256 if (p.getString(&pos, 'z', true) == "1.0") {
00257 mail->mimeType = 1;
00258 }
00259 }
00260 }
00261
00262 if (mail->mimeType == 1) {
00263 boundary = "";
00264 if ((pos = p.find("BOUNDARY", '=', 0, TRUE)) != -1) {
00265 pos++;
00266 boundary = p.getString(&pos, 'z', true);
00267 if (boundary[0] == '"') {
00268 boundary = boundary.left(boundary.length() - 1);
00269 boundary = boundary.right(boundary.length() - 1);
00270 }
00271 boundary = "--" + boundary;
00272 }
00273
00274 if (boundary == "") {
00275 mail->body = body;
00276 mail->bodyPlain = body;
00277 delete lp;
00278 return mail;
00279 }
00280
00281 while (body.length() > 0) {
00282 pos = body.find(boundary, 0, FALSE);
00283 pos = body.find(delimiter, pos, FALSE);
00284 mimeHeader = body.left(pos);
00285 mimeBody = body.right(body.length() - pos - delimiter.length());
00286 TextParser bp(mimeHeader, lineShift);
00287
00288 contentType = "";
00289 contentAttribute = "";
00290 fileName = "";
00291 if ((pos = bp.find("CONTENT",'-', 0, TRUE)) != -1) {
00292 pos++;
00293 if ( (bp.wordAt(pos).upper() == "TYPE") &&
00294 (bp.separatorAt(pos) == ':') ) {
00295 contentType = bp.nextWord().upper();
00296 if (bp.nextSeparator() == '/')
00297 contentAttribute = bp.nextWord().upper();
00298 content = contentType + "/" + contentAttribute;
00299 }
00300 if ((pos = bp.find("ENCODING",':', 0, TRUE)) != -1) {
00301 pos++;
00302 encoding = bp.getString(&pos, 'z', TRUE);
00303 }
00304
00305 if ( (pos = bp.find("FILENAME",'=', 0, TRUE)) != -1) {
00306 pos++;
00307 fileName = bp.getString(&pos, 'z', TRUE);
00308 fileName = fileName.right(fileName.length() - 1);
00309 fileName = fileName.left(fileName.length() - 1);
00310 }
00311
00312 }
00313 pos = mimeBody.find(boundary, 0, FALSE);
00314 if (pos == -1)
00315 pos = mimeBody.length();
00316 body = mimeBody.right(mimeBody.length() - pos);
00317 mimeBody = mimeBody.left(pos);
00318
00319 if (fileName != "") {
00320
00321 Enclosure e;
00322 e.id = enclosureId;
00323 e.originalName = fileName;
00324 e.contentType = contentType;
00325 e.contentAttribute = contentAttribute;
00326 e.encoding = encoding;
00327 e.body = mimeBody;
00328 e.saved = FALSE;
00329 mail->addEnclosure(&e);
00330 enclosureId++;
00331
00332 } else if (contentType == "TEXT") {
00333 if (contentAttribute == "PLAIN") {
00334 mail->body = mimeBody;
00335 mail->bodyPlain = mimeBody;
00336 }
00337 if (contentAttribute == "HTML") {
00338 mail->body = mimeBody;
00339 }
00340 }
00341 }
00342 } else {
00343 mail->bodyPlain = body;
00344 mail->body = body;
00345 }
00346 delete lp;
00347 return TRUE;
00348 }
00349
00350 bool EmailHandler::getEnclosure(Enclosure *ePtr)
00351 {
00352 QFile f(ePtr->path + ePtr->name);
00353 char src[4];
00354 char *destPtr;
00355 QByteArray buffer;
00356 uint bufCount, pos, decodedCount, size, x;
00357
00358 if (! f.open(IO_WriteOnly) ) {
00359 qWarning("could not save: " + ePtr->path + ePtr->name);
00360 return FALSE;
00361 }
00362
00363 if (ePtr->encoding.upper() == "BASE64") {
00364 size = (ePtr->body.length() * 3 / 4);
00365 buffer.resize(size);
00366 bufCount = 0;
00367 pos = 0;
00368 destPtr = buffer.data();
00369
00370 while (pos < ePtr->body.length()) {
00371 decodedCount = 4;
00372 x = 0;
00373 while ( (x < 4) && (pos < ePtr->body.length()) ) {
00374 src[x] = ePtr->body[pos].latin1();
00375 pos++;
00376 if (src[x] == '\r' || src[x] == '\n' || src[x] == ' ')
00377 x--;
00378 x++;
00379 }
00380 if (x > 1) {
00381 decodedCount = parse64base(src, destPtr);
00382 destPtr += decodedCount;
00383 bufCount += decodedCount;
00384 }
00385 }
00386
00387 buffer.resize(bufCount);
00388 f.writeBlock(buffer);
00389 } else {
00390 QTextStream t(&f);
00391 t << ePtr->body;
00392 }
00393 return TRUE;
00394 }
00395
00396 int EmailHandler::parse64base(char *src, char *bufOut) {
00397
00398 char c, z;
00399 char li[4];
00400 int processed;
00401
00402
00403 for (int x = 0; x < 4; x++) {
00404 c = src[x];
00405
00406 if ( (int) c >= 'A' && (int) c <= 'Z')
00407 li[x] = (int) c - (int) 'A';
00408 if ( (int) c >= 'a' && (int) c <= 'z')
00409 li[x] = (int) c - (int) 'a' + 26;
00410 if ( (int) c >= '0' && (int) c <= '9')
00411 li[x] = (int) c - (int) '0' + 52;
00412 if (c == '+')
00413 li[x] = 62;
00414 if (c == '/')
00415 li[x] = 63;
00416 }
00417
00418 processed = 1;
00419 bufOut[0] = (char) li[0] & (32+16+8+4+2+1);
00420 bufOut[0] <<= 2;
00421 z = li[1] >> 4;
00422 bufOut[0] = bufOut[0] | z;
00423
00424 if (src[2] != '=') {
00425 bufOut[1] = (char) li[1] & (8+4+2+1);
00426 bufOut[1] <<= 4;
00427 z = li[2] >> 2;
00428 bufOut[1] = bufOut[1] | z;
00429 processed++;
00430
00431 if (src[3] != '=') {
00432 bufOut[2] = (char) li[2] & (2+1);
00433 bufOut[2] <<= 6;
00434 z = li[3];
00435 bufOut[2] = bufOut[2] | z;
00436 processed++;
00437 }
00438 }
00439 return processed;
00440 }
00441
00442 int EmailHandler::encodeMime(Email *mail)
00443 {
00444
00445 QString fileName, fileType, contentType, newBody, boundary;
00446 Enclosure *ePtr;
00447 QString userName;
00448
00449 if ( ! mailAccount.name.isEmpty() ) {
00450 userName = "\"" + mailAccount.name + "\" <" + mailAccount.emailAddress + ">";
00451 } else {
00452 userName = "<" + mailAccount.emailAddress + ">";
00453 }
00454
00455
00456 newBody = "From: " + userName + "\r\nTo: ";
00457 for (QStringList::Iterator it = mail->recipients.begin(); it != mail->recipients.end(); ++it ) {
00458 newBody += *it + " ";
00459 }
00460
00461 newBody += "\r\nCC: ";
00462
00463 for (QStringList::Iterator it = mail->carbonCopies.begin(); it != mail->carbonCopies.end(); ++it ) {
00464 newBody += *it + " ";
00465 }
00466
00467 newBody += "\r\nSubject: " + mail->subject + "\r\n";
00468
00469 if (mail->files.count() == 0) {
00470 newBody += "\r\n" + mail->body;
00471 mail->rawMail = newBody;
00472 return 0;
00473 }
00474
00475
00476 boundary = "-----4345=next_bound=0495----";
00477
00478 newBody += "Mime-Version: 1.0\r\n";
00479 newBody += "Content-Type: multipart/mixed; boundary=\"" +
00480 boundary + "\"\r\n\r\n";
00481
00482 newBody += "This is a multipart message in Mime 1.0 format\r\n\r\n";
00483 newBody += "--" + boundary + "\r\nContent-Type: text/plain\r\n\r\n";
00484 newBody += mail->body;
00485
00486 for ( ePtr=mail->files.first(); ePtr != 0; ePtr=mail->files.next() ) {
00487 fileName = ePtr->originalName;
00488 fileType = ePtr->contentType;
00489 QFileInfo fi(fileName);
00490
00491
00492 contentType = "";
00493 if (fileType == "Picture") {
00494 contentType = "image/x-image";
00495 } else if (fileType == "Document") {
00496 contentType = "text/plain";
00497 } else if (fileType == "Sound") {
00498 contentType = "audio/x-wav";
00499 } else if (fileType == "Movie") {
00500 contentType = "video/mpeg";
00501 } else {
00502 contentType = "application/octet-stream";
00503 }
00504
00505 newBody += "\r\n\r\n--" + boundary + "\r\n";
00506 newBody += "Content-Type: " + contentType + "; name=\"" +
00507 fi.fileName() + "\"\r\n";
00508 newBody += "Content-Transfer-Encoding: base64\r\n";
00509 newBody += "Content-Disposition: inline; filename=\"" +
00510 fi.fileName() + "\"\r\n\r\n";
00511
00512 if (encodeFile(fileName, &newBody) == -1)
00513 return -1;
00514 }
00515
00516 newBody += "\r\n\r\n--" + boundary + "--";
00517 mail->rawMail = newBody;
00518
00519 return 0;
00520 }
00521
00522 int EmailHandler::encodeFile(const QString &fileName, QString *toBody)
00523 {
00524 char *fileData;
00525 char *dataPtr;
00526 QString temp;
00527 uint dataSize, count;
00528 QFile f(fileName);
00529
00530 if (! f.open(IO_ReadOnly) ) {
00531 qWarning("could not open file: " + fileName);
00532 return -1;
00533 }
00534 QTextStream s(&f);
00535 dataSize = f.size();
00536 fileData = (char *) malloc(dataSize + 3);
00537 s.readRawBytes(fileData, dataSize);
00538
00539 temp = "";
00540 dataPtr = fileData;
00541 count = 0;
00542 while (dataSize > 0) {
00543 if (dataSize < 3) {
00544 encode64base(dataPtr, &temp, dataSize);
00545 dataSize = 0;
00546 } else {
00547 encode64base(dataPtr, &temp, 3);
00548 dataSize -= 3;
00549 dataPtr += 3;
00550 count += 4;
00551 }
00552 if (count > 72) {
00553 count = 0;
00554 temp += "\r\n";
00555 }
00556 }
00557 toBody->append(temp);
00558
00559 delete(fileData);
00560 f.close();
00561 return 0;
00562 }
00563
00564 void EmailHandler::encode64base(char *src, QString *dest, int len)
00565 {
00566 QString temp;
00567 uchar c;
00568 uchar bufOut[4];
00569
00570 bufOut[0] = src[0];
00571 bufOut[0] >>= 2;
00572
00573 bufOut[1] = src[0];
00574 bufOut[1] = bufOut[1] & (1 + 2);
00575 bufOut[1] <<= 4;
00576 if (len > 1) {
00577 c = src[1];
00578 } else {
00579 c = 0;
00580 }
00581
00582 c = c & (16 + 32 + 64 + 128);
00583 c >>= 4;
00584 bufOut[1] = bufOut[1] | c;
00585
00586 bufOut[2] = src[1];
00587 bufOut[2] = bufOut[2] & (1 + 2 + 4 + 8);
00588 bufOut[2] <<= 2;
00589 if (len > 2) {
00590 c = src[2];
00591 } else {
00592 c = 0;
00593 }
00594 c >>= 6;
00595 bufOut[2] = bufOut[2] | c;
00596
00597 bufOut[3] = src[2];
00598 bufOut[3] = bufOut[3] & (1 + 2 + 4 + 8 + 16 + 32);
00599
00600 if (len == 1) {
00601 bufOut[2] = 64;
00602 bufOut[3] = 64;
00603 }
00604 if (len == 2) {
00605 bufOut[3] = 64;
00606 }
00607 for (int x = 0; x < 4; x++) {
00608 if (bufOut[x] <= 25)
00609 bufOut[x] += (uint) 'A';
00610 else if (bufOut[x] >= 26 && bufOut[x] <= 51)
00611 bufOut[x] += (uint) 'a' - 26;
00612 else if (bufOut[x] >= 52 && bufOut[x] <= 61)
00613 bufOut[x] += (uint) '0' - 52;
00614 else if (bufOut[x] == 62)
00615 bufOut[x] = '+';
00616 else if (bufOut[x] == 63)
00617 bufOut[x] = '/';
00618 else if (bufOut[x] == 64)
00619 bufOut[x] = '=';
00620
00621 dest->append(bufOut[x]);
00622 }
00623 }
00624
00625 void EmailHandler::cancel()
00626 {
00627 popClient->errorHandling(ErrCancel);
00628 smtpClient->errorHandling(ErrCancel);
00629 }
00630