00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kalarm.h"
00022
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <time.h>
00026 #include <sys/stat.h>
00027 #include <sys/time.h>
00028 #include <pwd.h>
00029
00030 #include <qfile.h>
00031 #include <qregexp.h>
00032
00033 #include <kstandarddirs.h>
00034 #include <dcopclient.h>
00035 #include <dcopref.h>
00036 #include <kmessagebox.h>
00037 #include <kprocess.h>
00038 #include <klocale.h>
00039 #include <kaboutdata.h>
00040 #include <kfileitem.h>
00041 #include <kio/netaccess.h>
00042 #include <ktempfile.h>
00043 #include <kemailsettings.h>
00044 #include <kdebug.h>
00045
00046 #include <libkpimidentities/identitymanager.h>
00047 #include <libkpimidentities/identity.h>
00048 #include <libkcal/person.h>
00049
00050 #include <kmime_header_parsing.h>
00051
00052 #include "alarmevent.h"
00053 #include "functions.h"
00054 #include "kalarmapp.h"
00055 #include "mainwindow.h"
00056 #include "preferences.h"
00057 #include "kamail.h"
00058
00059
00060 namespace HeaderParsing
00061 {
00062 bool parseAddress( const char* & scursor, const char * const send,
00063 KMime::Types::Address & result, bool isCRLF=false );
00064 bool parseAddressList( const char* & scursor, const char * const send,
00065 QValueList<KMime::Types::Address> & result, bool isCRLF=false );
00066 }
00067
00068 namespace
00069 {
00070 QString getHostName();
00071 }
00072
00073 struct KAMailData
00074 {
00075 KAMailData(const KAEvent& e, const QString& fr, const QString& bc, bool allownotify)
00076 : event(e), from(fr), bcc(bc), allowNotify(allownotify) { }
00077 const KAEvent& event;
00078 QString from;
00079 QString bcc;
00080 bool allowNotify;
00081 };
00082
00083
00084 QString KAMail::i18n_NeedFromEmailAddress()
00085 { return i18n("A 'From' email address must be configured in order to execute email alarms."); }
00086
00087 QString KAMail::i18n_sent_mail()
00088 { return i18n("KMail folder name: this should be translated the same as in kmail", "sent-mail"); }
00089
00090 KPIM::IdentityManager* KAMail::mIdentityManager = 0;
00091 KPIM::IdentityManager* KAMail::identityManager()
00092 {
00093 if (!mIdentityManager)
00094 mIdentityManager = new KPIM::IdentityManager(true);
00095 return mIdentityManager;
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 bool KAMail::send(const KAEvent& event, QStringList& errmsgs, bool allowNotify)
00105 {
00106 QString err;
00107 QString from;
00108 if (event.emailFromKMail().isEmpty())
00109 from = Preferences::emailAddress();
00110 else
00111 {
00112 from = mIdentityManager->identityForName(event.emailFromKMail()).fullEmailAddr();
00113 if (from.isEmpty())
00114 {
00115 errmsgs = errors(i18n("Invalid 'From' email address.\nKMail identity '%1' not found.").arg(event.emailFromKMail()));
00116 return false;
00117 }
00118 }
00119 if (from.isEmpty())
00120 {
00121 switch (Preferences::emailFrom())
00122 {
00123 case Preferences::MAIL_FROM_KMAIL:
00124 errmsgs = errors(i18n("No 'From' email address is configured (no default KMail identity found)\nPlease set it in KMail or in the KAlarm Preferences dialog."));
00125 break;
00126 case Preferences::MAIL_FROM_CONTROL_CENTRE:
00127 errmsgs = errors(i18n("No 'From' email address is configured.\nPlease set it in the KDE Control Center or in the KAlarm Preferences dialog."));
00128 break;
00129 case Preferences::MAIL_FROM_ADDR:
00130 default:
00131 errmsgs = errors(i18n("No 'From' email address is configured.\nPlease set it in the KAlarm Preferences dialog."));
00132 break;
00133 }
00134 return false;
00135 }
00136 KAMailData data(event, from,
00137 (event.emailBcc() ? Preferences::emailBccAddress() : QString::null),
00138 allowNotify);
00139 kdDebug(5950) << "KAlarmApp::sendEmail(): To: " << event.emailAddresses(", ")
00140 << "\nSubject: " << event.emailSubject() << endl;
00141
00142 if (Preferences::emailClient() == Preferences::SENDMAIL)
00143 {
00144
00145 QString textComplete;
00146 QString command = KStandardDirs::findExe(QString::fromLatin1("sendmail"),
00147 QString::fromLatin1("/sbin:/usr/sbin:/usr/lib"));
00148 if (!command.isNull())
00149 {
00150 command += QString::fromLatin1(" -oi -t ");
00151 textComplete = initHeaders(data, false);
00152 }
00153 else
00154 {
00155 command = KStandardDirs::findExe(QString::fromLatin1("mail"));
00156 if (command.isNull())
00157 {
00158 errmsgs = errors(i18n("%1 not found").arg(QString::fromLatin1("sendmail")));
00159 return false;
00160 }
00161
00162 command += QString::fromLatin1(" -s ");
00163 command += KShellProcess::quote(event.emailSubject());
00164
00165 if (!data.bcc.isEmpty())
00166 {
00167 command += QString::fromLatin1(" -b ");
00168 command += KShellProcess::quote(data.bcc);
00169 }
00170
00171 command += ' ';
00172 command += event.emailAddresses(" ");
00173 }
00174
00175
00176
00177 err = appendBodyAttachments(textComplete, event);
00178 if (!err.isNull())
00179 {
00180 errmsgs = errors(err);
00181 return false;
00182 }
00183
00184
00185 FILE* fd = popen(command.local8Bit(), "w");
00186 if (!fd)
00187 {
00188 kdError(5950) << "KAMail::send(): Unable to open a pipe to " << command << endl;
00189 errmsgs = errors();
00190 return false;
00191 }
00192 fwrite(textComplete.local8Bit(), textComplete.length(), 1, fd);
00193 pclose(fd);
00194
00195 if (Preferences::emailCopyToKMail())
00196 {
00197
00198 err = addToKMailFolder(data, "sent-mail", true);
00199 if (!err.isNull())
00200 errmsgs = errors(err, false);
00201 }
00202
00203 if (allowNotify)
00204 notifyQueued(event);
00205 }
00206 else
00207 {
00208
00209 err = sendKMail(data);
00210 if (!err.isNull())
00211 {
00212 errmsgs = errors(err);
00213 return false;
00214 }
00215 }
00216 return true;
00217 }
00218
00219
00220
00221
00222
00223
00224 QString KAMail::sendKMail(const KAMailData& data)
00225 {
00226 QString err = KAlarm::runKMail(true);
00227 if (!err.isNull())
00228 return err;
00229
00230
00231 bool useSend = false;
00232 QCString sendFunction = "sendMessage(QString,QString,QString,QString,QString,QString,KURL::List)";
00233 QCStringList funcs = kapp->dcopClient()->remoteFunctions("kmail", "MailTransportServiceIface");
00234 for (QCStringList::Iterator it=funcs.begin(); it != funcs.end() && !useSend; ++it)
00235 {
00236 QCString func = DCOPClient::normalizeFunctionSignature(*it);
00237 if (func.left(5) == "bool ")
00238 {
00239 func = func.mid(5);
00240 func.replace(QRegExp(" [0-9A-Za-z_:]+"), "");
00241 useSend = (func == sendFunction);
00242 }
00243 }
00244
00245 QByteArray callData;
00246 QDataStream arg(callData, IO_WriteOnly);
00247 kdDebug(5950) << "KAMail::sendKMail(): using " << (useSend ? "sendMessage()" : "dcopAddMessage()") << endl;
00248 if (useSend)
00249 {
00250
00251
00252 arg << data.from;
00253 arg << data.event.emailAddresses(", ");
00254 arg << "";
00255 arg << data.bcc;
00256 arg << data.event.emailSubject();
00257 arg << data.event.message();
00258 arg << KURL::List(data.event.emailAttachments());
00259 if (!callKMail(callData, "MailTransportServiceIface", sendFunction, "bool"))
00260 return i18n("Error calling KMail");
00261 }
00262 else
00263 {
00264
00265
00266 err = addToKMailFolder(data, "outbox", false);
00267 if (!err.isNull())
00268 return err;
00269 }
00270 if (data.allowNotify)
00271 notifyQueued(data.event);
00272 return QString::null;
00273 }
00274
00275
00276
00277
00278
00279
00280 QString KAMail::addToKMailFolder(const KAMailData& data, const char* folder, bool checkKmailRunning)
00281 {
00282 QString err;
00283 if (checkKmailRunning)
00284 err = KAlarm::runKMail(true);
00285 if (err.isNull())
00286 {
00287 QString message = initHeaders(data, true);
00288 err = appendBodyAttachments(message, data.event);
00289 if (!err.isNull())
00290 return err;
00291
00292
00293 KTempFile tmpFile;
00294 tmpFile.setAutoDelete(true);
00295 QTextStream* stream = tmpFile.textStream();
00296 if (!stream)
00297 {
00298 kdError(5950) << "KAMail::addToKMailFolder(" << folder << "): Unable to open a temporary mail file" << endl;
00299 return QString("");
00300 }
00301 *stream << message;
00302 tmpFile.close();
00303 if (tmpFile.status())
00304 {
00305 kdError(5950) << "KAMail::addToKMailFolder(" << folder << "): Error " << tmpFile.status() << " writing to temporary mail file" << endl;
00306 return QString("");
00307 }
00308
00309
00310 QByteArray callData;
00311 QDataStream arg(callData, IO_WriteOnly);
00312 arg << QString::fromLatin1(folder) << tmpFile.name();
00313 if (callKMail(callData, "KMailIface", "dcopAddMessage(QString,QString)", "int"))
00314 return QString::null;
00315 err = i18n("Error calling KMail");
00316 }
00317 kdError(5950) << "KAMail::addToKMailFolder(" << folder << "): " << err << endl;
00318 return err;
00319 }
00320
00321
00322
00323
00324 bool KAMail::callKMail(const QByteArray& callData, const QCString& iface, const QCString& function, const QCString& funcType)
00325 {
00326 QCString replyType;
00327 QByteArray replyData;
00328 if (!kapp->dcopClient()->call("kmail", iface, function, callData, replyType, replyData)
00329 || replyType != funcType)
00330 {
00331 QCString funcname = function;
00332 funcname.replace(QRegExp("(.+$"), "()");
00333 kdError(5950) << "KAMail::callKMail(): kmail " << funcname << " call failed\n";;
00334 return false;
00335 }
00336 QDataStream replyStream(replyData, IO_ReadOnly);
00337 QCString funcname = function;
00338 funcname.replace(QRegExp("(.+$"), "()");
00339 if (replyType == "int")
00340 {
00341 int result;
00342 replyStream >> result;
00343 if (result <= 0)
00344 {
00345 kdError(5950) << "KAMail::callKMail(): kmail " << funcname << " call returned error code = " << result << endl;
00346 return false;
00347 }
00348 }
00349 else if (replyType == "bool")
00350 {
00351 bool result;
00352 replyStream >> result;
00353 if (!result)
00354 {
00355 kdError(5950) << "KAMail::callKMail(): kmail " << funcname << " call returned error\n";
00356 return false;
00357 }
00358 }
00359 return true;
00360 }
00361
00362
00363
00364
00365 QString KAMail::initHeaders(const KAMailData& data, bool dateId)
00366 {
00367 QString message;
00368 if (dateId)
00369 {
00370 struct timeval tod;
00371 gettimeofday(&tod, 0);
00372 time_t timenow = tod.tv_sec;
00373 char buff[64];
00374 strftime(buff, sizeof(buff), "Date: %a, %d %b %Y %H:%M:%S %z", localtime(&timenow));
00375 message = QString::fromLatin1(buff);
00376 message += QString::fromLatin1("\nMessage-Id: <%1.%2.%3>\n").arg(timenow).arg(tod.tv_usec).arg(data.from);
00377 }
00378 message += QString::fromLatin1("From: ") + data.from;
00379 message += QString::fromLatin1("\nTo: ") + data.event.emailAddresses(", ");
00380 if (!data.bcc.isEmpty())
00381 message += QString::fromLatin1("\nBcc: ") + data.bcc;
00382 message += QString::fromLatin1("\nSubject: ") + data.event.emailSubject();
00383 message += QString::fromLatin1("\nX-Mailer: %1" KALARM_VERSION).arg(kapp->aboutData()->programName());
00384 return message;
00385 }
00386
00387
00388
00389
00390
00391
00392 QString KAMail::appendBodyAttachments(QString& message, const KAEvent& event)
00393 {
00394 static const char* textMimeTypes[] = {
00395 "application/x-sh", "application/x-csh", "application/x-shellscript",
00396 "application/x-nawk", "application/x-gawk", "application/x-awk",
00397 "application/x-perl", "application/x-desktop",
00398 0
00399 };
00400 QStringList attachments = event.emailAttachments();
00401 if (!attachments.count())
00402 {
00403
00404 message += "\n\n";
00405 message += event.message();
00406 }
00407 else
00408 {
00409
00410
00411 time_t timenow;
00412 time(&timenow);
00413 QCString boundary;
00414 boundary.sprintf("------------_%lu_-%lx=", 2*timenow, timenow);
00415 message += QString::fromLatin1("\nMIME-Version: 1.0");
00416 message += QString::fromLatin1("\nContent-Type: multipart/mixed;\n boundary=\"%1\"\n").arg(boundary);
00417
00418 if (!event.message().isEmpty())
00419 {
00420
00421 message += QString::fromLatin1("\n--%1\nContent-Type: text/plain\nContent-Transfer-Encoding: 8bit\n\n").arg(boundary);
00422 message += event.message();
00423 }
00424
00425
00426 QString attachError = i18n("Error attaching file:\n%1");
00427 for (QStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at)
00428 {
00429 QString attachment = (*at).local8Bit();
00430 KURL url(attachment);
00431 url.cleanPath();
00432 KIO::UDSEntry uds;
00433 if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow())) {
00434 kdError(5950) << "KAMail::appendBodyAttachments(): not found: " << attachment << endl;
00435 return i18n("Attachment not found:\n%1").arg(attachment);
00436 }
00437 KFileItem fi(uds, url);
00438 if (fi.isDir() || !fi.isReadable()) {
00439 kdError(5950) << "KAMail::appendBodyAttachments(): not file/not readable: " << attachment << endl;
00440 return attachError.arg(attachment);
00441 }
00442
00443
00444 QString mimeType = fi.mimetype();
00445 bool text = mimeType.startsWith("text/");
00446 if (!text)
00447 {
00448 for (int i = 0; !text && textMimeTypes[i]; ++i)
00449 text = (mimeType == textMimeTypes[i]);
00450 }
00451
00452 message += QString::fromLatin1("\n--%1").arg(boundary);
00453 message += QString::fromLatin1("\nContent-Type: %2; name=\"%3\"").arg(mimeType).arg(fi.text());
00454 message += QString::fromLatin1("\nContent-Transfer-Encoding: %1").arg(QString::fromLatin1(text ? "8bit" : "BASE64"));
00455 message += QString::fromLatin1("\nContent-Disposition: attachment; filename=\"%4\"\n\n").arg(fi.text());
00456
00457
00458 QString tmpFile;
00459 if (!KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow())) {
00460 kdError(5950) << "KAMail::appendBodyAttachments(): load failure: " << attachment << endl;
00461 return attachError.arg(attachment);
00462 }
00463 QFile file(tmpFile);
00464 if (!file.open(IO_ReadOnly) ) {
00465 kdDebug(5950) << "KAMail::appendBodyAttachments() tmp load error: " << attachment << endl;
00466 return attachError.arg(attachment);
00467 }
00468 QIODevice::Offset size = file.size();
00469 char* contents = new char [size + 1];
00470 Q_LONG bytes = file.readBlock(contents, size);
00471 file.close();
00472 contents[size] = 0;
00473 bool atterror = false;
00474 if (bytes == -1 || (QIODevice::Offset)bytes < size) {
00475 kdDebug(5950) << "KAMail::appendBodyAttachments() read error: " << attachment << endl;
00476 atterror = true;
00477 }
00478 else if (text)
00479 {
00480
00481 message += contents;
00482 }
00483 else
00484 {
00485
00486 QIODevice::Offset base64Size;
00487 char* base64 = base64Encode(contents, size, base64Size);
00488 if (base64Size == (QIODevice::Offset)-1) {
00489 kdDebug(5950) << "KAMail::appendBodyAttachments() base64 buffer overflow: " << attachment << endl;
00490 atterror = true;
00491 }
00492 else
00493 message += QString::fromLatin1(base64, base64Size);
00494 delete[] base64;
00495 }
00496 delete[] contents;
00497 if (atterror)
00498 return attachError.arg(attachment);
00499 }
00500 message += QString::fromLatin1("\n--%1--\n.\n").arg(boundary);
00501 }
00502 return QString::null;
00503 }
00504
00505
00506
00507
00508
00509 void KAMail::notifyQueued(const KAEvent& event)
00510 {
00511 KMime::Types::Address addr;
00512 QString localhost = QString::fromLatin1("localhost");
00513 QString hostname = getHostName();
00514 const EmailAddressList& addresses = event.emailAddresses();
00515 for (QValueList<KCal::Person>::ConstIterator it = addresses.begin(); it != addresses.end(); ++it)
00516 {
00517 QCString email = (*it).email().local8Bit();
00518 const char* em = email;
00519 if (!email.isEmpty()
00520 && HeaderParsing::parseAddress(em, em + email.length(), addr))
00521 {
00522 QString domain = addr.mailboxList.first().addrSpec.domain;
00523 if (!domain.isEmpty() && domain != localhost && domain != hostname)
00524 {
00525 QString text = (Preferences::emailClient() == Preferences::KMAIL)
00526 ? i18n("An email has been queued to be sent by KMail")
00527 : i18n("An email has been queued to be sent");
00528 KMessageBox::information(0, text, QString::null, Preferences::EMAIL_QUEUED_NOTIFY);
00529 return;
00530 }
00531 }
00532 }
00533 }
00534
00535
00536
00537
00538 bool KAMail::identitiesExist()
00539 {
00540 identityManager();
00541 return mIdentityManager->begin() != mIdentityManager->end();
00542 }
00543
00544
00545
00546
00547 QString KAMail::controlCentreAddress()
00548 {
00549 KEMailSettings e;
00550 return e.getSetting(KEMailSettings::EmailAddress);
00551 }
00552
00553
00554
00555
00556
00557
00558 QString KAMail::convertAddresses(const QString& items, EmailAddressList& list)
00559 {
00560 list.clear();
00561 QCString addrs = items.local8Bit();
00562 const char* ad = static_cast<const char*>(addrs);
00563
00564
00565 QValueList<KMime::Types::Address> maybeAddressList;
00566 if (!HeaderParsing::parseAddressList(ad, ad + addrs.length(), maybeAddressList))
00567 return QString::fromLocal8Bit(ad);
00568
00569
00570 for (QValueList<KMime::Types::Address>::ConstIterator it = maybeAddressList.begin();
00571 it != maybeAddressList.end(); ++it)
00572 {
00573 QString bad = convertAddress(*it, list);
00574 if (!bad.isEmpty())
00575 return bad;
00576 }
00577 return QString::null;
00578 }
00579
00580 #if 0
00581
00582
00583
00584
00585
00586 QString KAMail::convertAddress(const QString& item, EmailAddressList& list)
00587 {
00588 QCString addr = item.local8Bit();
00589 const char* ad = static_cast<const char*>(addr);
00590 KMime::Types::Address maybeAddress;
00591 if (!HeaderParsing::parseAddress(ad, ad + addr.length(), maybeAddress))
00592 return item;
00593 return convertAddress(maybeAddress, list);
00594 }
00595 #endif
00596
00597
00598
00599
00600
00601 QString KAMail::convertAddress(KMime::Types::Address addr, EmailAddressList& list)
00602 {
00603 if (!addr.displayName.isEmpty())
00604 {
00605 kdDebug(5950) << "mailbox groups not allowed! Name: \"" << addr.displayName << "\"" << endl;
00606 return addr.displayName;
00607 }
00608 const QValueList<KMime::Types::Mailbox>& mblist = addr.mailboxList;
00609 for (QValueList<KMime::Types::Mailbox>::ConstIterator mb = mblist.begin();
00610 mb != mblist.end(); ++mb)
00611 {
00612 QString addrPart = (*mb).addrSpec.localPart;
00613 if (!(*mb).addrSpec.domain.isEmpty())
00614 {
00615 addrPart += QChar('@');
00616 addrPart += (*mb).addrSpec.domain;
00617 }
00618 list += KCal::Person((*mb).displayName, addrPart);
00619 }
00620 return QString::null;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 int KAMail::checkAddress(QString& address)
00654 {
00655 address = address.stripWhiteSpace();
00656
00657 if (address.find(',') >= 0 || address.find(';') >= 0)
00658 return -1;
00659 int n = address.length();
00660 if (!n)
00661 return 0;
00662 int start = 0;
00663 int end = n - 1;
00664 if (address[end] == '>')
00665 {
00666
00667 if ((start = address.find('<')) < 0)
00668 return -1;
00669 ++start;
00670 --end;
00671 }
00672 int i = address.find('@', start);
00673 if (i >= 0)
00674 {
00675 if (i == start || i == end)
00676
00677 return -1;
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 return 1;
00695 }
00696
00697
00698
00699
00700
00701
00702 QString KAMail::convertAttachments(const QString& items, QStringList& list)
00703 {
00704 KURL url;
00705 list.clear();
00706 int length = items.length();
00707 for (int next = 0; next < length; )
00708 {
00709
00710 int i = items.find(',', next);
00711 if (i < 0)
00712 i = items.length();
00713 int sc = items.find(';', next);
00714 if (sc < 0)
00715 sc = items.length();
00716 if (sc < i)
00717 i = sc;
00718 QString item = items.mid(next, i - next).stripWhiteSpace();
00719 switch (checkAttachment(item))
00720 {
00721 case 1: list += item; break;
00722 case 0: break;
00723 case -1:
00724 default: return item;
00725 }
00726 next = i + 1;
00727 }
00728 return QString::null;
00729 }
00730
00731 #if 0
00732
00733
00734
00735
00736
00737 QString KAMail::convertAttachments(const QString& items, KURL::List& list)
00738 {
00739 KURL url;
00740 list.clear();
00741 QCString addrs = items.local8Bit();
00742 int length = items.length();
00743 for (int next = 0; next < length; )
00744 {
00745
00746 int i = items.find(',', next);
00747 if (i < 0)
00748 i = items.length();
00749 int sc = items.find(';', next);
00750 if (sc < 0)
00751 sc = items.length();
00752 if (sc < i)
00753 i = sc;
00754 QString item = items.mid(next, i - next);
00755 switch (checkAttachment(item, &url))
00756 {
00757 case 1: list += url; break;
00758 case 0: break;
00759 case -1:
00760 default: return item;
00761 }
00762 next = i + 1;
00763 }
00764 return QString::null;
00765 }
00766 #endif
00767
00768
00769
00770
00771
00772
00773
00774
00775 int KAMail::checkAttachment(QString& attachment, KURL* url)
00776 {
00777 attachment = attachment.stripWhiteSpace();
00778 if (attachment.isEmpty())
00779 {
00780 if (url)
00781 *url = KURL();
00782 return 0;
00783 }
00784
00785 KURL u = KURL::fromPathOrURL(attachment);
00786 u.cleanPath();
00787 if (url)
00788 *url = u;
00789 return checkAttachment(u) ? 1 : -1;
00790 }
00791
00792
00793
00794
00795 bool KAMail::checkAttachment(const KURL& url)
00796 {
00797 KIO::UDSEntry uds;
00798 if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
00799 return false;
00800 KFileItem fi(uds, url);
00801 if (fi.isDir() || !fi.isReadable())
00802 return false;
00803 return true;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 char* KAMail::base64Encode(const char* in, QIODevice::Offset size, QIODevice::Offset& outSize)
00814 {
00815 const int MAX_LINELEN = 72;
00816 static unsigned char dtable[65] =
00817 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00818 "abcdefghijklmnopqrstuvwxyz"
00819 "0123456789+/";
00820
00821 char* out = new char [2*size + 5];
00822 outSize = (QIODevice::Offset)-1;
00823 QIODevice::Offset outIndex = 0;
00824 int lineLength = 0;
00825 for (QIODevice::Offset inIndex = 0; inIndex < size; )
00826 {
00827 unsigned char igroup[3];
00828 int n;
00829 for (n = 0; n < 3; ++n)
00830 {
00831 if (inIndex < size)
00832 igroup[n] = (unsigned char)in[inIndex++];
00833 else
00834 {
00835 igroup[n] = igroup[2] = 0;
00836 break;
00837 }
00838 }
00839
00840 if (n > 0)
00841 {
00842 unsigned char ogroup[4];
00843 ogroup[0] = dtable[igroup[0] >> 2];
00844 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
00845 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
00846 ogroup[3] = dtable[igroup[2] & 0x3F];
00847
00848 if (n < 3)
00849 {
00850 ogroup[3] = '=';
00851 if (n < 2)
00852 ogroup[2] = '=';
00853 }
00854 if (outIndex >= size*2)
00855 {
00856 delete[] out;
00857 return 0;
00858 }
00859 for (int i = 0; i < 4; ++i)
00860 {
00861 if (lineLength >= MAX_LINELEN)
00862 {
00863 out[outIndex++] = '\r';
00864 out[outIndex++] = '\n';
00865 lineLength = 0;
00866 }
00867 out[outIndex++] = ogroup[i];
00868 ++lineLength;
00869 }
00870 }
00871 }
00872
00873 if (outIndex + 2 < size*2)
00874 {
00875 out[outIndex++] = '\r';
00876 out[outIndex++] = '\n';
00877 }
00878 outSize = outIndex;
00879 return out;
00880 }
00881
00882
00883
00884
00885 QStringList KAMail::errors(const QString& err, bool sendfail)
00886 {
00887 QString error1 = sendfail ? i18n("Failed to send email")
00888 : i18n("Error copying sent email to KMail %1 folder").arg(i18n_sent_mail());
00889 if (err.isEmpty())
00890 return QStringList(error1);
00891 QStringList errs(QString::fromLatin1("%1:").arg(error1));
00892 errs += err;
00893 return errs;
00894 }
00895
00896
00897
00898
00899 QString KAMail::getMailBody(Q_UINT32 serialNumber)
00900 {
00901
00902 QCString replyType;
00903 QByteArray replyData;
00904 QByteArray data;
00905 QDataStream arg(data, IO_WriteOnly);
00906 arg << serialNumber;
00907 arg << (int)0;
00908 QString body;
00909 if (kapp->dcopClient()->call("kmail", "KMailIface", "getDecodedBodyPart(Q_UINT32,int)", data, replyType, replyData)
00910 && replyType == "QString")
00911 {
00912 QDataStream reply_stream(replyData, IO_ReadOnly);
00913 reply_stream >> body;
00914 }
00915 else
00916 kdDebug(5950) << "KAMail::getMailBody(): kmail getDecodedBodyPart() call failed\n";
00917 return body;
00918 }
00919
00920 namespace
00921 {
00922
00923
00924
00925 QString getHostName()
00926 {
00927 char hname[256];
00928 if (gethostname(hname, sizeof(hname)))
00929 return QString::null;
00930 return QString::fromLocal8Bit(hname);
00931 }
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941 namespace HeaderParsing
00942 {
00943
00944 using namespace KMime;
00945 using namespace KMime::Types;
00946 using namespace KMime::HeaderParsing;
00947
00948
00949
00950
00951
00952 bool parseUserName( const char* & scursor, const char * const send,
00953 QString & result, bool isCRLF ) {
00954
00955 QString maybeLocalPart;
00956 QString tmp;
00957
00958 if ( scursor != send ) {
00959
00960 eatCFWS( scursor, send, isCRLF );
00961
00962 char ch = *scursor++;
00963 switch ( ch ) {
00964 case '.':
00965 case '@':
00966 case '"':
00967 return false;
00968
00969 default:
00970 scursor--;
00971 tmp = QString::null;
00972 if ( parseAtom( scursor, send, result, false ) ) {
00973 if (getpwnam(result.local8Bit()))
00974 return true;
00975 }
00976 return false;
00977 }
00978 }
00979 return false;
00980 }
00981
00982
00983
00984
00985
00986
00987 bool parseAddress( const char* & scursor, const char * const send,
00988 Address & result, bool isCRLF ) {
00989
00990
00991 eatCFWS( scursor, send, isCRLF );
00992 if ( scursor == send ) return false;
00993
00994
00995 Mailbox maybeMailbox;
00996 const char * oldscursor = scursor;
00997 if ( parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
00998
00999 result.displayName = QString::null;
01000 result.mailboxList.append( maybeMailbox );
01001 return true;
01002 }
01003 scursor = oldscursor;
01004
01005
01006
01007 QString maybeUserName;
01008 if ( parseUserName( scursor, send, maybeUserName, isCRLF ) ) {
01009
01010 maybeMailbox.displayName = QString::null;
01011 maybeMailbox.addrSpec.localPart = maybeUserName;
01012 maybeMailbox.addrSpec.domain = QString::null;
01013 result.displayName = QString::null;
01014 result.mailboxList.append( maybeMailbox );
01015 return true;
01016 }
01017 scursor = oldscursor;
01018
01019 Address maybeAddress;
01020
01021
01022 if ( !parseGroup( scursor, send, maybeAddress, isCRLF ) )
01023 {
01024 scursor = oldscursor;
01025 return false;
01026 }
01027
01028 result = maybeAddress;
01029 return true;
01030 }
01031
01032
01033
01034
01035
01036 bool parseAddressList( const char* & scursor, const char * const send,
01037 QValueList<Address> & result, bool isCRLF ) {
01038 while ( scursor != send ) {
01039 eatCFWS( scursor, send, isCRLF );
01040
01041 if ( scursor == send ) return true;
01042
01043 if ( *scursor == ',' || *scursor == ';' ) { scursor++; continue; }
01044
01045
01046 Address maybeAddress;
01047 if ( !parseAddress( scursor, send, maybeAddress, isCRLF ) ) return false;
01048 result.append( maybeAddress );
01049
01050 eatCFWS( scursor, send, isCRLF );
01051
01052 if ( scursor == send ) return true;
01053
01054 if ( *scursor == ',' || *scursor == ';' ) scursor++;
01055 }
01056 return true;
01057 }
01058
01059 }