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