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

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"
  • 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.5
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