• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

kioslave/imap4

imap4.cpp

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

kioslave/imap4

Skip menu "kioslave/imap4"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal