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-shellscript", "application/x-nawk", "application/x-gawk", "application/x-awk",
00396 "application/x-perl", "application/x-python", "application/x-desktop",
00397 0
00398 };
00399 QStringList attachments = event.emailAttachments();
00400 if (!attachments.count())
00401 {
00402
00403 message += "\n\n";
00404 message += event.message();
00405 }
00406 else
00407 {
00408
00409
00410 time_t timenow;
00411 time(&timenow);
00412 QCString boundary;
00413 boundary.sprintf("------------_%lu_-%lx=", 2*timenow, timenow);
00414 message += QString::fromLatin1("\nMIME-Version: 1.0");
00415 message += QString::fromLatin1("\nContent-Type: multipart/mixed;\n boundary=\"%1\"\n").arg(boundary);
00416
00417 if (!event.message().isEmpty())
00418 {
00419
00420 message += QString::fromLatin1("\n--%1\nContent-Type: text/plain\nContent-Transfer-Encoding: 8bit\n\n").arg(boundary);
00421 message += event.message();
00422 }
00423
00424
00425 QString attachError = i18n("Error attaching file:\n%1");
00426 for (QStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at)
00427 {
00428 QString attachment = (*at).local8Bit();
00429 KURL url(attachment);
00430 url.cleanPath();
00431 KIO::UDSEntry uds;
00432 if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow())) {
00433 kdError(5950) << "KAMail::appendBodyAttachments(): not found: " << attachment << endl;
00434 return i18n("Attachment not found:\n%1").arg(attachment);
00435 }
00436 KFileItem fi(uds, url);
00437 if (fi.isDir() || !fi.isReadable()) {
00438 kdError(5950) << "KAMail::appendBodyAttachments(): not file/not readable: " << attachment << endl;
00439 return attachError.arg(attachment);
00440 }
00441
00442
00443 QString mimeType = fi.mimetype();
00444 bool text = mimeType.startsWith("text/");
00445 if (!text)
00446 {
00447 for (int i = 0; !text && textMimeTypes[i]; ++i)
00448 text = (mimeType == textMimeTypes[i]);
00449 }
00450
00451 message += QString::fromLatin1("\n--%1").arg(boundary);
00452 message += QString::fromLatin1("\nContent-Type: %2; name=\"%3\"").arg(mimeType).arg(fi.text());
00453 message += QString::fromLatin1("\nContent-Transfer-Encoding: %1").arg(QString::fromLatin1(text ? "8bit" : "BASE64"));
00454 message += QString::fromLatin1("\nContent-Disposition: attachment; filename=\"%4\"\n\n").arg(fi.text());
00455
00456
00457 QString tmpFile;
00458 if (!KIO::NetAccess::download(url, tmpFile, MainWindow::mainMainWindow())) {
00459 kdError(5950) << "KAMail::appendBodyAttachments(): load failure: " << attachment << endl;
00460 return attachError.arg(attachment);
00461 }
00462 QFile file(tmpFile);
00463 if (!file.open(IO_ReadOnly) ) {
00464 kdDebug(5950) << "KAMail::appendBodyAttachments() tmp load error: " << attachment << endl;
00465 return attachError.arg(attachment);
00466 }
00467 QIODevice::Offset size = file.size();
00468 char* contents = new char [size + 1];
00469 Q_LONG bytes = file.readBlock(contents, size);
00470 file.close();
00471 contents[size] = 0;
00472 bool atterror = false;
00473 if (bytes == -1 || (QIODevice::Offset)bytes < size) {
00474 kdDebug(5950) << "KAMail::appendBodyAttachments() read error: " << attachment << endl;
00475 atterror = true;
00476 }
00477 else if (text)
00478 {
00479
00480 message += contents;
00481 }
00482 else
00483 {
00484
00485 QIODevice::Offset base64Size;
00486 char* base64 = base64Encode(contents, size, base64Size);
00487 if (base64Size == (QIODevice::Offset)-1) {
00488 kdDebug(5950) << "KAMail::appendBodyAttachments() base64 buffer overflow: " << attachment << endl;
00489 atterror = true;
00490 }
00491 else
00492 message += QString::fromLatin1(base64, base64Size);
00493 delete[] base64;
00494 }
00495 delete[] contents;
00496 if (atterror)
00497 return attachError.arg(attachment);
00498 }
00499 message += QString::fromLatin1("\n--%1--\n.\n").arg(boundary);
00500 }
00501 return QString::null;
00502 }
00503
00504
00505
00506
00507
00508 void KAMail::notifyQueued(const KAEvent& event)
00509 {
00510 KMime::Types::Address addr;
00511 QString localhost = QString::fromLatin1("localhost");
00512 QString hostname = getHostName();
00513 const EmailAddressList& addresses = event.emailAddresses();
00514 for (QValueList<KCal::Person>::ConstIterator it = addresses.begin(); it != addresses.end(); ++it)
00515 {
00516 QCString email = (*it).email().local8Bit();
00517 const char* em = email;
00518 if (!email.isEmpty()
00519 && HeaderParsing::parseAddress(em, em + email.length(), addr))
00520 {
00521 QString domain = addr.mailboxList.first().addrSpec.domain;
00522 if (!domain.isEmpty() && domain != localhost && domain != hostname)
00523 {
00524 QString text = (Preferences::emailClient() == Preferences::KMAIL)
00525 ? i18n("An email has been queued to be sent by KMail")
00526 : i18n("An email has been queued to be sent");
00527 KMessageBox::information(0, text, QString::null, Preferences::EMAIL_QUEUED_NOTIFY);
00528 return;
00529 }
00530 }
00531 }
00532 }
00533
00534
00535
00536
00537 bool KAMail::identitiesExist()
00538 {
00539 identityManager();
00540 return mIdentityManager->begin() != mIdentityManager->end();
00541 }
00542
00543
00544
00545
00546 QString KAMail::controlCentreAddress()
00547 {
00548 KEMailSettings e;
00549 return e.getSetting(KEMailSettings::EmailAddress);
00550 }
00551
00552
00553
00554
00555
00556
00557 QString KAMail::convertAddresses(const QString& items, EmailAddressList& list)
00558 {
00559 list.clear();
00560 QCString addrs = items.local8Bit();
00561 const char* ad = static_cast<const char*>(addrs);
00562
00563
00564 QValueList<KMime::Types::Address> maybeAddressList;
00565 if (!HeaderParsing::parseAddressList(ad, ad + addrs.length(), maybeAddressList))
00566 return QString::fromLocal8Bit(ad);
00567
00568
00569 for (QValueList<KMime::Types::Address>::ConstIterator it = maybeAddressList.begin();
00570 it != maybeAddressList.end(); ++it)
00571 {
00572 QString bad = convertAddress(*it, list);
00573 if (!bad.isEmpty())
00574 return bad;
00575 }
00576 return QString::null;
00577 }
00578
00579 #if 0
00580
00581
00582
00583
00584
00585 QString KAMail::convertAddress(const QString& item, EmailAddressList& list)
00586 {
00587 QCString addr = item.local8Bit();
00588 const char* ad = static_cast<const char*>(addr);
00589 KMime::Types::Address maybeAddress;
00590 if (!HeaderParsing::parseAddress(ad, ad + addr.length(), maybeAddress))
00591 return item;
00592 return convertAddress(maybeAddress, list);
00593 }
00594 #endif
00595
00596
00597
00598
00599
00600 QString KAMail::convertAddress(KMime::Types::Address addr, EmailAddressList& list)
00601 {
00602 if (!addr.displayName.isEmpty())
00603 {
00604 kdDebug(5950) << "mailbox groups not allowed! Name: \"" << addr.displayName << "\"" << endl;
00605 return addr.displayName;
00606 }
00607 const QValueList<KMime::Types::Mailbox>& mblist = addr.mailboxList;
00608 for (QValueList<KMime::Types::Mailbox>::ConstIterator mb = mblist.begin();
00609 mb != mblist.end(); ++mb)
00610 {
00611 QString addrPart = (*mb).addrSpec.localPart;
00612 if (!(*mb).addrSpec.domain.isEmpty())
00613 {
00614 addrPart += QChar('@');
00615 addrPart += (*mb).addrSpec.domain;
00616 }
00617 list += KCal::Person((*mb).displayName, addrPart);
00618 }
00619 return QString::null;
00620 }
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 int KAMail::checkAddress(QString& address)
00653 {
00654 address = address.stripWhiteSpace();
00655
00656 if (address.find(',') >= 0 || address.find(';') >= 0)
00657 return -1;
00658 int n = address.length();
00659 if (!n)
00660 return 0;
00661 int start = 0;
00662 int end = n - 1;
00663 if (address[end] == '>')
00664 {
00665
00666 if ((start = address.find('<')) < 0)
00667 return -1;
00668 ++start;
00669 --end;
00670 }
00671 int i = address.find('@', start);
00672 if (i >= 0)
00673 {
00674 if (i == start || i == end)
00675
00676 return -1;
00677 }
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 return 1;
00694 }
00695
00696
00697
00698
00699
00700
00701 QString KAMail::convertAttachments(const QString& items, QStringList& list)
00702 {
00703 KURL url;
00704 list.clear();
00705 int length = items.length();
00706 for (int next = 0; next < length; )
00707 {
00708
00709 int i = items.find(',', next);
00710 if (i < 0)
00711 i = items.length();
00712 int sc = items.find(';', next);
00713 if (sc < 0)
00714 sc = items.length();
00715 if (sc < i)
00716 i = sc;
00717 QString item = items.mid(next, i - next).stripWhiteSpace();
00718 switch (checkAttachment(item))
00719 {
00720 case 1: list += item; break;
00721 case 0: break;
00722 case -1:
00723 default: return item;
00724 }
00725 next = i + 1;
00726 }
00727 return QString::null;
00728 }
00729
00730 #if 0
00731
00732
00733
00734
00735
00736 QString KAMail::convertAttachments(const QString& items, KURL::List& list)
00737 {
00738 KURL url;
00739 list.clear();
00740 QCString addrs = items.local8Bit();
00741 int length = items.length();
00742 for (int next = 0; next < length; )
00743 {
00744
00745 int i = items.find(',', next);
00746 if (i < 0)
00747 i = items.length();
00748 int sc = items.find(';', next);
00749 if (sc < 0)
00750 sc = items.length();
00751 if (sc < i)
00752 i = sc;
00753 QString item = items.mid(next, i - next);
00754 switch (checkAttachment(item, &url))
00755 {
00756 case 1: list += url; break;
00757 case 0: break;
00758 case -1:
00759 default: return item;
00760 }
00761 next = i + 1;
00762 }
00763 return QString::null;
00764 }
00765 #endif
00766
00767
00768
00769
00770
00771
00772
00773
00774 int KAMail::checkAttachment(QString& attachment, KURL* url)
00775 {
00776 attachment = attachment.stripWhiteSpace();
00777 if (attachment.isEmpty())
00778 {
00779 if (url)
00780 *url = KURL();
00781 return 0;
00782 }
00783
00784 KURL u = KURL::fromPathOrURL(attachment);
00785 u.cleanPath();
00786 if (url)
00787 *url = u;
00788 return checkAttachment(u) ? 1 : -1;
00789 }
00790
00791
00792
00793
00794 bool KAMail::checkAttachment(const KURL& url)
00795 {
00796 KIO::UDSEntry uds;
00797 if (!KIO::NetAccess::stat(url, uds, MainWindow::mainMainWindow()))
00798 return false;
00799 KFileItem fi(uds, url);
00800 if (fi.isDir() || !fi.isReadable())
00801 return false;
00802 return true;
00803 }
00804
00805
00806
00807
00808
00809
00810
00811
00812 char* KAMail::base64Encode(const char* in, QIODevice::Offset size, QIODevice::Offset& outSize)
00813 {
00814 const int MAX_LINELEN = 72;
00815 static unsigned char dtable[65] =
00816 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00817 "abcdefghijklmnopqrstuvwxyz"
00818 "0123456789+/";
00819
00820 char* out = new char [2*size + 5];
00821 outSize = (QIODevice::Offset)-1;
00822 QIODevice::Offset outIndex = 0;
00823 int lineLength = 0;
00824 for (QIODevice::Offset inIndex = 0; inIndex < size; )
00825 {
00826 unsigned char igroup[3];
00827 int n;
00828 for (n = 0; n < 3; ++n)
00829 {
00830 if (inIndex < size)
00831 igroup[n] = (unsigned char)in[inIndex++];
00832 else
00833 {
00834 igroup[n] = igroup[2] = 0;
00835 break;
00836 }
00837 }
00838
00839 if (n > 0)
00840 {
00841 unsigned char ogroup[4];
00842 ogroup[0] = dtable[igroup[0] >> 2];
00843 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
00844 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
00845 ogroup[3] = dtable[igroup[2] & 0x3F];
00846
00847 if (n < 3)
00848 {
00849 ogroup[3] = '=';
00850 if (n < 2)
00851 ogroup[2] = '=';
00852 }
00853 if (outIndex >= size*2)
00854 {
00855 delete[] out;
00856 return 0;
00857 }
00858 for (int i = 0; i < 4; ++i)
00859 {
00860 if (lineLength >= MAX_LINELEN)
00861 {
00862 out[outIndex++] = '\r';
00863 out[outIndex++] = '\n';
00864 lineLength = 0;
00865 }
00866 out[outIndex++] = ogroup[i];
00867 ++lineLength;
00868 }
00869 }
00870 }
00871
00872 if (outIndex + 2 < size*2)
00873 {
00874 out[outIndex++] = '\r';
00875 out[outIndex++] = '\n';
00876 }
00877 outSize = outIndex;
00878 return out;
00879 }
00880
00881
00882
00883
00884 QStringList KAMail::errors(const QString& err, bool sendfail)
00885 {
00886 QString error1 = sendfail ? i18n("Failed to send email")
00887 : i18n("Error copying sent email to KMail %1 folder").arg(i18n_sent_mail());
00888 if (err.isEmpty())
00889 return QStringList(error1);
00890 QStringList errs(QString::fromLatin1("%1:").arg(error1));
00891 errs += err;
00892 return errs;
00893 }
00894
00895
00896
00897
00898 QString KAMail::getMailBody(Q_UINT32 serialNumber)
00899 {
00900
00901 QCString replyType;
00902 QByteArray replyData;
00903 QByteArray data;
00904 QDataStream arg(data, IO_WriteOnly);
00905 arg << serialNumber;
00906 arg << (int)0;
00907 QString body;
00908 if (kapp->dcopClient()->call("kmail", "KMailIface", "getDecodedBodyPart(Q_UINT32,int)", data, replyType, replyData)
00909 && replyType == "QString")
00910 {
00911 QDataStream reply_stream(replyData, IO_ReadOnly);
00912 reply_stream >> body;
00913 }
00914 else
00915 kdDebug(5950) << "KAMail::getMailBody(): kmail getDecodedBodyPart() call failed\n";
00916 return body;
00917 }
00918
00919 namespace
00920 {
00921
00922
00923
00924 QString getHostName()
00925 {
00926 char hname[256];
00927 if (gethostname(hname, sizeof(hname)))
00928 return QString::null;
00929 return QString::fromLocal8Bit(hname);
00930 }
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940 namespace HeaderParsing
00941 {
00942
00943 using namespace KMime;
00944 using namespace KMime::Types;
00945 using namespace KMime::HeaderParsing;
00946
00947
00948
00949
00950
00951 bool parseUserName( const char* & scursor, const char * const send,
00952 QString & result, bool isCRLF ) {
00953
00954 QString maybeLocalPart;
00955 QString tmp;
00956
00957 if ( scursor != send ) {
00958
00959 eatCFWS( scursor, send, isCRLF );
00960
00961 char ch = *scursor++;
00962 switch ( ch ) {
00963 case '.':
00964 case '@':
00965 case '"':
00966 return false;
00967
00968 default:
00969 scursor--;
00970 tmp = QString::null;
00971 if ( parseAtom( scursor, send, result, false ) ) {
00972 if (getpwnam(result.local8Bit()))
00973 return true;
00974 }
00975 return false;
00976 }
00977 }
00978 return false;
00979 }
00980
00981
00982
00983
00984
00985
00986 bool parseAddress( const char* & scursor, const char * const send,
00987 Address & result, bool isCRLF ) {
00988
00989
00990 eatCFWS( scursor, send, isCRLF );
00991 if ( scursor == send ) return false;
00992
00993
00994 Mailbox maybeMailbox;
00995 const char * oldscursor = scursor;
00996 if ( parseMailbox( scursor, send, maybeMailbox, isCRLF ) ) {
00997
00998 result.displayName = QString::null;
00999 result.mailboxList.append( maybeMailbox );
01000 return true;
01001 }
01002 scursor = oldscursor;
01003
01004
01005
01006 QString maybeUserName;
01007 if ( parseUserName( scursor, send, maybeUserName, isCRLF ) ) {
01008
01009 maybeMailbox.displayName = QString::null;
01010 maybeMailbox.addrSpec.localPart = maybeUserName;
01011 maybeMailbox.addrSpec.domain = QString::null;
01012 result.displayName = QString::null;
01013 result.mailboxList.append( maybeMailbox );
01014 return true;
01015 }
01016 scursor = oldscursor;
01017
01018 Address maybeAddress;
01019
01020
01021 if ( !parseGroup( scursor, send, maybeAddress, isCRLF ) )
01022 {
01023 scursor = oldscursor;
01024 return false;
01025 }
01026
01027 result = maybeAddress;
01028 return true;
01029 }
01030
01031
01032
01033
01034
01035 bool parseAddressList( const char* & scursor, const char * const send,
01036 QValueList<Address> & result, bool isCRLF ) {
01037 while ( scursor != send ) {
01038 eatCFWS( scursor, send, isCRLF );
01039
01040 if ( scursor == send ) return true;
01041
01042 if ( *scursor == ',' || *scursor == ';' ) { scursor++; continue; }
01043
01044
01045 Address maybeAddress;
01046 if ( !parseAddress( scursor, send, maybeAddress, isCRLF ) ) return false;
01047 result.append( maybeAddress );
01048
01049 eatCFWS( scursor, send, isCRLF );
01050
01051 if ( scursor == send ) return true;
01052
01053 if ( *scursor == ',' || *scursor == ';' ) scursor++;
01054 }
01055 return true;
01056 }
01057
01058 }