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

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
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.7.1
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