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