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