00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00059 #ifdef HAVE_CONFIG_H
00060 #include <config.h>
00061 #endif
00062
00063 #include "imap4.h"
00064
00065 #include "rfcdecoder.h"
00066
00067 #include <sys/stat.h>
00068
00069 #include <stdio.h>
00070 #include <stdlib.h>
00071 #include <signal.h>
00072 #include <sys/types.h>
00073 #include <sys/wait.h>
00074
00075 #ifdef HAVE_LIBSASL2
00076 extern "C" {
00077 #include <sasl/sasl.h>
00078 }
00079 #endif
00080
00081 #include <qbuffer.h>
00082 #include <qdatetime.h>
00083 #include <qregexp.h>
00084 #include <kprotocolmanager.h>
00085 #include <kmessagebox.h>
00086 #include <kdebug.h>
00087 #include <kio/connection.h>
00088 #include <kio/slaveinterface.h>
00089 #include <kio/passdlg.h>
00090 #include <klocale.h>
00091 #include <kmimetype.h>
00092 #include <kmdcodec.h>
00093
00094 #include "kdepimmacros.h"
00095
00096 #define IMAP_PROTOCOL "imap"
00097 #define IMAP_SSL_PROTOCOL "imaps"
00098
00099 using namespace KIO;
00100
00101 extern "C"
00102 {
00103 void sigalrm_handler (int);
00104 KDE_EXPORT int kdemain (int argc, char **argv);
00105 }
00106
00107 int
00108 kdemain (int argc, char **argv)
00109 {
00110 kdDebug(7116) << "IMAP4::kdemain" << endl;
00111
00112 KInstance instance ("kio_imap4");
00113 if (argc != 4)
00114 {
00115 fprintf(stderr, "Usage: kio_imap4 protocol domain-socket1 domain-socket2\n");
00116 ::exit (-1);
00117 }
00118
00119 #ifdef HAVE_LIBSASL2
00120 if ( sasl_client_init( NULL ) != SASL_OK ) {
00121 fprintf(stderr, "SASL library initialization failed!\n");
00122 ::exit (-1);
00123 }
00124 #endif
00125
00126
00127
00128 IMAP4Protocol *slave;
00129 if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
00130 slave = new IMAP4Protocol (argv[2], argv[3], true);
00131 else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
00132 slave = new IMAP4Protocol (argv[2], argv[3], false);
00133 else
00134 abort ();
00135 slave->dispatchLoop ();
00136 delete slave;
00137
00138 #ifdef HAVE_LIBSASL2
00139 sasl_done();
00140 #endif
00141
00142 return 0;
00143 }
00144
00145 void
00146 sigchld_handler (int signo)
00147 {
00148 int pid, status;
00149
00150 while (true && signo == SIGCHLD)
00151 {
00152 pid = waitpid (-1, &status, WNOHANG);
00153 if (pid <= 0)
00154 {
00155
00156
00157
00158 signal (SIGCHLD, sigchld_handler);
00159 return;
00160 }
00161 }
00162 }
00163
00164 IMAP4Protocol::IMAP4Protocol (const QCString & pool, const QCString & app, bool isSSL):TCPSlaveBase ((isSSL ? 993 : 143),
00165 (isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool,
00166 app, isSSL), imapParser (), mimeIO (), outputBuffer(outputCache)
00167 {
00168 outputBufferIndex = 0;
00169 mySSL = isSSL;
00170 readBuffer[0] = 0x00;
00171 relayEnabled = false;
00172 readBufferLen = 0;
00173 cacheOutput = false;
00174 decodeContent = false;
00175 mTimeOfLastNoop = QDateTime();
00176 }
00177
00178 IMAP4Protocol::~IMAP4Protocol ()
00179 {
00180 closeDescriptor();
00181 kdDebug(7116) << "IMAP4: Finishing" << endl;
00182 }
00183
00184 void
00185 IMAP4Protocol::get (const KURL & _url)
00186 {
00187 if (!makeLogin()) return;
00188 kdDebug(7116) << "IMAP4::get - " << _url.prettyURL() << endl;
00189 QString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
00190 enum IMAP_TYPE aEnum =
00191 parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
00192 if (aEnum != ITYPE_ATTACH)
00193 mimeType (getMimeType(aEnum));
00194 if (aInfo == "DECODE")
00195 decodeContent = true;
00196
00197 if (aSequence == "0:0" && getState() == ISTATE_SELECT)
00198 {
00199 imapCommand *cmd = doCommand (imapCommand::clientNoop());
00200 completeQueue.removeRef(cmd);
00201 }
00202
00203 if (aSequence.isEmpty ())
00204 {
00205 aSequence = "1:*";
00206 }
00207
00208 mProcessedSize = 0;
00209 imapCommand *cmd = NULL;
00210 if (!assureBox (aBox, true)) return;
00211
00212 #ifdef USE_VALIDITY
00213 if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
00214 && selectInfo.uidValidity () != aValidity.toULong ())
00215 {
00216
00217 error (ERR_COULD_NOT_READ, _url.prettyURL());
00218 return;
00219 }
00220 else
00221 #endif
00222 {
00223
00224
00225
00226
00227
00228
00229
00230 QString aUpper = aSection.upper();
00231 if (aUpper.find ("STRUCTURE") != -1)
00232 {
00233 aSection = "BODYSTRUCTURE";
00234 }
00235 else if (aUpper.find ("ENVELOPE") != -1)
00236 {
00237 aSection = "UID RFC822.SIZE FLAGS ENVELOPE";
00238 if (hasCapability("IMAP4rev1")) {
00239 aSection += " BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
00240 } else {
00241
00242 aSection += " RFC822.HEADER.LINES (REFERENCES)";
00243 }
00244 }
00245 else if (aUpper == "HEADER")
00246 {
00247 aSection = "UID RFC822.HEADER RFC822.SIZE FLAGS";
00248 }
00249 else if (aUpper.find ("BODY.PEEK[") != -1)
00250 {
00251 if (aUpper.find ("BODY.PEEK[]") != -1)
00252 {
00253 if (!hasCapability("IMAP4rev1"))
00254 aSection.replace("BODY.PEEK[]", "RFC822.PEEK");
00255 }
00256 aSection.prepend("UID RFC822.SIZE FLAGS ");
00257 }
00258 else if (aSection.isEmpty())
00259 {
00260 aSection = "UID BODY[] RFC822.SIZE FLAGS";
00261 }
00262 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00263 {
00264
00265 cacheOutput = true;
00266 outputLine
00267 ("Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
00268 if (selectInfo.recentAvailable ())
00269 outputLineStr ("X-Recent: " +
00270 QString::number(selectInfo.recent ()) + "\r\n");
00271 if (selectInfo.countAvailable ())
00272 outputLineStr ("X-Count: " + QString::number(selectInfo.count ()) +
00273 "\r\n");
00274 if (selectInfo.unseenAvailable ())
00275 outputLineStr ("X-Unseen: " +
00276 QString::number(selectInfo.unseen ()) + "\r\n");
00277 if (selectInfo.uidValidityAvailable ())
00278 outputLineStr ("X-uidValidity: " +
00279 QString::number(selectInfo.uidValidity ()) +
00280 "\r\n");
00281 if (selectInfo.uidNextAvailable ())
00282 outputLineStr ("X-UidNext: " +
00283 QString::number(selectInfo.uidNext ()) + "\r\n");
00284 if (selectInfo.flagsAvailable ())
00285 outputLineStr ("X-Flags: " + QString::number(selectInfo.flags ()) +
00286 "\r\n");
00287 if (selectInfo.permanentFlagsAvailable ())
00288 outputLineStr ("X-PermanentFlags: " +
00289 QString::number(selectInfo.permanentFlags ()) + "\r\n");
00290 if (selectInfo.readWriteAvailable ()) {
00291 if (selectInfo.readWrite()) {
00292 outputLine ("X-Access: Read/Write\r\n", 22);
00293 } else {
00294 outputLine ("X-Access: Read only\r\n", 21);
00295 }
00296 }
00297 outputLine ("\r\n", 2);
00298 flushOutput(QString::null);
00299 cacheOutput = false;
00300 }
00301
00302 if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
00303 relayEnabled = true;
00304
00305 if (aSequence != "0:0")
00306 {
00307 QString contentEncoding;
00308 if (aEnum == ITYPE_ATTACH && decodeContent)
00309 {
00310
00311 QString mySection = aSection;
00312 mySection.replace("]", ".MIME]");
00313 cmd = sendCommand (imapCommand::clientFetch (aSequence, mySection));
00314 do
00315 {
00316 while (!parseLoop ());
00317 }
00318 while (!cmd->isComplete ());
00319 completeQueue.removeRef (cmd);
00320
00321 if (getLastHandled() && getLastHandled()->getHeader())
00322 contentEncoding = getLastHandled()->getHeader()->getEncoding();
00323
00324
00325
00326
00327 cacheOutput = true;
00328 }
00329
00330 cmd = sendCommand (imapCommand::clientFetch (aSequence, aSection));
00331 int res;
00332 aUpper = aSection.upper();
00333 do
00334 {
00335 while (!(res = parseLoop()));
00336 if (res == -1) break;
00337
00338 mailHeader *lastone = 0;
00339 imapCache *cache = getLastHandled ();
00340 if (cache)
00341 lastone = cache->getHeader ();
00342
00343 if (cmd && !cmd->isComplete ())
00344 {
00345 if ((aUpper.find ("BODYSTRUCTURE") != -1)
00346 || (aUpper.find ("FLAGS") != -1)
00347 || (aUpper.find ("UID") != -1)
00348 || (aUpper.find ("ENVELOPE") != -1)
00349 || (aUpper.find ("BODY.PEEK[0]") != -1
00350 && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
00351 {
00352 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00353 {
00354
00355 outputLine ("--IMAPDIGEST\r\n", 14);
00356 cacheOutput = true;
00357 if (cache && cache->getUid () != 0)
00358 outputLineStr ("X-UID: " +
00359 QString::number(cache->getUid ()) + "\r\n");
00360 if (cache && cache->getSize () != 0)
00361 outputLineStr ("X-Length: " +
00362 QString::number(cache->getSize ()) + "\r\n");
00363 if (cache && !cache->getDate ().isEmpty())
00364 outputLineStr ("X-Date: " + cache->getDate () + "\r\n");
00365 if (cache && cache->getFlags () != 0)
00366 outputLineStr ("X-Flags: " +
00367 QString::number(cache->getFlags ()) + "\r\n");
00368 } else cacheOutput = true;
00369 if ( lastone && !decodeContent )
00370 lastone->outputPart (*this);
00371 cacheOutput = false;
00372 flushOutput(contentEncoding);
00373 }
00374 }
00375 }
00376 while (cmd && !cmd->isComplete ());
00377 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00378 {
00379
00380 outputLine ("--IMAPDIGEST--\r\n", 16);
00381 }
00382
00383 completeQueue.removeRef (cmd);
00384 }
00385 }
00386
00387
00388 data (QByteArray ());
00389
00390 finished ();
00391 relayEnabled = false;
00392 cacheOutput = false;
00393 kdDebug(7116) << "IMAP4::get - finished" << endl;
00394 }
00395
00396 void
00397 IMAP4Protocol::listDir (const KURL & _url)
00398 {
00399 kdDebug(7116) << " IMAP4::listDir - " << _url.prettyURL() << endl;
00400
00401 if (_url.path().isEmpty())
00402 {
00403 KURL url = _url;
00404 url.setPath("/");
00405 redirection( url );
00406 finished();
00407 return;
00408 }
00409
00410 QString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
00411
00412 enum IMAP_TYPE myType =
00413 parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
00414 myDelimiter, myInfo, true);
00415
00416 if (!makeLogin()) return;
00417
00418 if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
00419 {
00420 QString listStr = myBox;
00421 imapCommand *cmd;
00422
00423 if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
00424 mySection != "FOLDERONLY")
00425 listStr += myDelimiter;
00426
00427 if (mySection.isEmpty())
00428 {
00429 listStr += "%";
00430 } else if (mySection == "COMPLETE") {
00431 listStr += "*";
00432 }
00433 kdDebug(7116) << "IMAP4Protocol::listDir - listStr=" << listStr << endl;
00434 cmd =
00435 doCommand (imapCommand::clientList ("", listStr,
00436 (myLType == "LSUB" || myLType == "LSUBNOCHECK")));
00437 if (cmd->result () == "OK")
00438 {
00439 QString mailboxName;
00440 UDSEntry entry;
00441 UDSAtom atom;
00442 KURL aURL = _url;
00443 if (aURL.path().find(';') != -1)
00444 aURL.setPath(aURL.path().left(aURL.path().find(';')));
00445
00446 kdDebug(7116) << "IMAP4Protocol::listDir - got " << listResponses.count () << endl;
00447
00448 if (myLType == "LSUB")
00449 {
00450
00451 QValueList<imapList> listResponsesSave = listResponses;
00452 doCommand (imapCommand::clientList ("", listStr, false));
00453 for (QValueListIterator < imapList > it = listResponsesSave.begin ();
00454 it != listResponsesSave.end (); ++it)
00455 {
00456 bool boxOk = false;
00457 for (QValueListIterator < imapList > it2 = listResponses.begin ();
00458 it2 != listResponses.end (); ++it2)
00459 {
00460 if ((*it2).name() == (*it).name())
00461 {
00462 boxOk = true;
00463
00464 (*it) = (*it2);
00465 break;
00466 }
00467 }
00468 if (boxOk)
00469 doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
00470 else
00471 kdDebug(7116) << "IMAP4Protocol::listDir - suppress " << (*it).name() << endl;
00472 }
00473 listResponses = listResponsesSave;
00474 }
00475 else
00476 {
00477 for (QValueListIterator < imapList > it = listResponses.begin ();
00478 it != listResponses.end (); ++it)
00479 {
00480 doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
00481 }
00482 }
00483 entry.clear ();
00484 listEntry (entry, true);
00485 }
00486 else
00487 {
00488 error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyURL());
00489 completeQueue.removeRef (cmd);
00490 return;
00491 }
00492 completeQueue.removeRef (cmd);
00493 }
00494 if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
00495 && myLType != "LIST" && myLType != "LSUB" && myLType != "LSUBNOCHECK")
00496 {
00497 KURL aURL = _url;
00498 aURL.setQuery (QString::null);
00499 const QString encodedUrl = aURL.url(0, 106);
00500
00501 if (!_url.query ().isEmpty ())
00502 {
00503 QString query = KURL::decode_string (_url.query ());
00504 query = query.right (query.length () - 1);
00505 if (!query.isEmpty())
00506 {
00507 imapCommand *cmd = NULL;
00508
00509 if (!assureBox (myBox, true)) return;
00510
00511 if (!selectInfo.countAvailable() || selectInfo.count())
00512 {
00513 cmd = doCommand (imapCommand::clientSearch (query));
00514 if (cmd->result() != "OK")
00515 {
00516 error(ERR_UNSUPPORTED_ACTION, _url.prettyURL());
00517 completeQueue.removeRef (cmd);
00518 return;
00519 }
00520 completeQueue.removeRef (cmd);
00521
00522 QStringList list = getResults ();
00523 int stretch = 0;
00524
00525 if (selectInfo.uidNextAvailable ())
00526 stretch = QString::number(selectInfo.uidNext ()).length ();
00527 UDSEntry entry;
00528 imapCache fake;
00529
00530 for (QStringList::ConstIterator it = list.begin(); it != list.end();
00531 ++it)
00532 {
00533 fake.setUid((*it).toULong());
00534 doListEntry (encodedUrl, stretch, &fake);
00535 }
00536 entry.clear ();
00537 listEntry (entry, true);
00538 }
00539 }
00540 }
00541 else
00542 {
00543 if (!assureBox (myBox, true)) return;
00544
00545 kdDebug(7116) << "IMAP4: select returned:" << endl;
00546 if (selectInfo.recentAvailable ())
00547 kdDebug(7116) << "Recent: " << selectInfo.recent () << "d" << endl;
00548 if (selectInfo.countAvailable ())
00549 kdDebug(7116) << "Count: " << selectInfo.count () << "d" << endl;
00550 if (selectInfo.unseenAvailable ())
00551 kdDebug(7116) << "Unseen: " << selectInfo.unseen () << "d" << endl;
00552 if (selectInfo.uidValidityAvailable ())
00553 kdDebug(7116) << "uidValidity: " << selectInfo.uidValidity () << "d" << endl;
00554 if (selectInfo.flagsAvailable ())
00555 kdDebug(7116) << "Flags: " << selectInfo.flags () << "d" << endl;
00556 if (selectInfo.permanentFlagsAvailable ())
00557 kdDebug(7116) << "PermanentFlags: " << selectInfo.permanentFlags () << "d" << endl;
00558 if (selectInfo.readWriteAvailable ())
00559 kdDebug(7116) << "Access: " << (selectInfo.readWrite ()? "Read/Write" : "Read only") << endl;
00560
00561 #ifdef USE_VALIDITY
00562 if (selectInfo.uidValidityAvailable ()
00563 && selectInfo.uidValidity () != myValidity.toULong ())
00564 {
00565
00566 KURL newUrl = _url;
00567
00568 newUrl.setPath ("/" + myBox + ";UIDVALIDITY=" +
00569 QString::number(selectInfo.uidValidity ()));
00570 kdDebug(7116) << "IMAP4::listDir - redirecting to " << newUrl.prettyURL() << endl;
00571 redirection (newUrl);
00572
00573
00574 }
00575 else
00576 #endif
00577 if (selectInfo.count () > 0)
00578 {
00579 int stretch = 0;
00580
00581 if (selectInfo.uidNextAvailable ())
00582 stretch = QString::number(selectInfo.uidNext ()).length ();
00583
00584 UDSEntry entry;
00585
00586 if (mySequence.isEmpty()) mySequence = "1:*";
00587
00588 bool withSubject = mySection.isEmpty();
00589 if (mySection.isEmpty()) mySection = "UID RFC822.SIZE ENVELOPE";
00590
00591 bool withFlags = mySection.upper().find("FLAGS") != -1;
00592 imapCommand *fetch =
00593 sendCommand (imapCommand::
00594 clientFetch (mySequence, mySection));
00595 imapCache *cache;
00596 do
00597 {
00598 while (!parseLoop ());
00599
00600 cache = getLastHandled ();
00601
00602 if (cache && !fetch->isComplete())
00603 doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
00604 }
00605 while (!fetch->isComplete ());
00606 entry.clear ();
00607 listEntry (entry, true);
00608 }
00609 }
00610 }
00611 if ( !selectInfo.alert().isNull() ) {
00612 if ( !myBox.isEmpty() ) {
00613 warning( i18n( "Message from %1 while processing '%2': %3" ).arg( myHost, myBox, selectInfo.alert() ) );
00614 } else {
00615 warning( i18n( "Message from %1: %2" ).arg( myHost, selectInfo.alert() ) );
00616 }
00617 selectInfo.setAlert( 0 );
00618 }
00619
00620 kdDebug(7116) << "IMAP4Protocol::listDir - Finishing listDir" << endl;
00621 finished ();
00622 }
00623
00624 void
00625 IMAP4Protocol::setHost (const QString & _host, int _port,
00626 const QString & _user, const QString & _pass)
00627 {
00628 if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
00629 {
00630
00631 if (!myHost.isEmpty ())
00632 closeConnection ();
00633 myHost = _host;
00634 myPort = _port;
00635 myUser = _user;
00636 myPass = _pass;
00637 }
00638 }
00639
00640 void
00641 IMAP4Protocol::parseRelay (const QByteArray & buffer)
00642 {
00643 if (relayEnabled) {
00644
00645 data( buffer );
00646 mProcessedSize += buffer.size();
00647 processedSize( mProcessedSize );
00648 } else if (cacheOutput)
00649 {
00650
00651 if ( !outputBuffer.isOpen() ) {
00652 outputBuffer.open(IO_WriteOnly);
00653 }
00654 outputBuffer.at(outputBufferIndex);
00655 outputBuffer.writeBlock(buffer, buffer.size());
00656 outputBufferIndex += buffer.size();
00657 }
00658 }
00659
00660 void
00661 IMAP4Protocol::parseRelay (ulong len)
00662 {
00663 if (relayEnabled)
00664 totalSize (len);
00665 }
00666
00667
00668 bool IMAP4Protocol::parseRead(QByteArray & buffer, ulong len, ulong relay)
00669 {
00670 char buf[8192];
00671 while (buffer.size() < len)
00672 {
00673 ssize_t readLen = myRead(buf, QMIN(len - buffer.size(), sizeof(buf) - 1));
00674 if (readLen == 0)
00675 {
00676 kdDebug(7116) << "parseRead: readLen == 0 - connection broken" << endl;
00677 error (ERR_CONNECTION_BROKEN, myHost);
00678 setState(ISTATE_CONNECT);
00679 closeConnection();
00680 return FALSE;
00681 }
00682 if (relay > buffer.size())
00683 {
00684 QByteArray relayData;
00685 ssize_t relbuf = relay - buffer.size();
00686 int currentRelay = QMIN(relbuf, readLen);
00687 relayData.setRawData(buf, currentRelay);
00688 parseRelay(relayData);
00689 relayData.resetRawData(buf, currentRelay);
00690 }
00691 {
00692 QBuffer stream (buffer);
00693 stream.open (IO_WriteOnly);
00694 stream.at (buffer.size ());
00695 stream.writeBlock (buf, readLen);
00696 stream.close ();
00697 }
00698 }
00699 return (buffer.size() == len);
00700 }
00701
00702
00703 bool IMAP4Protocol::parseReadLine (QByteArray & buffer, ulong relay)
00704 {
00705 if (myHost.isEmpty()) return FALSE;
00706
00707 while (true) {
00708 ssize_t copyLen = 0;
00709 if (readBufferLen > 0)
00710 {
00711 while (copyLen < readBufferLen && readBuffer[copyLen] != '\n') copyLen++;
00712 if (copyLen < readBufferLen) copyLen++;
00713 if (relay > 0)
00714 {
00715 QByteArray relayData;
00716
00717 if (copyLen < (ssize_t) relay)
00718 relay = copyLen;
00719 relayData.setRawData (readBuffer, relay);
00720 parseRelay (relayData);
00721 relayData.resetRawData (readBuffer, relay);
00722
00723 }
00724
00725 {
00726 QBuffer stream (buffer);
00727
00728 stream.open (IO_WriteOnly);
00729 stream.at (buffer.size ());
00730 stream.writeBlock (readBuffer, copyLen);
00731 stream.close ();
00732
00733 }
00734
00735 readBufferLen -= copyLen;
00736 if (readBufferLen)
00737 memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
00738 if (buffer[buffer.size() - 1] == '\n') return TRUE;
00739 }
00740 if (!isConnectionValid())
00741 {
00742 kdDebug(7116) << "parseReadLine - connection broken" << endl;
00743 error (ERR_CONNECTION_BROKEN, myHost);
00744 setState(ISTATE_CONNECT);
00745 closeConnection();
00746 return FALSE;
00747 }
00748 if (!waitForResponse( responseTimeout() ))
00749 {
00750 error(ERR_SERVER_TIMEOUT, myHost);
00751 setState(ISTATE_CONNECT);
00752 closeConnection();
00753 return FALSE;
00754 }
00755 readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
00756 if (readBufferLen == 0)
00757 {
00758 kdDebug(7116) << "parseReadLine: readBufferLen == 0 - connection broken" << endl;
00759 error (ERR_CONNECTION_BROKEN, myHost);
00760 setState(ISTATE_CONNECT);
00761 closeConnection();
00762 return FALSE;
00763 }
00764 }
00765 }
00766
00767 void
00768 IMAP4Protocol::setSubURL (const KURL & _url)
00769 {
00770 kdDebug(7116) << "IMAP4::setSubURL - " << _url.prettyURL() << endl;
00771 KIO::TCPSlaveBase::setSubURL (_url);
00772 }
00773
00774 void
00775 IMAP4Protocol::put (const KURL & _url, int, bool, bool)
00776 {
00777 kdDebug(7116) << "IMAP4::put - " << _url.prettyURL() << endl;
00778
00779 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
00780 enum IMAP_TYPE aType =
00781 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00782
00783
00784 if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
00785 {
00786 if (aBox[aBox.length () - 1] == '/')
00787 aBox = aBox.right (aBox.length () - 1);
00788 imapCommand *cmd = doCommand (imapCommand::clientCreate (aBox));
00789
00790 if (cmd->result () != "OK") {
00791 error (ERR_COULD_NOT_WRITE, _url.prettyURL());
00792 completeQueue.removeRef (cmd);
00793 return;
00794 }
00795 completeQueue.removeRef (cmd);
00796 }
00797 else
00798 {
00799 QPtrList < QByteArray > bufferList;
00800 int length = 0;
00801
00802 int result;
00803
00804 do
00805 {
00806 QByteArray *buffer = new QByteArray ();
00807 dataReq ();
00808 result = readData (*buffer);
00809 if (result > 0)
00810 {
00811 bufferList.append (buffer);
00812 length += result;
00813 } else {
00814 delete buffer;
00815 }
00816 }
00817 while (result > 0);
00818
00819 if (result != 0)
00820 {
00821 error (ERR_ABORTED, _url.prettyURL());
00822 return;
00823 }
00824
00825 imapCommand *cmd =
00826 sendCommand (imapCommand::clientAppend (aBox, aSection, length));
00827 while (!parseLoop ());
00828
00829
00830 if (!cmd->isComplete () && !getContinuation ().isEmpty ())
00831 {
00832 bool sendOk = true;
00833 ulong wrote = 0;
00834
00835 QByteArray *buffer;
00836
00837 while (!bufferList.isEmpty () && sendOk)
00838 {
00839 buffer = bufferList.take (0);
00840
00841 sendOk =
00842 (write (buffer->data (), buffer->size ()) ==
00843 (ssize_t) buffer->size ());
00844 wrote += buffer->size ();
00845 processedSize(wrote);
00846 delete buffer;
00847 if (!sendOk)
00848 {
00849 error (ERR_CONNECTION_BROKEN, myHost);
00850 completeQueue.removeRef (cmd);
00851 setState(ISTATE_CONNECT);
00852 closeConnection();
00853 return;
00854 }
00855 }
00856 parseWriteLine ("");
00857
00858 while (!cmd->isComplete () && getState() != ISTATE_NO)
00859 parseLoop ();
00860 if ( getState() == ISTATE_NO ) {
00861
00862
00863 error( ERR_CONNECTION_BROKEN, myHost );
00864 completeQueue.removeRef (cmd);
00865 closeConnection();
00866 return;
00867 }
00868 else if (cmd->result () != "OK") {
00869 error( ERR_SLAVE_DEFINED, cmd->resultInfo() );
00870 completeQueue.removeRef (cmd);
00871 return;
00872 }
00873 else
00874 {
00875 if (hasCapability("UIDPLUS"))
00876 {
00877 QString uid = cmd->resultInfo();
00878 if (uid.find("APPENDUID") != -1)
00879 {
00880 uid = uid.section(" ", 2, 2);
00881 uid.truncate(uid.length()-1);
00882 infoMessage("UID "+uid);
00883 }
00884 }
00885
00886 else if (aBox == getCurrentBox ())
00887 {
00888 cmd =
00889 doCommand (imapCommand::
00890 clientSelect (aBox, !selectInfo.readWrite ()));
00891 completeQueue.removeRef (cmd);
00892 }
00893 }
00894 }
00895 else
00896 {
00897
00898
00899 error (ERR_SLAVE_DEFINED, cmd->resultInfo());
00900 completeQueue.removeRef (cmd);
00901 return;
00902 }
00903
00904 completeQueue.removeRef (cmd);
00905 }
00906
00907 finished ();
00908 }
00909
00910 void
00911 IMAP4Protocol::mkdir (const KURL & _url, int)
00912 {
00913 kdDebug(7116) << "IMAP4::mkdir - " << _url.prettyURL() << endl;
00914 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
00915 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00916 kdDebug(7116) << "IMAP4::mkdir - create " << aBox << endl;
00917 imapCommand *cmd = doCommand (imapCommand::clientCreate(aBox));
00918
00919 if (cmd->result () != "OK")
00920 {
00921 kdDebug(7116) << "IMAP4::mkdir - " << cmd->resultInfo() << endl;
00922 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
00923 completeQueue.removeRef (cmd);
00924 return;
00925 }
00926 completeQueue.removeRef (cmd);
00927
00928
00929 enum IMAP_TYPE type =
00930 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00931 if (type == ITYPE_BOX)
00932 {
00933 bool ask = ( aInfo.find( "ASKUSER" ) != -1 );
00934 if ( ask &&
00935 messageBox(QuestionYesNo,
00936 i18n("The following folder will be created on the server: %1 "
00937 "What do you want to store in this folder?").arg( aBox ),
00938 i18n("Create Folder"),
00939 i18n("&Messages"), i18n("&Subfolders")) == KMessageBox::No )
00940 {
00941 cmd = doCommand(imapCommand::clientDelete(aBox));
00942 completeQueue.removeRef (cmd);
00943 cmd = doCommand(imapCommand::clientCreate(aBox + aDelimiter));
00944 if (cmd->result () != "OK")
00945 {
00946 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
00947 completeQueue.removeRef (cmd);
00948 return;
00949 }
00950 completeQueue.removeRef (cmd);
00951 }
00952 }
00953
00954 cmd = doCommand(imapCommand::clientSubscribe(aBox));
00955 completeQueue.removeRef(cmd);
00956
00957 finished ();
00958 }
00959
00960 void
00961 IMAP4Protocol::copy (const KURL & src, const KURL & dest, int, bool overwrite)
00962 {
00963 kdDebug(7116) << "IMAP4::copy - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
00964 QString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
00965 QString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
00966 enum IMAP_TYPE sType =
00967 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
00968 enum IMAP_TYPE dType =
00969 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
00970
00971
00972 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
00973 {
00974
00975 int sub = dBox.find (sBox);
00976
00977
00978 if (sub > 0)
00979 {
00980 KURL testDir = dest;
00981
00982 QString subDir = dBox.right (dBox.length () - dBox.findRev ('/'));
00983 QString topDir = dBox.left (sub);
00984 testDir.setPath ("/" + topDir);
00985 dType =
00986 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
00987 dDelimiter, dInfo);
00988
00989 kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
00990
00991 if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
00992 {
00993 kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
00994 dBox = topDir;
00995 }
00996 else
00997 {
00998
00999
01000 topDir = "/" + topDir + subDir;
01001 testDir.setPath (topDir);
01002 kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
01003 dType =
01004 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
01005 dDelimiter, dInfo);
01006 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
01007 {
01008
01009 imapCommand *cmd = doCommand (imapCommand::clientCreate (topDir));
01010
01011
01012 if (cmd->result () == "OK")
01013 {
01014 kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
01015 dType = ITYPE_BOX;
01016 dBox = topDir;
01017 }
01018 else
01019 {
01020 completeQueue.removeRef (cmd);
01021 cmd = doCommand (imapCommand::clientCreate (dBox));
01022 if (cmd->result () == "OK")
01023 dType = ITYPE_BOX;
01024 else
01025 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
01026 }
01027 completeQueue.removeRef (cmd);
01028 }
01029 }
01030
01031 }
01032 }
01033 if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
01034 {
01035
01036 if (!assureBox(sBox, true)) return;
01037 kdDebug(7116) << "IMAP4::copy - " << sBox << " -> " << dBox << endl;
01038
01039
01040 imapCommand *cmd =
01041 doCommand (imapCommand::clientCopy (dBox, sSequence));
01042 if (cmd->result () != "OK")
01043 {
01044 kdError(5006) << "IMAP4::copy - " << cmd->resultInfo() << endl;
01045 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
01046 completeQueue.removeRef (cmd);
01047 return;
01048 } else {
01049 if (hasCapability("UIDPLUS"))
01050 {
01051 QString uid = cmd->resultInfo();
01052 if (uid.find("COPYUID") != -1)
01053 {
01054 uid = uid.section(" ", 2, 3);
01055 uid.truncate(uid.length()-1);
01056 infoMessage("UID "+uid);
01057 }
01058 }
01059 }
01060 completeQueue.removeRef (cmd);
01061 }
01062 else
01063 {
01064 error (ERR_ACCESS_DENIED, src.prettyURL());
01065 return;
01066 }
01067 finished ();
01068 }
01069
01070 void
01071 IMAP4Protocol::del (const KURL & _url, bool isFile)
01072 {
01073 kdDebug(7116) << "IMAP4::del - [" << (isFile ? "File" : "NoFile") << "] " << _url.prettyURL() << endl;
01074 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01075 enum IMAP_TYPE aType =
01076 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01077
01078 switch (aType)
01079 {
01080 case ITYPE_BOX:
01081 case ITYPE_DIR_AND_BOX:
01082 if (!aSequence.isEmpty ())
01083 {
01084 if (aSequence == "*")
01085 {
01086 if (!assureBox (aBox, false)) return;
01087 imapCommand *cmd = doCommand (imapCommand::clientExpunge ());
01088 if (cmd->result () != "OK") {
01089 error (ERR_CANNOT_DELETE, _url.prettyURL());
01090 completeQueue.removeRef (cmd);
01091 return;
01092 }
01093 completeQueue.removeRef (cmd);
01094 }
01095 else
01096 {
01097
01098 if (!assureBox (aBox, false)) return;
01099 imapCommand *cmd =
01100 doCommand (imapCommand::
01101 clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
01102 if (cmd->result () != "OK") {
01103 error (ERR_CANNOT_DELETE, _url.prettyURL());
01104 completeQueue.removeRef (cmd);
01105 return;
01106 }
01107 completeQueue.removeRef (cmd);
01108 }
01109 }
01110 else
01111 {
01112 if (getCurrentBox() == aBox)
01113 {
01114 imapCommand *cmd = doCommand(imapCommand::clientClose());
01115 completeQueue.removeRef(cmd);
01116 setState(ISTATE_LOGIN);
01117 }
01118
01119 imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
01120 completeQueue.removeRef(cmd);
01121 cmd = doCommand(imapCommand::clientDelete (aBox));
01122
01123 if (cmd->result () != "OK")
01124 {
01125 completeQueue.removeRef(cmd);
01126 if (!assureBox(aBox, false)) return;
01127 bool stillOk = true;
01128 if (stillOk)
01129 {
01130 imapCommand *cmd = doCommand(
01131 imapCommand::clientStore("1:*", "+FLAGS.SILENT", "\\DELETED"));
01132 if (cmd->result () != "OK") stillOk = false;
01133 completeQueue.removeRef(cmd);
01134 }
01135 if (stillOk)
01136 {
01137 imapCommand *cmd = doCommand(imapCommand::clientClose());
01138 if (cmd->result () != "OK") stillOk = false;
01139 completeQueue.removeRef(cmd);
01140 setState(ISTATE_LOGIN);
01141 }
01142 if (stillOk)
01143 {
01144 imapCommand *cmd = doCommand (imapCommand::clientDelete(aBox));
01145 if (cmd->result () != "OK") stillOk = false;
01146 completeQueue.removeRef(cmd);
01147 }
01148 if (!stillOk)
01149 {
01150 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
01151 return;
01152 }
01153 } else {
01154 completeQueue.removeRef (cmd);
01155 }
01156 }
01157 break;
01158
01159 case ITYPE_DIR:
01160 {
01161 imapCommand *cmd = doCommand (imapCommand::clientDelete (aBox));
01162 if (cmd->result () != "OK") {
01163 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
01164 completeQueue.removeRef (cmd);
01165 return;
01166 }
01167 completeQueue.removeRef (cmd);
01168 }
01169 break;
01170
01171 case ITYPE_MSG:
01172 {
01173
01174 if (!assureBox (aBox, false)) return;
01175 imapCommand *cmd =
01176 doCommand (imapCommand::
01177 clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
01178 if (cmd->result () != "OK") {
01179 error (ERR_CANNOT_DELETE, _url.prettyURL());
01180 completeQueue.removeRef (cmd);
01181 return;
01182 }
01183 completeQueue.removeRef (cmd);
01184 }
01185 break;
01186
01187 case ITYPE_UNKNOWN:
01188 case ITYPE_ATTACH:
01189 error (ERR_CANNOT_DELETE, _url.prettyURL());
01190 break;
01191 }
01192 finished ();
01193 }
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210 void
01211 IMAP4Protocol::special (const QByteArray & aData)
01212 {
01213 kdDebug(7116) << "IMAP4Protocol::special" << endl;
01214 if (!makeLogin()) return;
01215
01216 QDataStream stream(aData, IO_ReadOnly);
01217
01218 int tmp;
01219 stream >> tmp;
01220
01221 switch (tmp) {
01222 case 'C':
01223 {
01224
01225 KURL src;
01226 KURL dest;
01227 stream >> src >> dest;
01228 copy(src, dest, 0, FALSE);
01229 break;
01230 }
01231 case 'c':
01232 {
01233
01234 infoMessage(imapCapabilities.join(" "));
01235 finished();
01236 break;
01237 }
01238 case 'N':
01239 {
01240
01241 imapCommand *cmd = doCommand(imapCommand::clientNoop());
01242 if (cmd->result () != "OK")
01243 {
01244 kdDebug(7116) << "NOOP did not succeed - connection broken" << endl;
01245 completeQueue.removeRef (cmd);
01246 error (ERR_CONNECTION_BROKEN, myHost);
01247 return;
01248 }
01249 completeQueue.removeRef (cmd);
01250 finished();
01251 break;
01252 }
01253 case 'n':
01254 {
01255
01256
01257 infoMessage( imapNamespaces.join(",") );
01258 finished();
01259 break;
01260 }
01261 case 'U':
01262 {
01263
01264 KURL _url;
01265 stream >> _url;
01266 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01267 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01268 imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
01269 if (cmd->result () != "OK")
01270 {
01271 completeQueue.removeRef (cmd);
01272 error(ERR_SLAVE_DEFINED, i18n("Unsubscribe of folder %1 "
01273 "failed. The server returned: %2")
01274 .arg(_url.prettyURL())
01275 .arg(cmd->resultInfo()));
01276 return;
01277 }
01278 completeQueue.removeRef (cmd);
01279 finished();
01280 break;
01281 }
01282 case 'u':
01283 {
01284
01285 KURL _url;
01286 stream >> _url;
01287 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01288 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01289 imapCommand *cmd = doCommand(imapCommand::clientSubscribe(aBox));
01290 if (cmd->result () != "OK")
01291 {
01292 completeQueue.removeRef (cmd);
01293 error(ERR_SLAVE_DEFINED, i18n("Subscribe of folder %1 "
01294 "failed. The server returned: %2")
01295 .arg(_url.prettyURL())
01296 .arg(cmd->resultInfo()));
01297 return;
01298 }
01299 completeQueue.removeRef (cmd);
01300 finished();
01301 break;
01302 }
01303 case 'A':
01304 {
01305
01306 int cmd;
01307 stream >> cmd;
01308 if ( hasCapability( "ACL" ) ) {
01309 specialACLCommand( cmd, stream );
01310 } else {
01311 error( ERR_UNSUPPORTED_ACTION, "ACL" );
01312 }
01313 break;
01314 }
01315 case 'M':
01316 {
01317
01318 int cmd;
01319 stream >> cmd;
01320 if ( hasCapability( "ANNOTATEMORE" ) ) {
01321 specialAnnotateMoreCommand( cmd, stream );
01322 } else {
01323 error( ERR_UNSUPPORTED_ACTION, "ANNOTATEMORE" );
01324 }
01325 break;
01326 }
01327 case 'Q':
01328 {
01329
01330 int cmd;
01331 stream >> cmd;
01332 if ( hasCapability( "QUOTA" ) ) {
01333 specialQuotaCommand( cmd, stream );
01334 } else {
01335 error( ERR_UNSUPPORTED_ACTION, "QUOTA" );
01336 }
01337 break;
01338 }
01339 case 'S':
01340 {
01341
01342 KURL _url;
01343 QCString newFlags;
01344 stream >> _url >> newFlags;
01345
01346 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01347 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01348 if (!assureBox(aBox, false)) return;
01349 imapCommand *cmd = doCommand (imapCommand::
01350 clientStore (aSequence, "-FLAGS.SILENT",
01351 "\\SEEN \\ANSWERED \\FLAGGED \\DRAFT"));
01352 if (cmd->result () != "OK")
01353 {
01354 completeQueue.removeRef (cmd);
01355 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01356 "failed.").arg(_url.prettyURL()));
01357 return;
01358 }
01359 completeQueue.removeRef (cmd);
01360 if (!newFlags.isEmpty())
01361 {
01362 cmd = doCommand (imapCommand::
01363 clientStore (aSequence, "+FLAGS.SILENT", newFlags));
01364 if (cmd->result () != "OK")
01365 {
01366 completeQueue.removeRef (cmd);
01367 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01368 "failed.").arg(_url.prettyURL()));
01369 return;
01370 }
01371 completeQueue.removeRef (cmd);
01372 }
01373 finished();
01374 break;
01375 }
01376 case 's':
01377 {
01378
01379 KURL _url;
01380 bool seen;
01381 QCString newFlags;
01382 stream >> _url >> seen;
01383
01384 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01385 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01386 if ( !assureBox(aBox, true) )
01387 return;
01388
01389 imapCommand *cmd;
01390 if ( seen )
01391 cmd = doCommand( imapCommand::clientStore( aSequence, "+FLAGS.SILENT", "\\SEEN" ) );
01392 else
01393 cmd = doCommand( imapCommand::clientStore( aSequence, "-FLAGS.SILENT", "\\SEEN" ) );
01394
01395 if (cmd->result () != "OK")
01396 {
01397 completeQueue.removeRef (cmd);
01398 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01399 "failed.").arg(_url.prettyURL()));
01400 return;
01401 }
01402 completeQueue.removeRef (cmd);
01403 finished();
01404 break;
01405 }
01406
01407 case 'E':
01408 {
01409
01410 specialSearchCommand( stream );
01411 break;
01412 }
01413 default:
01414 kdWarning(7116) << "Unknown command in special(): " << tmp << endl;
01415 error( ERR_UNSUPPORTED_ACTION, QString(QChar(tmp)) );
01416 break;
01417 }
01418 }
01419
01420 void
01421 IMAP4Protocol::specialACLCommand( int command, QDataStream& stream )
01422 {
01423
01424 KURL _url;
01425 stream >> _url;
01426 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01427 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01428
01429 switch( command ) {
01430 case 'S':
01431 {
01432 QString user, acl;
01433 stream >> user >> acl;
01434 kdDebug(7116) << "SETACL " << aBox << " " << user << " " << acl << endl;
01435 imapCommand *cmd = doCommand(imapCommand::clientSetACL(aBox, user, acl));
01436 if (cmd->result () != "OK")
01437 {
01438 error(ERR_SLAVE_DEFINED, i18n("Setting the Access Control List on folder %1 "
01439 "for user %2 failed. The server returned: %3")
01440 .arg(_url.prettyURL())
01441 .arg(user)
01442 .arg(cmd->resultInfo()));
01443 return;
01444 }
01445 completeQueue.removeRef (cmd);
01446 finished();
01447 break;
01448 }
01449 case 'D':
01450 {
01451 QString user;
01452 stream >> user;
01453 kdDebug(7116) << "DELETEACL " << aBox << " " << user << endl;
01454 imapCommand *cmd = doCommand(imapCommand::clientDeleteACL(aBox, user));
01455 if (cmd->result () != "OK")
01456 {
01457 error(ERR_SLAVE_DEFINED, i18n("Deleting the Access Control List on folder %1 "
01458 "for user %2 failed. The server returned: %3")
01459 .arg(_url.prettyURL())
01460 .arg(user)
01461 .arg(cmd->resultInfo()));
01462 return;
01463 }
01464 completeQueue.removeRef (cmd);
01465 finished();
01466 break;
01467 }
01468 case 'G':
01469 {
01470 kdDebug(7116) << "GETACL " << aBox << endl;
01471 imapCommand *cmd = doCommand(imapCommand::clientGetACL(aBox));
01472 if (cmd->result () != "OK")
01473 {
01474 error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
01475 "failed. The server returned: %2")
01476 .arg(_url.prettyURL())
01477 .arg(cmd->resultInfo()));
01478 return;
01479 }
01480
01481
01482
01483
01484 kdDebug(7116) << getResults() << endl;
01485 infoMessage(getResults().join( " " ));
01486 finished();
01487 break;
01488 }
01489 case 'L':
01490 {
01491
01492 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
01493 break;
01494 }
01495 case 'M':
01496 {
01497 kdDebug(7116) << "MYRIGHTS " << aBox << endl;
01498 imapCommand *cmd = doCommand(imapCommand::clientMyRights(aBox));
01499 if (cmd->result () != "OK")
01500 {
01501 error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
01502 "failed. The server returned: %2")
01503 .arg(_url.prettyURL())
01504 .arg(cmd->resultInfo()));
01505 return;
01506 }
01507 QStringList lst = getResults();
01508 kdDebug(7116) << "myrights results: " << lst << endl;
01509 if ( !lst.isEmpty() ) {
01510 Q_ASSERT( lst.count() == 1 );
01511 infoMessage( lst.first() );
01512 }
01513 finished();
01514 break;
01515 }
01516 default:
01517 kdWarning(7116) << "Unknown special ACL command:" << command << endl;
01518 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
01519 }
01520 }
01521
01522 void
01523 IMAP4Protocol::specialSearchCommand( QDataStream& stream )
01524 {
01525 kdDebug(7116) << "IMAP4Protocol::specialSearchCommand" << endl;
01526 KURL _url;
01527 stream >> _url;
01528 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01529 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01530 if (!assureBox(aBox, false)) return;
01531
01532 imapCommand *cmd = doCommand (imapCommand::clientSearch( aSection ));
01533 if (cmd->result () != "OK")
01534 {
01535 error(ERR_SLAVE_DEFINED, i18n("Searching of folder %1 "
01536 "failed. The server returned: %2")
01537 .arg(aBox)
01538 .arg(cmd->resultInfo()));
01539 return;
01540 }
01541 completeQueue.removeRef(cmd);
01542 QStringList lst = getResults();
01543 kdDebug(7116) << "IMAP4Protocol::specialSearchCommand '" << aSection <<
01544 "' returns " << lst << endl;
01545 infoMessage( lst.join( " " ) );
01546
01547 finished();
01548 }
01549
01550 void
01551 IMAP4Protocol::specialAnnotateMoreCommand( int command, QDataStream& stream )
01552 {
01553
01554 KURL _url;
01555 stream >> _url;
01556 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01557 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01558
01559 switch( command ) {
01560 case 'S':
01561 {
01562
01563
01564
01565
01566 QString entry;
01567 QMap<QString, QString> attributes;
01568 stream >> entry >> attributes;
01569 kdDebug(7116) << "SETANNOTATION " << aBox << " " << entry << " " << attributes.count() << " attributes" << endl;
01570 imapCommand *cmd = doCommand(imapCommand::clientSetAnnotation(aBox, entry, attributes));
01571 if (cmd->result () != "OK")
01572 {
01573 error(ERR_SLAVE_DEFINED, i18n("Setting the annotation %1 on folder %2 "
01574 " failed. The server returned: %3")
01575 .arg(entry)
01576 .arg(_url.prettyURL())
01577 .arg(cmd->resultInfo()));
01578 return;
01579 }
01580 completeQueue.removeRef (cmd);
01581 finished();
01582 break;
01583 }
01584 case 'G':
01585 {
01586
01587
01588
01589
01590 QString entry;
01591 QStringList attributeNames;
01592 stream >> entry >> attributeNames;
01593 kdDebug(7116) << "GETANNOTATION " << aBox << " " << entry << " " << attributeNames << endl;
01594 imapCommand *cmd = doCommand(imapCommand::clientGetAnnotation(aBox, entry, attributeNames));
01595 if (cmd->result () != "OK")
01596 {
01597 error(ERR_SLAVE_DEFINED, i18n("Retrieving the annotation %1 on folder %2 "
01598 "failed. The server returned: %3")
01599 .arg(entry)
01600 .arg(_url.prettyURL())
01601 .arg(cmd->resultInfo()));
01602 return;
01603 }
01604
01605
01606
01607 kdDebug(7116) << getResults() << endl;
01608 infoMessage(getResults().join( "\r" ));
01609 finished();
01610 break;
01611 }
01612 default:
01613 kdWarning(7116) << "Unknown special annotate command:" << command << endl;
01614 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
01615 }
01616 }
01617
01618 void
01619 IMAP4Protocol::specialQuotaCommand( int command, QDataStream& stream )
01620 {
01621
01622 KURL _url;
01623 stream >> _url;
01624 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01625 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01626
01627 switch( command ) {
01628 case 'R':
01629 {
01630 kdDebug(7116) << "QUOTAROOT " << aBox << endl;
01631 imapCommand *cmd = doCommand(imapCommand::clientGetQuotaroot( aBox ) );
01632 if (cmd->result () != "OK")
01633 {
01634 error(ERR_SLAVE_DEFINED, i18n("Retrieving the quota root information on folder %1 "
01635 "failed. The server returned: %2")
01636 .arg(_url.prettyURL())
01637 .arg(cmd->resultInfo()));
01638 return;
01639 }
01640 infoMessage(getResults().join( "\r" ));
01641 finished();
01642 break;
01643 }
01644 case 'G':
01645 {
01646 kdDebug(7116) << "GETQUOTA command" << endl;
01647 kdWarning(7116) << "UNIMPLEMENTED" << endl;
01648 break;
01649 }
01650 case 'S':
01651 {
01652 kdDebug(7116) << "SETQUOTA command" << endl;
01653 kdWarning(7116) << "UNIMPLEMENTED" << endl;
01654 break;
01655 }
01656 default:
01657 kdWarning(7116) << "Unknown special quota command:" << command << endl;
01658 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
01659 }
01660 }
01661
01662 void
01663 IMAP4Protocol::rename (const KURL & src, const KURL & dest, bool overwrite)
01664 {
01665 kdDebug(7116) << "IMAP4::rename - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
01666 QString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
01667 QString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
01668 enum IMAP_TYPE sType =
01669 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo, false);
01670 enum IMAP_TYPE dType =
01671 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo, false);
01672
01673 if (dType == ITYPE_UNKNOWN)
01674 {
01675 switch (sType)
01676 {
01677 case ITYPE_BOX:
01678 case ITYPE_DIR:
01679 case ITYPE_DIR_AND_BOX:
01680 {
01681 if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
01682 {
01683 kdDebug(7116) << "IMAP4::rename - close " << getCurrentBox() << endl;
01684
01685 imapCommand *cmd = doCommand (imapCommand::clientClose());
01686 bool ok = cmd->result() == "OK";
01687 completeQueue.removeRef(cmd);
01688 if (!ok)
01689 {
01690 error(ERR_CANNOT_RENAME, i18n("Unable to close mailbox."));
01691 return;
01692 }
01693 setState(ISTATE_LOGIN);
01694 }
01695 imapCommand *cmd = doCommand (imapCommand::clientRename (sBox, dBox));
01696 if (cmd->result () != "OK") {
01697 error (ERR_CANNOT_RENAME, cmd->result ());
01698 completeQueue.removeRef (cmd);
01699 return;
01700 }
01701 completeQueue.removeRef (cmd);
01702 }
01703 break;
01704
01705 case ITYPE_MSG:
01706 case ITYPE_ATTACH:
01707 case ITYPE_UNKNOWN:
01708 error (ERR_CANNOT_RENAME, src.prettyURL());
01709 break;
01710 }
01711 }
01712 else
01713 {
01714 error (ERR_CANNOT_RENAME, src.prettyURL());
01715 return;
01716 }
01717 finished ();
01718 }
01719
01720 void
01721 IMAP4Protocol::slave_status ()
01722 {
01723 bool connected = (getState() != ISTATE_NO) && isConnectionValid();
01724 kdDebug(7116) << "IMAP4::slave_status " << connected << endl;
01725 slaveStatus ( connected ? myHost : QString::null, connected );
01726 }
01727
01728 void
01729 IMAP4Protocol::dispatch (int command, const QByteArray & data)
01730 {
01731 kdDebug(7116) << "IMAP4::dispatch - command=" << command << endl;
01732 KIO::TCPSlaveBase::dispatch (command, data);
01733 }
01734
01735 void
01736 IMAP4Protocol::stat (const KURL & _url)
01737 {
01738 kdDebug(7116) << "IMAP4::stat - " << _url.prettyURL() << endl;
01739 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01740
01741 enum IMAP_TYPE aType =
01742 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
01743 aInfo, true);
01744
01745 UDSEntry entry;
01746 UDSAtom atom;
01747
01748 atom.m_uds = UDS_NAME;
01749 atom.m_str = aBox;
01750 entry.append (atom);
01751
01752 if (!aSection.isEmpty())
01753 {
01754 if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
01755 {
01756 imapCommand *cmd = doCommand (imapCommand::clientClose());
01757 bool ok = cmd->result() == "OK";
01758 completeQueue.removeRef(cmd);
01759 if (!ok)
01760 {
01761 error(ERR_COULD_NOT_STAT, aBox);
01762 return;
01763 }
01764 setState(ISTATE_LOGIN);
01765 }
01766 bool ok = false;
01767 QString cmdInfo;
01768 if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
01769 ok = true;
01770 else
01771 {
01772 imapCommand *cmd = doCommand(imapCommand::clientStatus(aBox, aSection));
01773 ok = cmd->result() == "OK";
01774 cmdInfo = cmd->resultInfo();
01775 completeQueue.removeRef(cmd);
01776 }
01777 if (!ok)
01778 {
01779 bool found = false;
01780 imapCommand *cmd = doCommand (imapCommand::clientList ("", aBox));
01781 if (cmd->result () == "OK")
01782 {
01783 for (QValueListIterator < imapList > it = listResponses.begin ();
01784 it != listResponses.end (); ++it)
01785 {
01786 if (aBox == (*it).name ()) found = true;
01787 }
01788 }
01789 completeQueue.removeRef (cmd);
01790 if (found)
01791 error(ERR_COULD_NOT_STAT, aBox);
01792 else
01793 error(KIO::ERR_DOES_NOT_EXIST, aBox);
01794 return;
01795 }
01796 if ((aSection == "UIDNEXT" && getStatus().uidNextAvailable())
01797 || (aSection == "UNSEEN" && getStatus().unseenAvailable()))
01798 {
01799 atom.m_uds = UDS_SIZE;
01800 atom.m_str = QString::null;
01801 atom.m_long = (aSection == "UIDNEXT") ? getStatus().uidNext()
01802 : getStatus().unseen();
01803 entry.append(atom);
01804 }
01805 } else
01806 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
01807 aType == ITYPE_ATTACH)
01808 {
01809 ulong validity = 0;
01810
01811 if (aBox == getCurrentBox ())
01812 validity = selectInfo.uidValidity ();
01813 else
01814 {
01815
01816
01817
01818 imapCommand *cmd =
01819 doCommand (imapCommand::clientStatus (aBox, "UIDVALIDITY"));
01820 completeQueue.removeRef (cmd);
01821 validity = getStatus ().uidValidity ();
01822 }
01823 validity = 0;
01824
01825 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
01826 {
01827
01828 if (validity > 0 && validity != aValidity.toULong ())
01829 {
01830
01831 KURL newUrl = _url;
01832
01833 newUrl.setPath ("/" + aBox + ";UIDVALIDITY=" +
01834 QString::number(validity));
01835 kdDebug(7116) << "IMAP4::stat - redirecting to " << newUrl.prettyURL() << endl;
01836 redirection (newUrl);
01837 }
01838 }
01839 else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
01840 {
01841
01842
01843
01844
01845
01846 if (validity > 0 && validity != aValidity.toULong ())
01847 {
01848 aType = ITYPE_UNKNOWN;
01849 kdDebug(7116) << "IMAP4::stat - url has invalid validity [" << validity << "d] " << _url.prettyURL() << endl;
01850 }
01851 }
01852 }
01853
01854 atom.m_uds = UDS_MIME_TYPE;
01855 atom.m_str = getMimeType (aType);
01856 entry.append (atom);
01857
01858 kdDebug(7116) << "IMAP4: stat: " << atom.m_str << endl;
01859 switch (aType)
01860 {
01861 case ITYPE_DIR:
01862 atom.m_uds = UDS_FILE_TYPE;
01863 atom.m_str = QString::null;
01864 atom.m_long = S_IFDIR;
01865 entry.append (atom);
01866 break;
01867
01868 case ITYPE_BOX:
01869 case ITYPE_DIR_AND_BOX:
01870 atom.m_uds = UDS_FILE_TYPE;
01871 atom.m_str = QString::null;
01872 atom.m_long = S_IFDIR;
01873 entry.append (atom);
01874 break;
01875
01876 case ITYPE_MSG:
01877 case ITYPE_ATTACH:
01878 atom.m_uds = UDS_FILE_TYPE;
01879 atom.m_str = QString::null;
01880 atom.m_long = S_IFREG;
01881 entry.append (atom);
01882 break;
01883
01884 case ITYPE_UNKNOWN:
01885 error (ERR_DOES_NOT_EXIST, _url.prettyURL());
01886 break;
01887 }
01888
01889 statEntry (entry);
01890 kdDebug(7116) << "IMAP4::stat - Finishing stat" << endl;
01891 finished ();
01892 }
01893
01894 void IMAP4Protocol::openConnection()
01895 {
01896 if (makeLogin()) connected();
01897 }
01898
01899 void IMAP4Protocol::closeConnection()
01900 {
01901 if (getState() == ISTATE_NO) return;
01902 if (getState() == ISTATE_SELECT && metaData("expunge") == "auto")
01903 {
01904 imapCommand *cmd = doCommand (imapCommand::clientExpunge());
01905 completeQueue.removeRef (cmd);
01906 }
01907 if (getState() != ISTATE_CONNECT)
01908 {
01909 imapCommand *cmd = doCommand (imapCommand::clientLogout());
01910 completeQueue.removeRef (cmd);
01911 }
01912 closeDescriptor();
01913 setState(ISTATE_NO);
01914 completeQueue.clear();
01915 sentQueue.clear();
01916 lastHandled = 0;
01917 currentBox = QString::null;
01918 readBufferLen = 0;
01919 }
01920
01921 bool IMAP4Protocol::makeLogin ()
01922 {
01923 if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
01924 return true;
01925
01926 kdDebug(7116) << "IMAP4::makeLogin - checking login" << endl;
01927 bool alreadyConnected = getState() == ISTATE_CONNECT;
01928 kdDebug(7116) << "IMAP4::makeLogin - alreadyConnected " << alreadyConnected << endl;
01929 if (alreadyConnected || connectToHost (myHost.latin1(), myPort))
01930 {
01931
01932
01933 setState(ISTATE_CONNECT);
01934
01935 myAuth = metaData("auth");
01936 myTLS = metaData("tls");
01937 kdDebug(7116) << "myAuth: " << myAuth << endl;
01938
01939 imapCommand *cmd;
01940
01941 unhandled.clear ();
01942 if (!alreadyConnected) while (!parseLoop ());
01943 QString greeting;
01944 if (!unhandled.isEmpty()) greeting = unhandled.first().stripWhiteSpace();
01945 unhandled.clear ();
01946 cmd = doCommand (new imapCommand ("CAPABILITY", ""));
01947
01948 kdDebug(7116) << "IMAP4: setHost: capability" << endl;
01949 for (QStringList::Iterator it = imapCapabilities.begin ();
01950 it != imapCapabilities.end (); ++it)
01951 {
01952 kdDebug(7116) << "'" << (*it) << "'" << endl;
01953 }
01954 completeQueue.removeRef (cmd);
01955
01956 if (!hasCapability("IMAP4") && !hasCapability("IMAP4rev1"))
01957 {
01958 error(ERR_COULD_NOT_LOGIN, i18n("The server %1 supports neither "
01959 "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2")
01960 .arg(myHost).arg(greeting));
01961 closeConnection();
01962 return false;
01963 }
01964
01965 if (metaData("nologin") == "on") return TRUE;
01966
01967 if (myTLS == "on" && !hasCapability(QString("STARTTLS")))
01968 {
01969 error(ERR_COULD_NOT_LOGIN, i18n("The server does not support TLS.\n"
01970 "Disable this security feature to connect unencrypted."));
01971 closeConnection();
01972 return false;
01973 }
01974 if ((myTLS == "on" || (canUseTLS() && myTLS != "off")) &&
01975 hasCapability(QString("STARTTLS")))
01976 {
01977 imapCommand *cmd = doCommand (imapCommand::clientStartTLS());
01978 if (cmd->result () == "OK")
01979 {
01980 completeQueue.removeRef(cmd);
01981 int tlsrc = startTLS();
01982 if (tlsrc == 1)
01983 {
01984 kdDebug(7116) << "TLS mode has been enabled." << endl;
01985 imapCommand *cmd2 = doCommand (new imapCommand ("CAPABILITY", ""));
01986 for (QStringList::Iterator it = imapCapabilities.begin ();
01987 it != imapCapabilities.end (); ++it)
01988 {
01989 kdDebug(7116) << "'" << (*it) << "'" << endl;
01990 }
01991 completeQueue.removeRef (cmd2);
01992 } else {
01993 kdWarning(7116) << "TLS mode setup has failed. Aborting." << endl;
01994 error (ERR_COULD_NOT_LOGIN, i18n("Starting TLS failed."));
01995 closeConnection();
01996 return false;
01997 }
01998 } else completeQueue.removeRef(cmd);
01999 }
02000
02001 if (myAuth.isEmpty () || myAuth == "*") {
02002 if (hasCapability (QString ("LOGINDISABLED"))) {
02003 error (ERR_COULD_NOT_LOGIN, i18n("LOGIN is disabled by the server."));
02004 closeConnection();
02005 return false;
02006 }
02007 }
02008 else {
02009 if (!hasCapability (QString ("AUTH=") + myAuth)) {
02010 error (ERR_COULD_NOT_LOGIN, i18n("The authentication method %1 is not "
02011 "supported by the server.").arg(myAuth));
02012 closeConnection();
02013 return false;
02014 }
02015 }
02016
02017 if ( greeting.contains( QRegExp( "Cyrus IMAP4 v2.1" ) ) ) {
02018 removeCapability( "ANNOTATEMORE" );
02019 }
02020
02021 kdDebug(7116) << "IMAP4::makeLogin - attempting login" << endl;
02022
02023 KIO::AuthInfo authInfo;
02024 authInfo.username = myUser;
02025 authInfo.password = myPass;
02026 authInfo.prompt = i18n ("Username and password for your IMAP account:");
02027
02028 kdDebug(7116) << "IMAP4::makeLogin - open_PassDlg said user=" << myUser << " pass=xx" << endl;
02029
02030 QString resultInfo;
02031 if (myAuth.isEmpty () || myAuth == "*")
02032 {
02033 if (myUser.isEmpty () || myPass.isEmpty ()) {
02034 if(openPassDlg (authInfo)) {
02035 myUser = authInfo.username;
02036 myPass = authInfo.password;
02037 }
02038 }
02039 if (!clientLogin (myUser, myPass, resultInfo))
02040 error(KIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to login. Probably the "
02041 "password is wrong.\nThe server %1 replied:\n%2").arg(myHost).arg(resultInfo));
02042 }
02043 else
02044 {
02045 #ifdef HAVE_LIBSASL2
02046 if (!clientAuthenticate (this, authInfo, myHost, myAuth, mySSL, resultInfo))
02047 error(KIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to authenticate via %1.\n"
02048 "The server %2 replied:\n%3").arg(myAuth).arg(myHost).arg(resultInfo));
02049 else {
02050 myUser = authInfo.username;
02051 myPass = authInfo.password;
02052 }
02053 #else
02054 error(KIO::ERR_COULD_NOT_LOGIN, i18n("SASL authentication is not compiled into kio_imap4."));
02055 #endif
02056 }
02057 if ( hasCapability("NAMESPACE") )
02058 {
02059
02060 cmd = doCommand( imapCommand::clientNamespace() );
02061 if (cmd->result () == "OK")
02062 {
02063 kdDebug(7116) << "makeLogin - registered namespaces" << endl;
02064 }
02065 completeQueue.removeRef (cmd);
02066 }
02067
02068 cmd = doCommand( imapCommand::clientList("", "") );
02069 if (cmd->result () == "OK")
02070 {
02071 QValueListIterator < imapList > it = listResponses.begin();
02072 if ( it == listResponses.end() )
02073 {
02074
02075
02076 completeQueue.removeRef (cmd);
02077 cmd = doCommand( imapCommand::clientList("", "%") );
02078 if (cmd->result () == "OK")
02079 {
02080 it = listResponses.begin();
02081 }
02082 }
02083 if ( it != listResponses.end() )
02084 {
02085 namespaceToDelimiter[QString::null] = (*it).hierarchyDelimiter();
02086 kdDebug(7116) << "makeLogin - delimiter for empty ns='" <<
02087 (*it).hierarchyDelimiter() << "'" << endl;
02088 if ( !hasCapability("NAMESPACE") )
02089 {
02090
02091 QString nsentry = QString::number( 0 ) + "=="
02092 + (*it).hierarchyDelimiter();
02093 imapNamespaces.append( nsentry );
02094 }
02095 }
02096 }
02097 completeQueue.removeRef (cmd);
02098 } else {
02099 kdDebug(7116) << "makeLogin - NO login" << endl;
02100 }
02101
02102 return getState() == ISTATE_LOGIN;
02103 }
02104
02105 void
02106 IMAP4Protocol::parseWriteLine (const QString & aStr)
02107 {
02108
02109 QCString writer = aStr.utf8();
02110 int len = writer.length();
02111
02112
02113 if (len == 0 || (writer[len - 1] != '\n')) {
02114 len += 2;
02115 writer += "\r\n";
02116 }
02117
02118
02119 write(writer.data(), len);
02120 }
02121
02122 QString
02123 IMAP4Protocol::getMimeType (enum IMAP_TYPE aType)
02124 {
02125 switch (aType)
02126 {
02127 case ITYPE_DIR:
02128 return "inode/directory";
02129 break;
02130
02131 case ITYPE_BOX:
02132 return "message/digest";
02133 break;
02134
02135 case ITYPE_DIR_AND_BOX:
02136 return "message/directory";
02137 break;
02138
02139 case ITYPE_MSG:
02140 return "message/rfc822";
02141 break;
02142
02143
02144 case ITYPE_ATTACH:
02145 return "application/octet-stream";
02146 break;
02147
02148 case ITYPE_UNKNOWN:
02149 default:
02150 return "unknown/unknown";
02151 }
02152 }
02153
02154
02155
02156 void
02157 IMAP4Protocol::doListEntry (const KURL & _url, int stretch, imapCache * cache,
02158 bool withFlags, bool withSubject)
02159 {
02160 KURL aURL = _url;
02161 aURL.setQuery (QString::null);
02162 const QString encodedUrl = aURL.url(0, 106);
02163 doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
02164 }
02165
02166
02167
02168 void
02169 IMAP4Protocol::doListEntry (const QString & encodedUrl, int stretch, imapCache * cache,
02170 bool withFlags, bool withSubject)
02171 {
02172 if (cache)
02173 {
02174 UDSEntry entry;
02175 UDSAtom atom;
02176
02177 entry.clear ();
02178
02179 const QString uid = QString::number(cache->getUid());
02180
02181 atom.m_uds = UDS_NAME;
02182 atom.m_str = uid;
02183 atom.m_long = 0;
02184 if (stretch > 0)
02185 {
02186 atom.m_str = "0000000000000000" + atom.m_str;
02187 atom.m_str = atom.m_str.right (stretch);
02188 }
02189 if (withSubject)
02190 {
02191 mailHeader *header = cache->getHeader();
02192 if (header)
02193 atom.m_str += " " + header->getSubject();
02194 }
02195 entry.append (atom);
02196
02197 atom.m_uds = UDS_URL;
02198 atom.m_str = encodedUrl;
02199 if (atom.m_str[atom.m_str.length () - 1] != '/')
02200 atom.m_str += '/';
02201 atom.m_str += ";UID=" + uid;
02202 atom.m_long = 0;
02203 entry.append (atom);
02204
02205 atom.m_uds = UDS_FILE_TYPE;
02206 atom.m_str = QString::null;
02207 atom.m_long = S_IFREG;
02208 entry.append (atom);
02209
02210 atom.m_uds = UDS_SIZE;
02211 atom.m_long = cache->getSize();
02212 entry.append (atom);
02213
02214 atom.m_uds = UDS_MIME_TYPE;
02215 atom.m_str = "message/rfc822";
02216 atom.m_long = 0;
02217 entry.append (atom);
02218
02219 atom.m_uds = UDS_USER;
02220 atom.m_str = myUser;
02221 entry.append (atom);
02222
02223 atom.m_uds = KIO::UDS_ACCESS;
02224 atom.m_long = (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR;
02225 entry.append (atom);
02226
02227 listEntry (entry, false);
02228 }
02229 }
02230
02231 void
02232 IMAP4Protocol::doListEntry (const KURL & _url, const QString & myBox,
02233 const imapList & item, bool appendPath)
02234 {
02235 KURL aURL = _url;
02236 aURL.setQuery (QString::null);
02237 UDSEntry entry;
02238 UDSAtom atom;
02239 int hdLen = item.hierarchyDelimiter().length();
02240
02241 {
02242
02243 QString mailboxName = item.name ();
02244
02245
02246 if (mailboxName.find (myBox) == 0 && mailboxName.length() > myBox.length())
02247 {
02248 mailboxName =
02249 mailboxName.right (mailboxName.length () - myBox.length ());
02250 }
02251 if (mailboxName[0] == '/')
02252 mailboxName = mailboxName.right (mailboxName.length () - 1);
02253 if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
02254 mailboxName = mailboxName.right(mailboxName.length () - hdLen);
02255 if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
02256 mailboxName.truncate(mailboxName.length () - hdLen);
02257
02258 atom.m_uds = UDS_NAME;
02259 if (!item.hierarchyDelimiter().isEmpty() &&
02260 mailboxName.find(item.hierarchyDelimiter()) != -1)
02261 atom.m_str = mailboxName.section(item.hierarchyDelimiter(), -1);
02262 else
02263 atom.m_str = mailboxName;
02264
02265
02266 if (atom.m_str.isEmpty ())
02267 atom.m_str = "..";
02268
02269 if (!atom.m_str.isEmpty ())
02270 {
02271 atom.m_long = 0;
02272 entry.append (atom);
02273
02274 if (!item.noSelect ())
02275 {
02276 atom.m_uds = UDS_MIME_TYPE;
02277 if (!item.noInferiors ())
02278 {
02279 atom.m_str = "message/directory";
02280 } else {
02281 atom.m_str = "message/digest";
02282 }
02283 atom.m_long = 0;
02284 entry.append (atom);
02285 mailboxName += '/';
02286
02287
02288 atom.m_uds = UDS_FILE_TYPE;
02289 atom.m_str = QString::null;
02290 atom.m_long = S_IFDIR;
02291 entry.append (atom);
02292 }
02293 else if (!item.noInferiors ())
02294 {
02295 atom.m_uds = UDS_MIME_TYPE;
02296 atom.m_str = "inode/directory";
02297 atom.m_long = 0;
02298 entry.append (atom);
02299 mailboxName += '/';
02300
02301
02302 atom.m_uds = UDS_FILE_TYPE;
02303 atom.m_str = QString::null;
02304 atom.m_long = S_IFDIR;
02305 entry.append (atom);
02306 }
02307 else
02308 {
02309 atom.m_uds = UDS_MIME_TYPE;
02310 atom.m_str = "unknown/unknown";
02311 atom.m_long = 0;
02312 entry.append (atom);
02313 }
02314
02315 atom.m_uds = UDS_URL;
02316 QString path = aURL.path();
02317 atom.m_str = aURL.url (0, 106);
02318 if (appendPath)
02319 {
02320 if (path[path.length() - 1] == '/' && !path.isEmpty() && path != "/")
02321 path.truncate(path.length() - 1);
02322 if (!path.isEmpty() && path != "/"
02323 && path.right(hdLen) != item.hierarchyDelimiter()) {
02324 path += item.hierarchyDelimiter();
02325 }
02326 path += mailboxName;
02327 if (path.upper() == "/INBOX/") {
02328
02329 path = path.upper();
02330 }
02331 }
02332 aURL.setPath(path);
02333 atom.m_str = aURL.url(0, 106);
02334 atom.m_long = 0;
02335 entry.append (atom);
02336
02337 atom.m_uds = UDS_USER;
02338 atom.m_str = myUser;
02339 entry.append (atom);
02340
02341 atom.m_uds = UDS_ACCESS;
02342 atom.m_long = S_IRUSR | S_IXUSR | S_IWUSR;
02343 entry.append (atom);
02344
02345 atom.m_uds = UDS_EXTRA;
02346 atom.m_str = item.attributesAsString();
02347 atom.m_long = 0;
02348 entry.append (atom);
02349
02350 listEntry (entry, false);
02351 }
02352 }
02353 }
02354
02355 enum IMAP_TYPE
02356 IMAP4Protocol::parseURL (const KURL & _url, QString & _box,
02357 QString & _section, QString & _type, QString & _uid,
02358 QString & _validity, QString & _hierarchyDelimiter,
02359 QString & _info, bool cache)
02360 {
02361 enum IMAP_TYPE retVal;
02362 retVal = ITYPE_UNKNOWN;
02363
02364 imapParser::parseURL (_url, _box, _section, _type, _uid, _validity, _info);
02365
02366
02367
02368 QString myNamespace = namespaceForBox( _box );
02369 kdDebug(7116) << "IMAP4::parseURL - namespace=" << myNamespace << endl;
02370 if ( namespaceToDelimiter.contains(myNamespace) )
02371 {
02372 _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
02373 kdDebug(7116) << "IMAP4::parseURL - delimiter=" << _hierarchyDelimiter << endl;
02374 }
02375
02376 if (!_box.isEmpty ())
02377 {
02378 kdDebug(7116) << "IMAP4::parseURL - box=" << _box << endl;
02379
02380 if (makeLogin ())
02381 {
02382 if (getCurrentBox () != _box ||
02383 _type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK")
02384 {
02385 if ( cache )
02386 {
02387
02388 retVal = ITYPE_DIR_AND_BOX;
02389 } else
02390 {
02391
02392 imapCommand *cmd;
02393
02394 cmd = doCommand (imapCommand::clientList ("", _box));
02395 if (cmd->result () == "OK")
02396 {
02397 for (QValueListIterator < imapList > it = listResponses.begin ();
02398 it != listResponses.end (); ++it)
02399 {
02400
02401 if (_box == (*it).name ())
02402 {
02403 if ( !(*it).hierarchyDelimiter().isEmpty() )
02404 _hierarchyDelimiter = (*it).hierarchyDelimiter();
02405 if ((*it).noSelect ())
02406 {
02407 retVal = ITYPE_DIR;
02408 }
02409 else if ((*it).noInferiors ())
02410 {
02411 retVal = ITYPE_BOX;
02412 }
02413 else
02414 {
02415 retVal = ITYPE_DIR_AND_BOX;
02416 }
02417 }
02418 }
02419
02420 if ( retVal == ITYPE_UNKNOWN &&
02421 namespaceToDelimiter.contains(_box) ) {
02422 retVal = ITYPE_DIR;
02423 }
02424 } else {
02425 kdDebug(7116) << "IMAP4::parseURL - got error for " << _box << endl;
02426 }
02427 completeQueue.removeRef (cmd);
02428 }
02429 }
02430 else
02431 {
02432 retVal = ITYPE_BOX;
02433 }
02434 }
02435 else
02436 kdDebug(7116) << "IMAP4::parseURL: no login!" << endl;
02437
02438 }
02439 else
02440 {
02441
02442 kdDebug(7116) << "IMAP4: parseURL: box [root]" << endl;
02443 retVal = ITYPE_DIR;
02444 }
02445
02446
02447 if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
02448 {
02449 if (!_uid.isEmpty ())
02450 {
02451 if (_uid.find (':') == -1 && _uid.find (',') == -1
02452 && _uid.find ('*') == -1)
02453 retVal = ITYPE_MSG;
02454 }
02455 }
02456 if (retVal == ITYPE_MSG)
02457 {
02458 if ( (_section.find ("BODY.PEEK[", 0, false) != -1 ||
02459 _section.find ("BODY[", 0, false) != -1) &&
02460 _section.find(".MIME") == -1 &&
02461 _section.find(".HEADER") == -1 )
02462 retVal = ITYPE_ATTACH;
02463 }
02464 if ( _hierarchyDelimiter.isEmpty() &&
02465 (_type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK") )
02466 {
02467
02468
02469 if (!_box.isEmpty())
02470 {
02471 int start = _url.path().findRev(_box);
02472 if (start != -1)
02473 _hierarchyDelimiter = _url.path().mid(start-1, start);
02474 kdDebug(7116) << "IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
02475 << " from URL " << _url.path() << endl;
02476 }
02477 if (_hierarchyDelimiter.isEmpty())
02478 _hierarchyDelimiter = "/";
02479 }
02480 kdDebug(7116) << "IMAP4::parseURL - return " << retVal << endl;
02481
02482 return retVal;
02483 }
02484
02485 int
02486 IMAP4Protocol::outputLine (const QCString & _str, int len)
02487 {
02488 if (len == -1) {
02489 len = _str.length();
02490 }
02491
02492 if (cacheOutput)
02493 {
02494 if ( !outputBuffer.isOpen() ) {
02495 outputBuffer.open(IO_WriteOnly);
02496 }
02497 outputBuffer.at(outputBufferIndex);
02498 outputBuffer.writeBlock(_str.data(), len);
02499 outputBufferIndex += len;
02500 return 0;
02501 }
02502
02503 QByteArray temp;
02504 bool relay = relayEnabled;
02505
02506 relayEnabled = true;
02507 temp.setRawData (_str.data (), len);
02508 parseRelay (temp);
02509 temp.resetRawData (_str.data (), len);
02510
02511 relayEnabled = relay;
02512 return 0;
02513 }
02514
02515 void IMAP4Protocol::flushOutput(QString contentEncoding)
02516 {
02517
02518 if (outputBufferIndex == 0)
02519 return;
02520 outputBuffer.close();
02521 outputCache.resize(outputBufferIndex);
02522 if (decodeContent)
02523 {
02524
02525 QByteArray decoded;
02526 if (contentEncoding.find("quoted-printable", 0, false) == 0)
02527 decoded = KCodecs::quotedPrintableDecode(outputCache);
02528 else if (contentEncoding.find("base64", 0, false) == 0)
02529 KCodecs::base64Decode(outputCache, decoded);
02530 else
02531 decoded = outputCache;
02532
02533 QString mimetype = KMimeType::findByContent( decoded )->name();
02534 kdDebug(7116) << "IMAP4::flushOutput - mimeType " << mimetype << endl;
02535 mimeType(mimetype);
02536 decodeContent = false;
02537 data( decoded );
02538 } else {
02539 data( outputCache );
02540 }
02541 mProcessedSize += outputBufferIndex;
02542 processedSize( mProcessedSize );
02543 outputBufferIndex = 0;
02544 outputCache[0] = '\0';
02545 outputBuffer.setBuffer(outputCache);
02546 }
02547
02548 ssize_t IMAP4Protocol::myRead(void *data, ssize_t len)
02549 {
02550 if (readBufferLen)
02551 {
02552 ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
02553 memcpy(data, readBuffer, copyLen);
02554 readBufferLen -= copyLen;
02555 if (readBufferLen) memcpy(readBuffer, &readBuffer[copyLen], readBufferLen);
02556 return copyLen;
02557 }
02558 if (!isConnectionValid()) return 0;
02559 waitForResponse( responseTimeout() );
02560 return read(data, len);
02561 }
02562
02563 bool
02564 IMAP4Protocol::assureBox (const QString & aBox, bool readonly)
02565 {
02566 if (aBox.isEmpty()) return false;
02567
02568 imapCommand *cmd = 0;
02569
02570 if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
02571 {
02572
02573 kdDebug(7116) << "IMAP4Protocol::assureBox - opening box" << endl;
02574 selectInfo = imapInfo();
02575 cmd = doCommand (imapCommand::clientSelect (aBox, readonly));
02576 bool ok = cmd->result() == "OK";
02577 QString cmdInfo = cmd->resultInfo();
02578 completeQueue.removeRef (cmd);
02579
02580 if (!ok)
02581 {
02582 bool found = false;
02583 cmd = doCommand (imapCommand::clientList ("", aBox));
02584 if (cmd->result () == "OK")
02585 {
02586 for (QValueListIterator < imapList > it = listResponses.begin ();
02587 it != listResponses.end (); ++it)
02588 {
02589 if (aBox == (*it).name ()) found = true;
02590 }
02591 }
02592 completeQueue.removeRef (cmd);
02593 if (found) {
02594 if (cmdInfo.find("permission", 0, false) != -1) {
02595
02596 error(ERR_ACCESS_DENIED, cmdInfo);
02597 } else {
02598 error(ERR_SLAVE_DEFINED, i18n("Unable to open folder %1. The server replied: %2").arg(aBox).arg(cmdInfo));
02599 }
02600 } else {
02601 error(KIO::ERR_DOES_NOT_EXIST, aBox);
02602 }
02603 return false;
02604 }
02605 }
02606 else
02607 {
02608
02609
02610
02611 kdDebug(7116) << "IMAP4Protocol::assureBox - reusing box" << endl;
02612 if ( mTimeOfLastNoop.secsTo( QDateTime::currentDateTime() ) > 10 ) {
02613 cmd = doCommand (imapCommand::clientNoop ());
02614 completeQueue.removeRef (cmd);
02615 mTimeOfLastNoop = QDateTime::currentDateTime();
02616 kdDebug(7116) << "IMAP4Protocol::assureBox - noop timer fired" << endl;
02617 }
02618 }
02619
02620
02621 if (!getSelected().readWrite() && !readonly)
02622 {
02623 error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);
02624 return false;
02625 }
02626
02627 return true;
02628 }