summaryrefslogtreecommitdiffstats
path: root/kioslaves/imap4/imap4.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kioslaves/imap4/imap4.cc')
-rw-r--r--kioslaves/imap4/imap4.cc2734
1 files changed, 0 insertions, 2734 deletions
diff --git a/kioslaves/imap4/imap4.cc b/kioslaves/imap4/imap4.cc
deleted file mode 100644
index 6654bb3dd..000000000
--- a/kioslaves/imap4/imap4.cc
+++ /dev/null
@@ -1,2734 +0,0 @@
-/**********************************************************************
- *
- * imap4.cc - IMAP4rev1 KIOSlave
- * Copyright (C) 2001-2002 Michael Haeckel <haeckel@kde.org>
- * Copyright (C) 1999 John Corey
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Send comments and bug fixes to jcorey@fruity.ath.cx
- *
- *********************************************************************/
-
-/**
- * @class IMAP4Protocol
- * @note References:
- * - RFC 2060 - Internet Message Access Protocol - Version 4rev1 - December 1996
- * - RFC 2192 - IMAP URL Scheme - September 1997
- * - RFC 1731 - IMAP Authentication Mechanisms - December 1994
- * (Discusses KERBEROSv4, GSSAPI, and S/Key)
- * - RFC 2195 - IMAP/POP AUTHorize Extension for Simple Challenge/Response
- * - September 1997 (CRAM-MD5 authentication method)
- * - RFC 2104 - HMAC: Keyed-Hashing for Message Authentication - February 1997
- * - RFC 2086 - IMAP4 ACL extension - January 1997
- * - http://www.ietf.org/internet-drafts/draft-daboo-imap-annotatemore-05.txt
- * IMAP ANNOTATEMORE draft - April 2004.
- *
- *
- * Supported URLs:
- * \verbatim
-imap://server/
-imap://user:pass@server/
-imap://user;AUTH=method:pass@server/
-imap://server/folder/
- * \endverbatim
- * These URLs cause the following actions (in order):
- * - Prompt for user/pass, list all folders in home directory
- * - Uses LOGIN to log in
- * - Uses AUTHENTICATE to log in
- * - List messages in folder
- *
- * @note API notes:
- * Not receiving the required write access for a folder means
- * ERR_CANNOT_OPEN_FOR_WRITING.
- * ERR_DOES_NOT_EXIST is reserved for folders.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "imap4.h"
-
-#include "rfcdecoder.h"
-
-#include <sys/stat.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#ifdef HAVE_LIBSASL2
-extern "C" {
-#include <sasl/sasl.h>
-}
-#endif
-
-#include <tqbuffer.h>
-#include <tqdatetime.h>
-#include <tqregexp.h>
-#include <kprotocolmanager.h>
-#include <kmessagebox.h>
-#include <kdebug.h>
-#include <kio/connection.h>
-#include <kio/slaveinterface.h>
-#include <kio/passdlg.h>
-#include <klocale.h>
-#include <kmimetype.h>
-#include <kmdcodec.h>
-
-#include "tdepimmacros.h"
-
-#define IMAP_PROTOCOL "imap"
-#define IMAP_SSL_PROTOCOL "imaps"
-
-using namespace TDEIO;
-
-extern "C"
-{
- void sigalrm_handler (int);
- KDE_EXPORT int kdemain (int argc, char **argv);
-}
-
-int
-kdemain (int argc, char **argv)
-{
- kdDebug(7116) << "IMAP4::kdemain" << endl;
-
- TDEInstance instance ("kio_imap4");
- if (argc != 4)
- {
- fprintf(stderr, "Usage: kio_imap4 protocol domain-socket1 domain-socket2\n");
- ::exit (-1);
- }
-
-#ifdef HAVE_LIBSASL2
- if ( sasl_client_init( NULL ) != SASL_OK ) {
- fprintf(stderr, "SASL library initialization failed!\n");
- ::exit (-1);
- }
-#endif
-
- //set debug handler
-
- IMAP4Protocol *slave;
- if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
- slave = new IMAP4Protocol (argv[2], argv[3], true);
- else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
- slave = new IMAP4Protocol (argv[2], argv[3], false);
- else
- abort ();
- slave->dispatchLoop ();
- delete slave;
-
-#ifdef HAVE_LIBSASL2
- sasl_done();
-#endif
-
- return 0;
-}
-
-void
-sigchld_handler (int signo)
-{
- int pid, status;
-
- while (true && signo == SIGCHLD)
- {
- pid = waitpid (-1, &status, WNOHANG);
- if (pid <= 0)
- {
- // Reinstall signal handler, since Linux resets to default after
- // the signal occurred ( BSD handles it different, but it should do
- // no harm ).
- signal (SIGCHLD, sigchld_handler);
- return;
- }
- }
-}
-
-IMAP4Protocol::IMAP4Protocol (const TQCString & pool, const TQCString & app, bool isSSL):TCPSlaveBase ((isSSL ? 993 : 143),
- (isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool,
- app, isSSL), imapParser (), mimeIO (), outputBuffer(outputCache)
-{
- outputBufferIndex = 0;
- mySSL = isSSL;
- readBuffer[0] = 0x00;
- relayEnabled = false;
- readBufferLen = 0;
- cacheOutput = false;
- decodeContent = false;
- mTimeOfLastNoop = TQDateTime();
-}
-
-IMAP4Protocol::~IMAP4Protocol ()
-{
- closeDescriptor();
- kdDebug(7116) << "IMAP4: Finishing" << endl;
-}
-
-void
-IMAP4Protocol::get (const KURL & _url)
-{
- if (!makeLogin()) return;
- kdDebug(7116) << "IMAP4::get - " << _url.prettyURL() << endl;
- TQString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
- enum IMAP_TYPE aEnum =
- parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
- if (aEnum != ITYPE_ATTACH)
- mimeType (getMimeType(aEnum));
- if (aInfo == "DECODE")
- decodeContent = true;
-
- if (aSequence == "0:0" && getState() == ISTATE_SELECT)
- {
- imapCommand *cmd = doCommand (imapCommand::clientNoop());
- completeQueue.removeRef(cmd);
- }
-
- if (aSequence.isEmpty ())
- {
- aSequence = "1:*";
- }
-
- mProcessedSize = 0;
- imapCommand *cmd = NULL;
- if (!assureBox (aBox, true)) return;
-
-#ifdef USE_VALIDITY
- if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
- && selectInfo.uidValidity () != aValidity.toULong ())
- {
- // this url is stale
- error (ERR_COULD_NOT_READ, _url.prettyURL());
- return;
- }
- else
-#endif
- {
- // The "section" specified by the application can be:
- // * empty (which means body, size and flags)
- // * a known keyword, like STRUCTURE, ENVELOPE, HEADER, BODY.PEEK[...]
- // (in which case the slave has some logic to add the necessary items)
- // * Otherwise, it specifies the exact data items to request. In this case, all
- // the logic is in the app.
-
- TQString aUpper = aSection.upper();
- if (aUpper.find ("STRUCTURE") != -1)
- {
- aSection = "BODYSTRUCTURE";
- }
- else if (aUpper.find ("ENVELOPE") != -1)
- {
- aSection = "UID RFC822.SIZE FLAGS ENVELOPE";
- if (hasCapability("IMAP4rev1")) {
- aSection += " BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
- } else {
- // imap4 does not know HEADER.FIELDS
- aSection += " RFC822.HEADER.LINES (REFERENCES)";
- }
- }
- else if (aUpper == "HEADER")
- {
- aSection = "UID RFC822.HEADER RFC822.SIZE FLAGS";
- }
- else if (aUpper.find ("BODY.PEEK[") != -1)
- {
- if (aUpper.find ("BODY.PEEK[]") != -1)
- {
- if (!hasCapability("IMAP4rev1")) // imap4 does not know BODY.PEEK[]
- aSection.replace("BODY.PEEK[]", "RFC822.PEEK");
- }
- aSection.prepend("UID RFC822.SIZE FLAGS ");
- }
- else if (aSection.isEmpty())
- {
- aSection = "UID BODY[] RFC822.SIZE FLAGS";
- }
- if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
- {
- // write the digest header
- cacheOutput = true;
- outputLine
- ("Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
- if (selectInfo.recentAvailable ())
- outputLineStr ("X-Recent: " +
- TQString::number(selectInfo.recent ()) + "\r\n");
- if (selectInfo.countAvailable ())
- outputLineStr ("X-Count: " + TQString::number(selectInfo.count ()) +
- "\r\n");
- if (selectInfo.unseenAvailable ())
- outputLineStr ("X-Unseen: " +
- TQString::number(selectInfo.unseen ()) + "\r\n");
- if (selectInfo.uidValidityAvailable ())
- outputLineStr ("X-uidValidity: " +
- TQString::number(selectInfo.uidValidity ()) +
- "\r\n");
- if (selectInfo.uidNextAvailable ())
- outputLineStr ("X-UidNext: " +
- TQString::number(selectInfo.uidNext ()) + "\r\n");
- if (selectInfo.flagsAvailable ())
- outputLineStr ("X-Flags: " + TQString::number(selectInfo.flags ()) +
- "\r\n");
- if (selectInfo.permanentFlagsAvailable ())
- outputLineStr ("X-PermanentFlags: " +
- TQString::number(selectInfo.permanentFlags ()) + "\r\n");
- if (selectInfo.readWriteAvailable ()) {
- if (selectInfo.readWrite()) {
- outputLine ("X-Access: Read/Write\r\n", 22);
- } else {
- outputLine ("X-Access: Read only\r\n", 21);
- }
- }
- outputLine ("\r\n", 2);
- flushOutput(TQString());
- cacheOutput = false;
- }
-
- if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
- relayEnabled = true; // normal mode, relay data
-
- if (aSequence != "0:0")
- {
- TQString contentEncoding;
- if (aEnum == ITYPE_ATTACH && decodeContent)
- {
- // get the MIME header and fill getLastHandled()
- TQString mySection = aSection;
- mySection.replace("]", ".MIME]");
- cmd = sendCommand (imapCommand::clientFetch (aSequence, mySection));
- do
- {
- while (!parseLoop ()) ;
- }
- while (!cmd->isComplete ());
- completeQueue.removeRef (cmd);
- // get the content encoding now because getLastHandled will be cleared
- if (getLastHandled() && getLastHandled()->getHeader())
- contentEncoding = getLastHandled()->getHeader()->getEncoding();
-
- // from here on collect the data
- // it is send to the client in flushOutput in one go
- // needed to decode the content
- cacheOutput = true;
- }
-
- cmd = sendCommand (imapCommand::clientFetch (aSequence, aSection));
- int res;
- aUpper = aSection.upper();
- do
- {
- while (!(res = parseLoop())) ;
- if (res == -1) break;
-
- mailHeader *lastone = 0;
- imapCache *cache = getLastHandled ();
- if (cache)
- lastone = cache->getHeader ();
-
- if (cmd && !cmd->isComplete ())
- {
- if ((aUpper.find ("BODYSTRUCTURE") != -1)
- || (aUpper.find ("FLAGS") != -1)
- || (aUpper.find ("UID") != -1)
- || (aUpper.find ("ENVELOPE") != -1)
- || (aUpper.find ("BODY.PEEK[0]") != -1
- && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
- {
- if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
- {
- // write the mime header (default is here message/rfc822)
- outputLine ("--IMAPDIGEST\r\n", 14);
- cacheOutput = true;
- if (cache && cache->getUid () != 0)
- outputLineStr ("X-UID: " +
- TQString::number(cache->getUid ()) + "\r\n");
- if (cache && cache->getSize () != 0)
- outputLineStr ("X-Length: " +
- TQString::number(cache->getSize ()) + "\r\n");
- if (cache && !cache->getDate ().isEmpty())
- outputLineStr ("X-Date: " + cache->getDate () + "\r\n");
- if (cache && cache->getFlags () != 0)
- outputLineStr ("X-Flags: " +
- TQString::number(cache->getFlags ()) + "\r\n");
- } else cacheOutput = true;
- if ( lastone && !decodeContent )
- lastone->outputPart (*this);
- cacheOutput = false;
- flushOutput(contentEncoding);
- }
- } // if not complete
- }
- while (cmd && !cmd->isComplete ());
- if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
- {
- // write the end boundary
- outputLine ("--IMAPDIGEST--\r\n", 16);
- }
-
- completeQueue.removeRef (cmd);
- }
- }
-
- // just to keep everybody happy when no data arrived
- data (TQByteArray ());
-
- finished ();
- relayEnabled = false;
- cacheOutput = false;
- kdDebug(7116) << "IMAP4::get - finished" << endl;
-}
-
-void
-IMAP4Protocol::listDir (const KURL & _url)
-{
- kdDebug(7116) << " IMAP4::listDir - " << _url.prettyURL() << endl;
-
- if (_url.path().isEmpty())
- {
- KURL url = _url;
- url.setPath("/");
- redirection( url );
- finished();
- return;
- }
-
- TQString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
- // parseURL with caching
- enum IMAP_TYPE myType =
- parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
- myDelimiter, myInfo, true);
-
- if (!makeLogin()) return;
-
- if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
- {
- TQString listStr = myBox;
- imapCommand *cmd;
-
- if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
- mySection != "FOLDERONLY")
- listStr += myDelimiter;
-
- if (mySection.isEmpty())
- {
- listStr += "%";
- } else if (mySection == "COMPLETE") {
- listStr += "*";
- }
- kdDebug(7116) << "IMAP4Protocol::listDir - listStr=" << listStr << endl;
- cmd =
- doCommand (imapCommand::clientList ("", listStr,
- (myLType == "LSUB" || myLType == "LSUBNOCHECK")));
- if (cmd->result () == "OK")
- {
- TQString mailboxName;
- UDSEntry entry;
- UDSAtom atom;
- KURL aURL = _url;
- if (aURL.path().find(';') != -1)
- aURL.setPath(aURL.path().left(aURL.path().find(';')));
-
- kdDebug(7116) << "IMAP4Protocol::listDir - got " << listResponses.count () << endl;
-
- if (myLType == "LSUB")
- {
- // fire the same command as LIST to check if the box really exists
- TQValueList<imapList> listResponsesSave = listResponses;
- doCommand (imapCommand::clientList ("", listStr, false));
- for (TQValueListIterator < imapList > it = listResponsesSave.begin ();
- it != listResponsesSave.end (); ++it)
- {
- bool boxOk = false;
- for (TQValueListIterator < imapList > it2 = listResponses.begin ();
- it2 != listResponses.end (); ++it2)
- {
- if ((*it2).name() == (*it).name())
- {
- boxOk = true;
- // copy the flags from the LIST-command
- (*it) = (*it2);
- break;
- }
- }
- if (boxOk)
- doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
- else // this folder is dead
- kdDebug(7116) << "IMAP4Protocol::listDir - suppress " << (*it).name() << endl;
- }
- listResponses = listResponsesSave;
- }
- else // LIST or LSUBNOCHECK
- {
- for (TQValueListIterator < imapList > it = listResponses.begin ();
- it != listResponses.end (); ++it)
- {
- doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
- }
- }
- entry.clear ();
- listEntry (entry, true);
- }
- else
- {
- error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
- && myLType != "LIST" && myLType != "LSUB" && myLType != "LSUBNOCHECK")
- {
- KURL aURL = _url;
- aURL.setQuery (TQString());
- const TQString encodedUrl = aURL.url(0, 106); // utf-8
-
- if (!_url.query ().isEmpty ())
- {
- TQString query = KURL::decode_string (_url.query ());
- query = query.right (query.length () - 1);
- if (!query.isEmpty())
- {
- imapCommand *cmd = NULL;
-
- if (!assureBox (myBox, true)) return;
-
- if (!selectInfo.countAvailable() || selectInfo.count())
- {
- cmd = doCommand (imapCommand::clientSearch (query));
- if (cmd->result() != "OK")
- {
- error(ERR_UNSUPPORTED_ACTION, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
-
- TQStringList list = getResults ();
- int stretch = 0;
-
- if (selectInfo.uidNextAvailable ())
- stretch = TQString::number(selectInfo.uidNext ()).length ();
- UDSEntry entry;
- imapCache fake;
-
- for (TQStringList::ConstIterator it = list.begin(); it != list.end();
- ++it)
- {
- fake.setUid((*it).toULong());
- doListEntry (encodedUrl, stretch, &fake);
- }
- entry.clear ();
- listEntry (entry, true);
- }
- }
- }
- else
- {
- if (!assureBox (myBox, true)) return;
-
- kdDebug(7116) << "IMAP4: select returned:" << endl;
- if (selectInfo.recentAvailable ())
- kdDebug(7116) << "Recent: " << selectInfo.recent () << "d" << endl;
- if (selectInfo.countAvailable ())
- kdDebug(7116) << "Count: " << selectInfo.count () << "d" << endl;
- if (selectInfo.unseenAvailable ())
- kdDebug(7116) << "Unseen: " << selectInfo.unseen () << "d" << endl;
- if (selectInfo.uidValidityAvailable ())
- kdDebug(7116) << "uidValidity: " << selectInfo.uidValidity () << "d" << endl;
- if (selectInfo.flagsAvailable ())
- kdDebug(7116) << "Flags: " << selectInfo.flags () << "d" << endl;
- if (selectInfo.permanentFlagsAvailable ())
- kdDebug(7116) << "PermanentFlags: " << selectInfo.permanentFlags () << "d" << endl;
- if (selectInfo.readWriteAvailable ())
- kdDebug(7116) << "Access: " << (selectInfo.readWrite ()? "Read/Write" : "Read only") << endl;
-
-#ifdef USE_VALIDITY
- if (selectInfo.uidValidityAvailable ()
- && selectInfo.uidValidity () != myValidity.toULong ())
- {
- //redirect
- KURL newUrl = _url;
-
- newUrl.setPath ("/" + myBox + ";UIDVALIDITY=" +
- TQString::number(selectInfo.uidValidity ()));
- kdDebug(7116) << "IMAP4::listDir - redirecting to " << newUrl.prettyURL() << endl;
- redirection (newUrl);
-
-
- }
- else
-#endif
- if (selectInfo.count () > 0)
- {
- int stretch = 0;
-
- if (selectInfo.uidNextAvailable ())
- stretch = TQString::number(selectInfo.uidNext ()).length ();
- // kdDebug(7116) << selectInfo.uidNext() << "d used to stretch " << stretch << endl;
- UDSEntry entry;
-
- if (mySequence.isEmpty()) mySequence = "1:*";
-
- bool withSubject = mySection.isEmpty();
- if (mySection.isEmpty()) mySection = "UID RFC822.SIZE ENVELOPE";
-
- bool withFlags = mySection.upper().find("FLAGS") != -1;
- imapCommand *fetch =
- sendCommand (imapCommand::
- clientFetch (mySequence, mySection));
- imapCache *cache;
- do
- {
- while (!parseLoop ()) ;
-
- cache = getLastHandled ();
-
- if (cache && !fetch->isComplete())
- doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
- }
- while (!fetch->isComplete ());
- entry.clear ();
- listEntry (entry, true);
- }
- }
- }
- if ( !selectInfo.alert().isNull() ) {
- if ( !myBox.isEmpty() ) {
- warning( i18n( "Message from %1 while processing '%2': %3" ).arg( myHost, myBox, selectInfo.alert() ) );
- } else {
- warning( i18n( "Message from %1: %2" ).arg( myHost, TQString(selectInfo.alert()) ) );
- }
- selectInfo.setAlert( 0 );
- }
-
- kdDebug(7116) << "IMAP4Protocol::listDir - Finishing listDir" << endl;
- finished ();
-}
-
-void
-IMAP4Protocol::setHost (const TQString & _host, int _port,
- const TQString & _user, const TQString & _pass)
-{
- if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
- { // what's the point of doing 4 string compares to avoid 4 string copies?
- // DF: I guess to avoid calling closeConnection() unnecessarily.
- if (!myHost.isEmpty ())
- closeConnection ();
- myHost = _host;
- myPort = _port;
- myUser = _user;
- myPass = _pass;
- }
-}
-
-void
-IMAP4Protocol::parseRelay (const TQByteArray & buffer)
-{
- if (relayEnabled) {
- // relay data immediately
- data( buffer );
- mProcessedSize += buffer.size();
- processedSize( mProcessedSize );
- } else if (cacheOutput)
- {
- // collect data
- if ( !outputBuffer.isOpen() ) {
- outputBuffer.open(IO_WriteOnly);
- }
- outputBuffer.at(outputBufferIndex);
- outputBuffer.writeBlock(buffer, buffer.size());
- outputBufferIndex += buffer.size();
- }
-}
-
-void
-IMAP4Protocol::parseRelay (ulong len)
-{
- if (relayEnabled)
- totalSize (len);
-}
-
-
-bool IMAP4Protocol::parseRead(TQByteArray & buffer, ulong len, ulong relay)
-{
- char buf[8192];
- while (buffer.size() < len)
- {
- ssize_t readLen = myRead(buf, TQMIN(len - buffer.size(), sizeof(buf) - 1));
- if (readLen == 0)
- {
- kdDebug(7116) << "parseRead: readLen == 0 - connection broken" << endl;
- error (ERR_CONNECTION_BROKEN, myHost);
- setState(ISTATE_CONNECT);
- closeConnection();
- return FALSE;
- }
- if (relay > buffer.size())
- {
- TQByteArray relayData;
- ssize_t relbuf = relay - buffer.size();
- int currentRelay = TQMIN(relbuf, readLen);
- relayData.setRawData(buf, currentRelay);
- parseRelay(relayData);
- relayData.resetRawData(buf, currentRelay);
- }
- {
- TQBuffer stream (buffer);
- stream.open (IO_WriteOnly);
- stream.at (buffer.size ());
- stream.writeBlock (buf, readLen);
- stream.close ();
- }
- }
- return (buffer.size() == len);
-}
-
-
-bool IMAP4Protocol::parseReadLine (TQByteArray & buffer, ulong relay)
-{
- if (myHost.isEmpty()) return FALSE;
-
- while (true) {
- ssize_t copyLen = 0;
- if (readBufferLen > 0)
- {
- while (copyLen < readBufferLen && readBuffer[copyLen] != '\n') copyLen++;
- if (copyLen < readBufferLen) copyLen++;
- if (relay > 0)
- {
- TQByteArray relayData;
-
- if (copyLen < (ssize_t) relay)
- relay = copyLen;
- relayData.setRawData (readBuffer, relay);
- parseRelay (relayData);
- relayData.resetRawData (readBuffer, relay);
-// kdDebug(7116) << "relayed : " << relay << "d" << endl;
- }
- // append to buffer
- {
- TQBuffer stream (buffer);
-
- stream.open (IO_WriteOnly);
- stream.at (buffer.size ());
- stream.writeBlock (readBuffer, copyLen);
- stream.close ();
-// kdDebug(7116) << "appended " << copyLen << "d got now " << buffer.size() << endl;
- }
-
- readBufferLen -= copyLen;
- if (readBufferLen)
- memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
- if (buffer[buffer.size() - 1] == '\n') return TRUE;
- }
- if (!isConnectionValid())
- {
- kdDebug(7116) << "parseReadLine - connection broken" << endl;
- error (ERR_CONNECTION_BROKEN, myHost);
- setState(ISTATE_CONNECT);
- closeConnection();
- return FALSE;
- }
- if (!waitForResponse( responseTimeout() ))
- {
- error(ERR_SERVER_TIMEOUT, myHost);
- setState(ISTATE_CONNECT);
- closeConnection();
- return FALSE;
- }
- readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
- if (readBufferLen == 0)
- {
- kdDebug(7116) << "parseReadLine: readBufferLen == 0 - connection broken" << endl;
- error (ERR_CONNECTION_BROKEN, myHost);
- setState(ISTATE_CONNECT);
- closeConnection();
- return FALSE;
- }
- }
-}
-
-void
-IMAP4Protocol::setSubURL (const KURL & _url)
-{
- kdDebug(7116) << "IMAP4::setSubURL - " << _url.prettyURL() << endl;
- TDEIO::TCPSlaveBase::setSubURL (_url);
-}
-
-void
-IMAP4Protocol::put (const KURL & _url, int, bool, bool)
-{
- kdDebug(7116) << "IMAP4::put - " << _url.prettyURL() << endl;
-// TDEIO::TCPSlaveBase::put(_url,permissions,overwrite,resume);
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- enum IMAP_TYPE aType =
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
-
- // see if it is a box
- if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
- {
- if (aBox[aBox.length () - 1] == '/')
- aBox = aBox.right (aBox.length () - 1);
- imapCommand *cmd = doCommand (imapCommand::clientCreate (aBox));
-
- if (cmd->result () != "OK") {
- error (ERR_COULD_NOT_WRITE, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- else
- {
- TQPtrList < TQByteArray > bufferList;
- int length = 0;
-
- int result;
- // Loop until we got 'dataEnd'
- do
- {
- TQByteArray *buffer = new TQByteArray ();
- dataReq (); // Request for data
- result = readData (*buffer);
- if (result > 0)
- {
- bufferList.append (buffer);
- length += result;
- } else {
- delete buffer;
- }
- }
- while (result > 0);
-
- if (result != 0)
- {
- error (ERR_ABORTED, _url.prettyURL());
- return;
- }
-
- imapCommand *cmd =
- sendCommand (imapCommand::clientAppend (aBox, aSection, length));
- while (!parseLoop ()) ;
-
- // see if server is waiting
- if (!cmd->isComplete () && !getContinuation ().isEmpty ())
- {
- bool sendOk = true;
- ulong wrote = 0;
-
- TQByteArray *buffer;
- // send data to server
- while (!bufferList.isEmpty () && sendOk)
- {
- buffer = bufferList.take (0);
-
- sendOk =
- (write (buffer->data (), buffer->size ()) ==
- (ssize_t) buffer->size ());
- wrote += buffer->size ();
- processedSize(wrote);
- delete buffer;
- if (!sendOk)
- {
- error (ERR_CONNECTION_BROKEN, myHost);
- completeQueue.removeRef (cmd);
- setState(ISTATE_CONNECT);
- closeConnection();
- return;
- }
- }
- parseWriteLine ("");
- // Wait until cmd is complete, or connection breaks.
- while (!cmd->isComplete () && getState() != ISTATE_NO)
- parseLoop ();
- if ( getState() == ISTATE_NO ) {
- // TODO KDE4: pass cmd->resultInfo() as third argument.
- // ERR_CONNECTION_BROKEN expects a host, no way to pass details about the problem.
- error( ERR_CONNECTION_BROKEN, myHost );
- completeQueue.removeRef (cmd);
- closeConnection();
- return;
- }
- else if (cmd->result () != "OK") {
- error( ERR_SLAVE_DEFINED, cmd->resultInfo() );
- completeQueue.removeRef (cmd);
- return;
- }
- else
- {
- if (hasCapability("UIDPLUS"))
- {
- TQString uid = cmd->resultInfo();
- if (uid.find("APPENDUID") != -1)
- {
- uid = uid.section(" ", 2, 2);
- uid.truncate(uid.length()-1);
- infoMessage("UID "+uid);
- }
- }
- // MUST reselect to get the new message
- else if (aBox == getCurrentBox ())
- {
- cmd =
- doCommand (imapCommand::
- clientSelect (aBox, !selectInfo.readWrite ()));
- completeQueue.removeRef (cmd);
- }
- }
- }
- else
- {
- //error (ERR_COULD_NOT_WRITE, myHost);
- // Better ship the error message, e.g. "Over Quota"
- error (ERR_SLAVE_DEFINED, cmd->resultInfo());
- completeQueue.removeRef (cmd);
- return;
- }
-
- completeQueue.removeRef (cmd);
- }
-
- finished ();
-}
-
-void
-IMAP4Protocol::mkdir (const KURL & _url, int)
-{
- kdDebug(7116) << "IMAP4::mkdir - " << _url.prettyURL() << endl;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- kdDebug(7116) << "IMAP4::mkdir - create " << aBox << endl;
- imapCommand *cmd = doCommand (imapCommand::clientCreate(aBox));
-
- if (cmd->result () != "OK")
- {
- kdDebug(7116) << "IMAP4::mkdir - " << cmd->resultInfo() << endl;
- error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
-
- // start a new listing to find the type of the folder
- enum IMAP_TYPE type =
- parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- if (type == ITYPE_BOX)
- {
- bool ask = ( aInfo.find( "ASKUSER" ) != -1 );
- if ( ask &&
- messageBox(QuestionYesNo,
- i18n("The following folder will be created on the server: %1 "
- "What do you want to store in this folder?").arg( aBox ),
- i18n("Create Folder"),
- i18n("&Messages"), i18n("&Subfolders")) == KMessageBox::No )
- {
- cmd = doCommand(imapCommand::clientDelete(aBox));
- completeQueue.removeRef (cmd);
- cmd = doCommand(imapCommand::clientCreate(aBox + aDelimiter));
- if (cmd->result () != "OK")
- {
- error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- }
-
- cmd = doCommand(imapCommand::clientSubscribe(aBox));
- completeQueue.removeRef(cmd);
-
- finished ();
-}
-
-void
-IMAP4Protocol::copy (const KURL & src, const KURL & dest, int, bool overwrite)
-{
- kdDebug(7116) << "IMAP4::copy - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
- TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
- TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
- enum IMAP_TYPE sType =
- parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
- enum IMAP_TYPE dType =
- parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
-
- // see if we have to create anything
- if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
- {
- // this might be konqueror
- int sub = dBox.find (sBox);
-
- // might be moving to upper folder
- if (sub > 0)
- {
- KURL testDir = dest;
-
- TQString subDir = dBox.right (dBox.length () - dBox.findRev ('/'));
- TQString topDir = dBox.left (sub);
- testDir.setPath ("/" + topDir);
- dType =
- parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
- dDelimiter, dInfo);
-
- kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
- // see if this is what the user wants
- if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
- {
- kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
- dBox = topDir;
- }
- else
- {
-
- // maybe if we create a new mailbox
- topDir = "/" + topDir + subDir;
- testDir.setPath (topDir);
- kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
- dType =
- parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
- dDelimiter, dInfo);
- if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
- {
- // ok then we'll create a mailbox
- imapCommand *cmd = doCommand (imapCommand::clientCreate (topDir));
-
- // on success we'll use it, else we'll just try to create the given dir
- if (cmd->result () == "OK")
- {
- kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
- dType = ITYPE_BOX;
- dBox = topDir;
- }
- else
- {
- completeQueue.removeRef (cmd);
- cmd = doCommand (imapCommand::clientCreate (dBox));
- if (cmd->result () == "OK")
- dType = ITYPE_BOX;
- else
- error (ERR_COULD_NOT_WRITE, dest.prettyURL());
- }
- completeQueue.removeRef (cmd);
- }
- }
-
- }
- }
- if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
- {
- //select the source box
- if (!assureBox(sBox, true)) return;
- kdDebug(7116) << "IMAP4::copy - " << sBox << " -> " << dBox << endl;
-
- //issue copy command
- imapCommand *cmd =
- doCommand (imapCommand::clientCopy (dBox, sSequence));
- if (cmd->result () != "OK")
- {
- kdError(5006) << "IMAP4::copy - " << cmd->resultInfo() << endl;
- error (ERR_COULD_NOT_WRITE, dest.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- } else {
- if (hasCapability("UIDPLUS"))
- {
- TQString uid = cmd->resultInfo();
- if (uid.find("COPYUID") != -1)
- {
- uid = uid.section(" ", 2, 3);
- uid.truncate(uid.length()-1);
- infoMessage("UID "+uid);
- }
- }
- }
- completeQueue.removeRef (cmd);
- }
- else
- {
- error (ERR_ACCESS_DENIED, src.prettyURL());
- return;
- }
- finished ();
-}
-
-void
-IMAP4Protocol::del (const KURL & _url, bool isFile)
-{
- kdDebug(7116) << "IMAP4::del - [" << (isFile ? "File" : "NoFile") << "] " << _url.prettyURL() << endl;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- enum IMAP_TYPE aType =
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
-
- switch (aType)
- {
- case ITYPE_BOX:
- case ITYPE_DIR_AND_BOX:
- if (!aSequence.isEmpty ())
- {
- if (aSequence == "*")
- {
- if (!assureBox (aBox, false)) return;
- imapCommand *cmd = doCommand (imapCommand::clientExpunge ());
- if (cmd->result () != "OK") {
- error (ERR_CANNOT_DELETE, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- else
- {
- // if open for read/write
- if (!assureBox (aBox, false)) return;
- imapCommand *cmd =
- doCommand (imapCommand::
- clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
- if (cmd->result () != "OK") {
- error (ERR_CANNOT_DELETE, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- }
- else
- {
- if (getCurrentBox() == aBox)
- {
- imapCommand *cmd = doCommand(imapCommand::clientClose());
- completeQueue.removeRef(cmd);
- setState(ISTATE_LOGIN);
- }
- // We unsubscribe, otherwise we get ghost folders on UW-IMAP
- imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
- completeQueue.removeRef(cmd);
- cmd = doCommand(imapCommand::clientDelete (aBox));
- // If this doesn't work, we try to empty the mailbox first
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef(cmd);
- if (!assureBox(aBox, false)) return;
- bool stillOk = true;
- if (stillOk)
- {
- imapCommand *cmd = doCommand(
- imapCommand::clientStore("1:*", "+FLAGS.SILENT", "\\DELETED"));
- if (cmd->result () != "OK") stillOk = false;
- completeQueue.removeRef(cmd);
- }
- if (stillOk)
- {
- imapCommand *cmd = doCommand(imapCommand::clientClose());
- if (cmd->result () != "OK") stillOk = false;
- completeQueue.removeRef(cmd);
- setState(ISTATE_LOGIN);
- }
- if (stillOk)
- {
- imapCommand *cmd = doCommand (imapCommand::clientDelete(aBox));
- if (cmd->result () != "OK") stillOk = false;
- completeQueue.removeRef(cmd);
- }
- if (!stillOk)
- {
- error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
- return;
- }
- } else {
- completeQueue.removeRef (cmd);
- }
- }
- break;
-
- case ITYPE_DIR:
- {
- imapCommand *cmd = doCommand (imapCommand::clientDelete (aBox));
- if (cmd->result () != "OK") {
- error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- break;
-
- case ITYPE_MSG:
- {
- // if open for read/write
- if (!assureBox (aBox, false)) return;
- imapCommand *cmd =
- doCommand (imapCommand::
- clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
- if (cmd->result () != "OK") {
- error (ERR_CANNOT_DELETE, _url.prettyURL());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- break;
-
- case ITYPE_UNKNOWN:
- case ITYPE_ATTACH:
- error (ERR_CANNOT_DELETE, _url.prettyURL());
- break;
- }
- finished ();
-}
-
-/*
- * Copy a mail: data = 'C' + srcURL (KURL) + destURL (KURL)
- * Capabilities: data = 'c'. Result shipped in infoMessage() signal
- * No-op: data = 'N'
- * Namespace: data = 'n'. Result shipped in infoMessage() signal
- * The format is: section=namespace=delimiter
- * Note that the namespace can be empty
- * Unsubscribe: data = 'U' + URL (KURL)
- * Subscribe: data = 'u' + URL (KURL)
- * Change the status: data = 'S' + URL (KURL) + Flags (TQCString)
- * ACL commands: data = 'A' + command + URL (KURL) + command-dependent args
- * AnnotateMore commands: data = 'M' + 'G'et/'S'et + URL + entry + command-dependent args
- * Search: data = 'E' + URL (KURL)
- * Quota commands: data = 'Q' + 'R'oot/'G'et/'S'et + URL + entry + command-dependent args
- * Custom command: data = 'X' + 'N'ormal/'E'xtended + command + command-dependent args
- */
-void
-IMAP4Protocol::special (const TQByteArray & aData)
-{
- kdDebug(7116) << "IMAP4Protocol::special" << endl;
- if (!makeLogin()) return;
-
- TQDataStream stream(aData, IO_ReadOnly);
-
- int tmp;
- stream >> tmp;
-
- switch (tmp) {
- case 'C':
- {
- // copy
- KURL src;
- KURL dest;
- stream >> src >> dest;
- copy(src, dest, 0, FALSE);
- break;
- }
- case 'c':
- {
- // capabilities
- infoMessage(imapCapabilities.join(" "));
- finished();
- break;
- }
- case 'N':
- {
- // NOOP
- imapCommand *cmd = doCommand(imapCommand::clientNoop());
- if (cmd->result () != "OK")
- {
- kdDebug(7116) << "NOOP did not succeed - connection broken" << endl;
- completeQueue.removeRef (cmd);
- error (ERR_CONNECTION_BROKEN, myHost);
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'n':
- {
- // namespace in the form "section=namespace=delimiter"
- // entries are separated by ,
- infoMessage( imapNamespaces.join(",") );
- finished();
- break;
- }
- case 'U':
- {
- // unsubscribe
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef (cmd);
- error(ERR_SLAVE_DEFINED, i18n("Unsubscribe of folder %1 "
- "failed. The server returned: %2")
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'u':
- {
- // subscribe
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- imapCommand *cmd = doCommand(imapCommand::clientSubscribe(aBox));
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef (cmd);
- error(ERR_SLAVE_DEFINED, i18n("Subscribe of folder %1 "
- "failed. The server returned: %2")
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'A':
- {
- // acl
- int cmd;
- stream >> cmd;
- if ( hasCapability( "ACL" ) ) {
- specialACLCommand( cmd, stream );
- } else {
- error( ERR_UNSUPPORTED_ACTION, "ACL" );
- }
- break;
- }
- case 'M':
- {
- // annotatemore
- int cmd;
- stream >> cmd;
- if ( hasCapability( "ANNOTATEMORE" ) ) {
- specialAnnotateMoreCommand( cmd, stream );
- } else {
- error( ERR_UNSUPPORTED_ACTION, "ANNOTATEMORE" );
- }
- break;
- }
- case 'Q':
- {
- // quota
- int cmd;
- stream >> cmd;
- if ( hasCapability( "QUOTA" ) ) {
- specialQuotaCommand( cmd, stream );
- } else {
- error( ERR_UNSUPPORTED_ACTION, "QUOTA" );
- }
- break;
- }
- case 'S':
- {
- // status
- KURL _url;
- TQCString newFlags;
- stream >> _url >> newFlags;
-
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- if (!assureBox(aBox, false)) return;
-
- // make sure we only touch flags we know
- TQCString knownFlags = "\\SEEN \\ANSWERED \\FLAGGED \\DRAFT";
- const imapInfo info = getSelected();
- if ( info.permanentFlagsAvailable() && (info.permanentFlags() & imapInfo::User) ) {
- knownFlags += " KMAILFORWARDED KMAILTODO KMAILWATCHED KMAILIGNORED $FORWARDED $TODO $WATCHED $IGNORED";
- }
-
- imapCommand *cmd = doCommand (imapCommand::
- clientStore (aSequence, "-FLAGS.SILENT", knownFlags));
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef (cmd);
- error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
- "failed.").arg(_url.prettyURL()));
- return;
- }
- completeQueue.removeRef (cmd);
- if (!newFlags.isEmpty())
- {
- cmd = doCommand (imapCommand::
- clientStore (aSequence, "+FLAGS.SILENT", newFlags));
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef (cmd);
- error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
- "failed.").arg(_url.prettyURL()));
- return;
- }
- completeQueue.removeRef (cmd);
- }
- finished();
- break;
- }
- case 's':
- {
- // seen
- KURL _url;
- bool seen;
- TQCString newFlags;
- stream >> _url >> seen;
-
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- if ( !assureBox(aBox, true) ) // read-only because changing SEEN should be possible even then
- return;
-
- imapCommand *cmd;
- if ( seen )
- cmd = doCommand( imapCommand::clientStore( aSequence, "+FLAGS.SILENT", "\\SEEN" ) );
- else
- cmd = doCommand( imapCommand::clientStore( aSequence, "-FLAGS.SILENT", "\\SEEN" ) );
-
- if (cmd->result () != "OK")
- {
- completeQueue.removeRef (cmd);
- error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
- "failed.").arg(_url.prettyURL()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
-
- case 'E':
- {
- // search
- specialSearchCommand( stream );
- break;
- }
- case 'X':
- {
- // custom command
- specialCustomCommand( stream );
- break;
- }
- default:
- kdWarning(7116) << "Unknown command in special(): " << tmp << endl;
- error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(tmp)) );
- break;
- }
-}
-
-void
-IMAP4Protocol::specialACLCommand( int command, TQDataStream& stream )
-{
- // All commands start with the URL to the box
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
-
- switch( command ) {
- case 'S': // SETACL
- {
- TQString user, acl;
- stream >> user >> acl;
- kdDebug(7116) << "SETACL " << aBox << " " << user << " " << acl << endl;
- imapCommand *cmd = doCommand(imapCommand::clientSetACL(aBox, user, acl));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Setting the Access Control List on folder %1 "
- "for user %2 failed. The server returned: %3")
- .arg(_url.prettyURL())
- .arg(user)
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'D': // DELETEACL
- {
- TQString user;
- stream >> user;
- kdDebug(7116) << "DELETEACL " << aBox << " " << user << endl;
- imapCommand *cmd = doCommand(imapCommand::clientDeleteACL(aBox, user));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Deleting the Access Control List on folder %1 "
- "for user %2 failed. The server returned: %3")
- .arg(_url.prettyURL())
- .arg(user)
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'G': // GETACL
- {
- kdDebug(7116) << "GETACL " << aBox << endl;
- imapCommand *cmd = doCommand(imapCommand::clientGetACL(aBox));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
- "failed. The server returned: %2")
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- // Returning information to the application from a special() command isn't easy.
- // I'm reusing the infoMessage trick seen above (for capabilities), but this
- // limits me to a string instead of a stringlist. Using DQUOTE as separator,
- // because it's forbidden in userids by rfc3501
- kdDebug(7116) << getResults() << endl;
- infoMessage(getResults().join( "\"" ));
- finished();
- break;
- }
- case 'L': // LISTRIGHTS
- {
- // Do we need this one? It basically shows which rights are tied together, but that's all?
- error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
- break;
- }
- case 'M': // MYRIGHTS
- {
- kdDebug(7116) << "MYRIGHTS " << aBox << endl;
- imapCommand *cmd = doCommand(imapCommand::clientMyRights(aBox));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
- "failed. The server returned: %2")
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- TQStringList lst = getResults();
- kdDebug(7116) << "myrights results: " << lst << endl;
- if ( !lst.isEmpty() ) {
- Q_ASSERT( lst.count() == 1 );
- infoMessage( lst.first() );
- }
- finished();
- break;
- }
- default:
- kdWarning(7116) << "Unknown special ACL command:" << command << endl;
- error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
- }
-}
-
-void
-IMAP4Protocol::specialSearchCommand( TQDataStream& stream )
-{
- kdDebug(7116) << "IMAP4Protocol::specialSearchCommand" << endl;
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
- if (!assureBox(aBox, false)) return;
-
- imapCommand *cmd = doCommand (imapCommand::clientSearch( aSection ));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Searching of folder %1 "
- "failed. The server returned: %2")
- .arg(aBox)
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef(cmd);
- TQStringList lst = getResults();
- kdDebug(7116) << "IMAP4Protocol::specialSearchCommand '" << aSection <<
- "' returns " << lst << endl;
- infoMessage( lst.join( " " ) );
-
- finished();
-}
-
-void
-IMAP4Protocol::specialCustomCommand( TQDataStream& stream )
-{
- kdDebug(7116) << "IMAP4Protocol::specialCustomCommand" << endl;
-
- TQString command, arguments;
- int type;
- stream >> type;
- stream >> command >> arguments;
-
- /**
- * In 'normal' mode we send the command with all information in one go
- * and retrieve the result.
- */
- if ( type == 'N' ) {
- kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: normal mode" << endl;
- imapCommand *cmd = doCommand (imapCommand::clientCustom( command, arguments ));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Custom command %1:%2 "
- "failed. The server returned: %3")
- .arg(command)
- .arg(arguments)
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef(cmd);
- TQStringList lst = getResults();
- kdDebug(7116) << "IMAP4Protocol::specialCustomCommand '" << command <<
- ":" << arguments <<
- "' returns " << lst << endl;
- infoMessage( lst.join( " " ) );
-
- finished();
- } else
- /**
- * In 'extended' mode we send a first header and push the data of the request in
- * streaming mode.
- */
- if ( type == 'E' ) {
- kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: extended mode" << endl;
- imapCommand *cmd = sendCommand (imapCommand::clientCustom( command, TQString() ));
- while ( !parseLoop () ) ;
-
- // see if server is waiting
- if (!cmd->isComplete () && !getContinuation ().isEmpty ())
- {
- const TQByteArray buffer = arguments.utf8();
-
- // send data to server
- bool sendOk = (write (buffer.data (), buffer.size ()) == (ssize_t)buffer.size ());
- processedSize( buffer.size() );
-
- if ( !sendOk ) {
- error ( ERR_CONNECTION_BROKEN, myHost );
- completeQueue.removeRef ( cmd );
- setState(ISTATE_CONNECT);
- closeConnection();
- return;
- }
- }
- parseWriteLine ("");
-
- do
- {
- while (!parseLoop ()) ;
- }
- while (!cmd->isComplete ());
-
- completeQueue.removeRef (cmd);
-
- TQStringList lst = getResults();
- kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: returns " << lst << endl;
- infoMessage( lst.join( " " ) );
-
- finished ();
- }
-}
-
-void
-IMAP4Protocol::specialAnnotateMoreCommand( int command, TQDataStream& stream )
-{
- // All commands start with the URL to the box
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
-
- switch( command ) {
- case 'S': // SETANNOTATION
- {
- // Params:
- // KURL URL of the mailbox
- // TQString entry (should be an actual entry name, no % or *; empty for server entries)
- // TQMap<TQString,TQString> attributes (name and value)
- TQString entry;
- TQMap<TQString, TQString> attributes;
- stream >> entry >> attributes;
- kdDebug(7116) << "SETANNOTATION " << aBox << " " << entry << " " << attributes.count() << " attributes" << endl;
- imapCommand *cmd = doCommand(imapCommand::clientSetAnnotation(aBox, entry, attributes));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Setting the annotation %1 on folder %2 "
- " failed. The server returned: %3")
- .arg(entry)
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- completeQueue.removeRef (cmd);
- finished();
- break;
- }
- case 'G': // GETANNOTATION.
- {
- // Params:
- // KURL URL of the mailbox
- // TQString entry (should be an actual entry name, no % or *; empty for server entries)
- // TQStringList attributes (list of attributes to be retrieved, possibly with % or *)
- TQString entry;
- TQStringList attributeNames;
- stream >> entry >> attributeNames;
- kdDebug(7116) << "GETANNOTATION " << aBox << " " << entry << " " << attributeNames << endl;
- imapCommand *cmd = doCommand(imapCommand::clientGetAnnotation(aBox, entry, attributeNames));
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Retrieving the annotation %1 on folder %2 "
- "failed. The server returned: %3")
- .arg(entry)
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- // Returning information to the application from a special() command isn't easy.
- // I'm reusing the infoMessage trick seen above (for capabilities and acls), but this
- // limits me to a string instead of a stringlist. Let's use \r as separator.
- kdDebug(7116) << getResults() << endl;
- infoMessage(getResults().join( "\r" ));
- finished();
- break;
- }
- default:
- kdWarning(7116) << "Unknown special annotate command:" << command << endl;
- error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
- }
-}
-
-void
-IMAP4Protocol::specialQuotaCommand( int command, TQDataStream& stream )
-{
- // All commands start with the URL to the box
- KURL _url;
- stream >> _url;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
-
- switch( command ) {
- case 'R': // GETQUOTAROOT
- {
- kdDebug(7116) << "QUOTAROOT " << aBox << endl;
- imapCommand *cmd = doCommand(imapCommand::clientGetQuotaroot( aBox ) );
- if (cmd->result () != "OK")
- {
- error(ERR_SLAVE_DEFINED, i18n("Retrieving the quota root information on folder %1 "
- "failed. The server returned: %2")
- .arg(_url.prettyURL())
- .arg(cmd->resultInfo()));
- return;
- }
- infoMessage(getResults().join( "\r" ));
- finished();
- break;
- }
- case 'G': // GETQUOTA
- {
- kdDebug(7116) << "GETQUOTA command" << endl;
- kdWarning(7116) << "UNIMPLEMENTED" << endl;
- break;
- }
- case 'S': // SETQUOTA
- {
- kdDebug(7116) << "SETQUOTA command" << endl;
- kdWarning(7116) << "UNIMPLEMENTED" << endl;
- break;
- }
- default:
- kdWarning(7116) << "Unknown special quota command:" << command << endl;
- error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
- }
-}
-
-void
-IMAP4Protocol::rename (const KURL & src, const KURL & dest, bool overwrite)
-{
- kdDebug(7116) << "IMAP4::rename - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
- TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
- TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
- enum IMAP_TYPE sType =
- parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo, false);
- enum IMAP_TYPE dType =
- parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo, false);
-
- if (dType == ITYPE_UNKNOWN)
- {
- switch (sType)
- {
- case ITYPE_BOX:
- case ITYPE_DIR:
- case ITYPE_DIR_AND_BOX:
- {
- if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
- {
- kdDebug(7116) << "IMAP4::rename - close " << getCurrentBox() << endl;
- // mailbox can only be renamed if it is closed
- imapCommand *cmd = doCommand (imapCommand::clientClose());
- bool ok = cmd->result() == "OK";
- completeQueue.removeRef(cmd);
- if (!ok)
- {
- kdWarning(7116) << "Unable to close mailbox!" << endl;
- error(ERR_CANNOT_RENAME, src.path());
- return;
- }
- setState(ISTATE_LOGIN);
- }
- imapCommand *cmd = doCommand (imapCommand::clientRename (sBox, dBox));
- if (cmd->result () != "OK") {
- error (ERR_CANNOT_RENAME, src.path());
- completeQueue.removeRef (cmd);
- return;
- }
- completeQueue.removeRef (cmd);
- }
- break;
-
- case ITYPE_MSG:
- case ITYPE_ATTACH:
- case ITYPE_UNKNOWN:
- error (ERR_CANNOT_RENAME, src.path());
- break;
- }
- }
- else
- {
- error (ERR_CANNOT_RENAME, src.path());
- return;
- }
- finished ();
-}
-
-void
-IMAP4Protocol::slave_status ()
-{
- bool connected = (getState() != ISTATE_NO) && isConnectionValid();
- kdDebug(7116) << "IMAP4::slave_status " << connected << endl;
- slaveStatus ( connected ? myHost : TQString(), connected );
-}
-
-void
-IMAP4Protocol::dispatch (int command, const TQByteArray & data)
-{
- kdDebug(7116) << "IMAP4::dispatch - command=" << command << endl;
- TDEIO::TCPSlaveBase::dispatch (command, data);
-}
-
-void
-IMAP4Protocol::stat (const KURL & _url)
-{
- kdDebug(7116) << "IMAP4::stat - " << _url.prettyURL() << endl;
- TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
- // parseURL with caching
- enum IMAP_TYPE aType =
- parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
- aInfo, true);
-
- UDSEntry entry;
- UDSAtom atom;
-
- atom.m_uds = UDS_NAME;
- atom.m_str = aBox;
- entry.append (atom);
-
- if (!aSection.isEmpty())
- {
- if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
- {
- imapCommand *cmd = doCommand (imapCommand::clientClose());
- bool ok = cmd->result() == "OK";
- completeQueue.removeRef(cmd);
- if (!ok)
- {
- error(ERR_COULD_NOT_STAT, aBox);
- return;
- }
- setState(ISTATE_LOGIN);
- }
- bool ok = false;
- TQString cmdInfo;
- if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
- ok = true;
- else
- {
- imapCommand *cmd = doCommand(imapCommand::clienStatus(aBox, aSection));
- ok = cmd->result() == "OK";
- cmdInfo = cmd->resultInfo();
- completeQueue.removeRef(cmd);
- }
- if (!ok)
- {
- bool found = false;
- imapCommand *cmd = doCommand (imapCommand::clientList ("", aBox));
- if (cmd->result () == "OK")
- {
- for (TQValueListIterator < imapList > it = listResponses.begin ();
- it != listResponses.end (); ++it)
- {
- if (aBox == (*it).name ()) found = true;
- }
- }
- completeQueue.removeRef (cmd);
- if (found)
- error(ERR_COULD_NOT_STAT, aBox);
- else
- error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
- return;
- }
- if ((aSection == "UIDNEXT" && geStatus().uidNextAvailable())
- || (aSection == "UNSEEN" && geStatus().unseenAvailable()))
- {
- atom.m_uds = UDS_SIZE;
- atom.m_str = TQString();
- atom.m_long = (aSection == "UIDNEXT") ? geStatus().uidNext()
- : geStatus().unseen();
- entry.append(atom);
- }
- } else
- if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
- aType == ITYPE_ATTACH)
- {
- ulong validity = 0;
- // see if the box is already in select/examine state
- if (aBox == getCurrentBox ())
- validity = selectInfo.uidValidity ();
- else
- {
- // do a status lookup on the box
- // only do this if the box is not selected
- // the server might change the validity for new select/examine
- imapCommand *cmd =
- doCommand (imapCommand::clienStatus (aBox, "UIDVALIDITY"));
- completeQueue.removeRef (cmd);
- validity = geStatus ().uidValidity ();
- }
- validity = 0; // temporary
-
- if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
- {
- // has no or an invalid uidvalidity
- if (validity > 0 && validity != aValidity.toULong ())
- {
- //redirect
- KURL newUrl = _url;
-
- newUrl.setPath ("/" + aBox + ";UIDVALIDITY=" +
- TQString::number(validity));
- kdDebug(7116) << "IMAP4::stat - redirecting to " << newUrl.prettyURL() << endl;
- redirection (newUrl);
- }
- }
- else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
- {
- //must determine if this message exists
- //cause konqueror will check this on paste operations
-
- // has an invalid uidvalidity
- // or no messages in box
- if (validity > 0 && validity != aValidity.toULong ())
- {
- aType = ITYPE_UNKNOWN;
- kdDebug(7116) << "IMAP4::stat - url has invalid validity [" << validity << "d] " << _url.prettyURL() << endl;
- }
- }
- }
-
- atom.m_uds = UDS_MIME_TYPE;
- atom.m_str = getMimeType (aType);
- entry.append (atom);
-
- kdDebug(7116) << "IMAP4: stat: " << atom.m_str << endl;
- switch (aType)
- {
- case ITYPE_DIR:
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFDIR;
- entry.append (atom);
- break;
-
- case ITYPE_BOX:
- case ITYPE_DIR_AND_BOX:
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFDIR;
- entry.append (atom);
- break;
-
- case ITYPE_MSG:
- case ITYPE_ATTACH:
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFREG;
- entry.append (atom);
- break;
-
- case ITYPE_UNKNOWN:
- error (ERR_DOES_NOT_EXIST, _url.prettyURL());
- break;
- }
-
- statEntry (entry);
- kdDebug(7116) << "IMAP4::stat - Finishing stat" << endl;
- finished ();
-}
-
-void IMAP4Protocol::openConnection()
-{
- if (makeLogin()) connected();
-}
-
-void IMAP4Protocol::closeConnection()
-{
- if (getState() == ISTATE_NO) return;
- if (getState() == ISTATE_SELECT && metaData("expunge") == "auto")
- {
- imapCommand *cmd = doCommand (imapCommand::clientExpunge());
- completeQueue.removeRef (cmd);
- }
- if (getState() != ISTATE_CONNECT)
- {
- imapCommand *cmd = doCommand (imapCommand::clientLogout());
- completeQueue.removeRef (cmd);
- }
- closeDescriptor();
- setState(ISTATE_NO);
- completeQueue.clear();
- sentQueue.clear();
- lastHandled = 0;
- currentBox = TQString();
- readBufferLen = 0;
-}
-
-bool IMAP4Protocol::makeLogin ()
-{
- if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
- return true;
-
- kdDebug(7116) << "IMAP4::makeLogin - checking login" << endl;
- bool alreadyConnected = getState() == ISTATE_CONNECT;
- kdDebug(7116) << "IMAP4::makeLogin - alreadyConnected " << alreadyConnected << endl;
- if (alreadyConnected || connectToHost (myHost.latin1(), myPort))
- {
-// fcntl (m_iSock, F_SETFL, (fcntl (m_iSock, F_GETFL) | O_NDELAY));
-
- setState(ISTATE_CONNECT);
-
- myAuth = metaData("auth");
- myTLS = metaData("tls");
- kdDebug(7116) << "myAuth: " << myAuth << endl;
-
- imapCommand *cmd;
-
- unhandled.clear ();
- if (!alreadyConnected) while (!parseLoop ()) ; //get greeting
- TQString greeting;
- if (!unhandled.isEmpty()) greeting = unhandled.first().stripWhiteSpace();
- unhandled.clear (); //get rid of it
- cmd = doCommand (new imapCommand ("CAPABILITY", ""));
-
- kdDebug(7116) << "IMAP4: setHost: capability" << endl;
- for (TQStringList::Iterator it = imapCapabilities.begin ();
- it != imapCapabilities.end (); ++it)
- {
- kdDebug(7116) << "'" << (*it) << "'" << endl;
- }
- completeQueue.removeRef (cmd);
-
- if (!hasCapability("IMAP4") && !hasCapability("IMAP4rev1"))
- {
- error(ERR_COULD_NOT_LOGIN, i18n("The server %1 supports neither "
- "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2")
- .arg(myHost).arg(greeting));
- closeConnection();
- return false;
- }
-
- if (metaData("nologin") == "on") return TRUE;
-
- if (myTLS == "on" && !hasCapability(TQString("STARTTLS")))
- {
- error(ERR_COULD_NOT_LOGIN, i18n("The server does not support TLS.\n"
- "Disable this security feature to connect unencrypted."));
- closeConnection();
- return false;
- }
- if ((myTLS == "on" || (canUseTLS() && myTLS != "off")) &&
- hasCapability(TQString("STARTTLS")))
- {
- imapCommand *cmd = doCommand (imapCommand::clientStartTLS());
- if (cmd->result () == "OK")
- {
- completeQueue.removeRef(cmd);
- int tlsrc = startTLS();
- if (tlsrc == 1)
- {
- kdDebug(7116) << "TLS mode has been enabled." << endl;
- imapCommand *cmd2 = doCommand (new imapCommand ("CAPABILITY", ""));
- for (TQStringList::Iterator it = imapCapabilities.begin ();
- it != imapCapabilities.end (); ++it)
- {
- kdDebug(7116) << "'" << (*it) << "'" << endl;
- }
- completeQueue.removeRef (cmd2);
- } else {
- kdWarning(7116) << "TLS mode setup has failed. Aborting." << endl;
- error (ERR_COULD_NOT_LOGIN, i18n("Starting TLS failed."));
- closeConnection();
- return false;
- }
- } else completeQueue.removeRef(cmd);
- }
-
- if (myAuth.isEmpty () || myAuth == "*") {
- if (hasCapability (TQString ("LOGINDISABLED"))) {
- error (ERR_COULD_NOT_LOGIN, i18n("LOGIN is disabled by the server."));
- closeConnection();
- return false;
- }
- }
- else {
- if (!hasCapability (TQString ("AUTH=") + myAuth)) {
- error (ERR_COULD_NOT_LOGIN, i18n("The authentication method %1 is not "
- "supported by the server.").arg(myAuth));
- closeConnection();
- return false;
- }
- }
-
- if ( greeting.contains( TQRegExp( "Cyrus IMAP4 v2.1" ) ) ) {
- removeCapability( "ANNOTATEMORE" );
- }
-
- // starting from Cyrus IMAP 2.3.9, shared seen flags are available
- TQRegExp regExp( "Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)", false );
- if ( regExp.search( greeting ) >= 0 ) {
- const int major = regExp.cap( 1 ).toInt();
- const int minor = regExp.cap( 2 ).toInt();
- const int patch = regExp.cap( 3 ).toInt();
- if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
- kdDebug(7116) << k_funcinfo << "Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support" << endl;
- imapCapabilities.append( "x-kmail-sharedseen" );
- }
- }
-
- kdDebug(7116) << "IMAP4::makeLogin - attempting login" << endl;
-
- TDEIO::AuthInfo authInfo;
- authInfo.username = myUser;
- authInfo.password = myPass;
- authInfo.prompt = i18n ("Username and password for your IMAP account:");
-
- kdDebug(7116) << "IMAP4::makeLogin - open_PassDlg said user=" << myUser << " pass=xx" << endl;
-
- TQString resultInfo;
- if (myAuth.isEmpty () || myAuth == "*")
- {
- if (myUser.isEmpty () || myPass.isEmpty ()) {
- if(openPassDlg (authInfo)) {
- myUser = authInfo.username;
- myPass = authInfo.password;
- }
- }
- if (!clientLogin (myUser, myPass, resultInfo))
- error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to login. Probably the "
- "password is wrong.\nThe server %1 replied:\n%2").arg(myHost).arg(resultInfo));
- }
- else
- {
-#ifdef HAVE_LIBSASL2
- if (!clientAuthenticate (this, authInfo, myHost, myAuth, mySSL, resultInfo))
- error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to authenticate via %1.\n"
- "The server %2 replied:\n%3").arg(myAuth).arg(myHost).arg(resultInfo));
- else {
- myUser = authInfo.username;
- myPass = authInfo.password;
- }
-#else
- error(TDEIO::ERR_COULD_NOT_LOGIN, i18n("SASL authentication is not compiled into kio_imap4."));
-#endif
- }
- if ( hasCapability("NAMESPACE") )
- {
- // get all namespaces and save the namespace - delimiter association
- cmd = doCommand( imapCommand::clientNamespace() );
- if (cmd->result () == "OK")
- {
- kdDebug(7116) << "makeLogin - registered namespaces" << endl;
- }
- completeQueue.removeRef (cmd);
- }
- // get the default delimiter (empty listing)
- cmd = doCommand( imapCommand::clientList("", "") );
- if (cmd->result () == "OK")
- {
- TQValueListIterator < imapList > it = listResponses.begin();
- if ( it == listResponses.end() )
- {
- // empty answer - this is a buggy imap server
- // as a fallback we fire a normal listing and take the first answer
- completeQueue.removeRef (cmd);
- cmd = doCommand( imapCommand::clientList("", "%") );
- if (cmd->result () == "OK")
- {
- it = listResponses.begin();
- }
- }
- if ( it != listResponses.end() )
- {
- namespaceToDelimiter[TQString()] = (*it).hierarchyDelimiter();
- kdDebug(7116) << "makeLogin - delimiter for empty ns='" <<
- (*it).hierarchyDelimiter() << "'" << endl;
- if ( !hasCapability("NAMESPACE") )
- {
- // server does not support namespaces
- TQString nsentry = TQString::number( 0 ) + "=="
- + (*it).hierarchyDelimiter();
- imapNamespaces.append( nsentry );
- }
- }
- }
- completeQueue.removeRef (cmd);
- } else {
- kdDebug(7116) << "makeLogin - NO login" << endl;
- }
-
- return getState() == ISTATE_LOGIN;
-}
-
-void
-IMAP4Protocol::parseWriteLine (const TQString & aStr)
-{
- //kdDebug(7116) << "Writing: " << aStr << endl;
- TQCString writer = aStr.utf8();
- int len = writer.length();
-
- // append CRLF if necessary
- if (len == 0 || (writer[len - 1] != '\n')) {
- len += 2;
- writer += "\r\n";
- }
-
- // write it
- write(writer.data(), len);
-}
-
-TQString
-IMAP4Protocol::getMimeType (enum IMAP_TYPE aType)
-{
- switch (aType)
- {
- case ITYPE_DIR:
- return "inode/directory";
- break;
-
- case ITYPE_BOX:
- return "message/digest";
- break;
-
- case ITYPE_DIR_AND_BOX:
- return "message/directory";
- break;
-
- case ITYPE_MSG:
- return "message/rfc822";
- break;
-
- // this should be handled by flushOutput
- case ITYPE_ATTACH:
- return "application/octet-stream";
- break;
-
- case ITYPE_UNKNOWN:
- default:
- return "unknown/unknown";
- }
-}
-
-
-
-void
-IMAP4Protocol::doListEntry (const KURL & _url, int stretch, imapCache * cache,
- bool withFlags, bool withSubject)
-{
- KURL aURL = _url;
- aURL.setQuery (TQString());
- const TQString encodedUrl = aURL.url(0, 106); // utf-8
- doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
-}
-
-
-
-void
-IMAP4Protocol::doListEntry (const TQString & encodedUrl, int stretch, imapCache * cache,
- bool withFlags, bool withSubject)
-{
- if (cache)
- {
- UDSEntry entry;
- UDSAtom atom;
-
- entry.clear ();
-
- const TQString uid = TQString::number(cache->getUid());
-
- atom.m_uds = UDS_NAME;
- atom.m_str = uid;
- atom.m_long = 0;
- if (stretch > 0)
- {
- atom.m_str = "0000000000000000" + atom.m_str;
- atom.m_str = atom.m_str.right (stretch);
- }
- if (withSubject)
- {
- mailHeader *header = cache->getHeader();
- if (header)
- atom.m_str += " " + header->getSubject();
- }
- entry.append (atom);
-
- atom.m_uds = UDS_URL;
- atom.m_str = encodedUrl; // utf-8
- if (atom.m_str[atom.m_str.length () - 1] != '/')
- atom.m_str += '/';
- atom.m_str += ";UID=" + uid;
- atom.m_long = 0;
- entry.append (atom);
-
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFREG;
- entry.append (atom);
-
- atom.m_uds = UDS_SIZE;
- atom.m_long = cache->getSize();
- entry.append (atom);
-
- atom.m_uds = UDS_MIME_TYPE;
- atom.m_str = "message/rfc822";
- atom.m_long = 0;
- entry.append (atom);
-
- atom.m_uds = UDS_USER;
- atom.m_str = myUser;
- entry.append (atom);
-
- atom.m_uds = TDEIO::UDS_ACCESS;
- atom.m_long = (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR;
- entry.append (atom);
-
- listEntry (entry, false);
- }
-}
-
-void
-IMAP4Protocol::doListEntry (const KURL & _url, const TQString & myBox,
- const imapList & item, bool appendPath)
-{
- KURL aURL = _url;
- aURL.setQuery (TQString());
- UDSEntry entry;
- UDSAtom atom;
- int hdLen = item.hierarchyDelimiter().length();
-
- {
- // mailboxName will be appended to the path if appendPath is true
- TQString mailboxName = item.name ();
-
- // some beautification
- if (mailboxName.find (myBox) == 0 && mailboxName.length() > myBox.length())
- {
- mailboxName =
- mailboxName.right (mailboxName.length () - myBox.length ());
- }
- if (mailboxName[0] == '/')
- mailboxName = mailboxName.right (mailboxName.length () - 1);
- if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
- mailboxName = mailboxName.right(mailboxName.length () - hdLen);
- if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
- mailboxName.truncate(mailboxName.length () - hdLen);
-
- atom.m_uds = UDS_NAME;
- if (!item.hierarchyDelimiter().isEmpty() &&
- mailboxName.find(item.hierarchyDelimiter()) != -1)
- atom.m_str = mailboxName.section(item.hierarchyDelimiter(), -1);
- else
- atom.m_str = mailboxName;
-
- // konqueror will die with an assertion failure otherwise
- if (atom.m_str.isEmpty ())
- atom.m_str = "..";
-
- if (!atom.m_str.isEmpty ())
- {
- atom.m_long = 0;
- entry.append (atom);
-
- if (!item.noSelect ())
- {
- atom.m_uds = UDS_MIME_TYPE;
- if (!item.noInferiors ())
- {
- atom.m_str = "message/directory";
- } else {
- atom.m_str = "message/digest";
- }
- atom.m_long = 0;
- entry.append (atom);
- mailboxName += '/';
-
- // explicitly set this as a directory for KFileDialog
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFDIR;
- entry.append (atom);
- }
- else if (!item.noInferiors ())
- {
- atom.m_uds = UDS_MIME_TYPE;
- atom.m_str = "inode/directory";
- atom.m_long = 0;
- entry.append (atom);
- mailboxName += '/';
-
- // explicitly set this as a directory for KFileDialog
- atom.m_uds = UDS_FILE_TYPE;
- atom.m_str = TQString();
- atom.m_long = S_IFDIR;
- entry.append (atom);
- }
- else
- {
- atom.m_uds = UDS_MIME_TYPE;
- atom.m_str = "unknown/unknown";
- atom.m_long = 0;
- entry.append (atom);
- }
-
- atom.m_uds = UDS_URL;
- TQString path = aURL.path();
- atom.m_str = aURL.url (0, 106); // utf-8
- if (appendPath)
- {
- if (path[path.length() - 1] == '/' && !path.isEmpty() && path != "/")
- path.truncate(path.length() - 1);
- if (!path.isEmpty() && path != "/"
- && path.right(hdLen) != item.hierarchyDelimiter()) {
- path += item.hierarchyDelimiter();
- }
- path += mailboxName;
- if (path.upper() == "/INBOX/") {
- // make sure the client can rely on INBOX
- path = path.upper();
- }
- }
- aURL.setPath(path);
- atom.m_str = aURL.url(0, 106); // utf-8
- atom.m_long = 0;
- entry.append (atom);
-
- atom.m_uds = UDS_USER;
- atom.m_str = myUser;
- entry.append (atom);
-
- atom.m_uds = UDS_ACCESS;
- atom.m_long = S_IRUSR | S_IXUSR | S_IWUSR;
- entry.append (atom);
-
- atom.m_uds = UDS_EXTRA;
- atom.m_str = item.attributesAsString();
- atom.m_long = 0;
- entry.append (atom);
-
- listEntry (entry, false);
- }
- }
-}
-
-enum IMAP_TYPE
-IMAP4Protocol::parseURL (const KURL & _url, TQString & _box,
- TQString & _section, TQString & _type, TQString & _uid,
- TQString & _validity, TQString & _hierarchyDelimiter,
- TQString & _info, bool cache)
-{
- enum IMAP_TYPE retVal;
- retVal = ITYPE_UNKNOWN;
-
- imapParser::parseURL (_url, _box, _section, _type, _uid, _validity, _info);
-// kdDebug(7116) << "URL: query - '" << KURL::decode_string(_url.query()) << "'" << endl;
-
- // get the delimiter
- TQString myNamespace = namespaceForBox( _box );
- kdDebug(7116) << "IMAP4::parseURL - namespace=" << myNamespace << endl;
- if ( namespaceToDelimiter.contains(myNamespace) )
- {
- _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
- kdDebug(7116) << "IMAP4::parseURL - delimiter=" << _hierarchyDelimiter << endl;
- }
-
- if (!_box.isEmpty ())
- {
- kdDebug(7116) << "IMAP4::parseURL - box=" << _box << endl;
-
- if (makeLogin ())
- {
- if (getCurrentBox () != _box ||
- _type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK")
- {
- if ( cache )
- {
- // assume a normal box
- retVal = ITYPE_DIR_AND_BOX;
- } else
- {
- // start a listing for the box to get the type
- imapCommand *cmd;
-
- cmd = doCommand (imapCommand::clientList ("", _box));
- if (cmd->result () == "OK")
- {
- for (TQValueListIterator < imapList > it = listResponses.begin ();
- it != listResponses.end (); ++it)
- {
- //kdDebug(7116) << "IMAP4::parseURL - checking " << _box << " to " << (*it).name() << endl;
- if (_box == (*it).name ())
- {
- if ( !(*it).hierarchyDelimiter().isEmpty() )
- _hierarchyDelimiter = (*it).hierarchyDelimiter();
- if ((*it).noSelect ())
- {
- retVal = ITYPE_DIR;
- }
- else if ((*it).noInferiors ())
- {
- retVal = ITYPE_BOX;
- }
- else
- {
- retVal = ITYPE_DIR_AND_BOX;
- }
- }
- }
- // if we got no list response for the box see if it's a prefix
- if ( retVal == ITYPE_UNKNOWN &&
- namespaceToDelimiter.contains(_box) ) {
- retVal = ITYPE_DIR;
- }
- } else {
- kdDebug(7116) << "IMAP4::parseURL - got error for " << _box << endl;
- }
- completeQueue.removeRef (cmd);
- } // cache
- }
- else // current == box
- {
- retVal = ITYPE_BOX;
- }
- }
- else
- kdDebug(7116) << "IMAP4::parseURL: no login!" << endl;
-
- }
- else // empty box
- {
- // the root is just a dir
- kdDebug(7116) << "IMAP4: parseURL: box [root]" << endl;
- retVal = ITYPE_DIR;
- }
-
- // see if it is a real sequence or a simple uid
- if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
- {
- if (!_uid.isEmpty ())
- {
- if (_uid.find (':') == -1 && _uid.find (',') == -1
- && _uid.find ('*') == -1)
- retVal = ITYPE_MSG;
- }
- }
- if (retVal == ITYPE_MSG)
- {
- if ( (_section.find ("BODY.PEEK[", 0, false) != -1 ||
- _section.find ("BODY[", 0, false) != -1) &&
- _section.find(".MIME") == -1 &&
- _section.find(".HEADER") == -1 )
- retVal = ITYPE_ATTACH;
- }
- if ( _hierarchyDelimiter.isEmpty() &&
- (_type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK") )
- {
- // this shouldn't happen but when the delimiter is really empty
- // we try to reconstruct it from the URL
- if (!_box.isEmpty())
- {
- int start = _url.path().findRev(_box);
- if (start != -1)
- _hierarchyDelimiter = _url.path().mid(start-1, start);
- kdDebug(7116) << "IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
- << " from URL " << _url.path() << endl;
- }
- if (_hierarchyDelimiter.isEmpty())
- _hierarchyDelimiter = "/";
- }
- kdDebug(7116) << "IMAP4::parseURL - return " << retVal << endl;
-
- return retVal;
-}
-
-int
-IMAP4Protocol::outputLine (const TQCString & _str, int len)
-{
- if (len == -1) {
- len = _str.length();
- }
-
- if (cacheOutput)
- {
- if ( !outputBuffer.isOpen() ) {
- outputBuffer.open(IO_WriteOnly);
- }
- outputBuffer.at(outputBufferIndex);
- outputBuffer.writeBlock(_str.data(), len);
- outputBufferIndex += len;
- return 0;
- }
-
- TQByteArray temp;
- bool relay = relayEnabled;
-
- relayEnabled = true;
- temp.setRawData (_str.data (), len);
- parseRelay (temp);
- temp.resetRawData (_str.data (), len);
-
- relayEnabled = relay;
- return 0;
-}
-
-void IMAP4Protocol::flushOutput(TQString contentEncoding)
-{
- // send out cached data to the application
- if (outputBufferIndex == 0)
- return;
- outputBuffer.close();
- outputCache.resize(outputBufferIndex);
- if (decodeContent)
- {
- // get the coding from the MIME header
- TQByteArray decoded;
- if (contentEncoding.find("quoted-printable", 0, false) == 0)
- decoded = KCodecs::quotedPrintableDecode(outputCache);
- else if (contentEncoding.find("base64", 0, false) == 0)
- KCodecs::base64Decode(outputCache, decoded);
- else
- decoded = outputCache;
-
- TQString mimetype = KMimeType::findByContent( decoded )->name();
- kdDebug(7116) << "IMAP4::flushOutput - mimeType " << mimetype << endl;
- mimeType(mimetype);
- decodeContent = false;
- data( decoded );
- } else {
- data( outputCache );
- }
- mProcessedSize += outputBufferIndex;
- processedSize( mProcessedSize );
- outputBufferIndex = 0;
- outputCache[0] = '\0';
- outputBuffer.setBuffer(outputCache);
-}
-
-ssize_t IMAP4Protocol::myRead(void *data, ssize_t len)
-{
- if (readBufferLen)
- {
- ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
- memcpy(data, readBuffer, copyLen);
- readBufferLen -= copyLen;
- if (readBufferLen) memcpy(readBuffer, &readBuffer[copyLen], readBufferLen);
- return copyLen;
- }
- if (!isConnectionValid()) return 0;
- waitForResponse( responseTimeout() );
- return read(data, len);
-}
-
-bool
-IMAP4Protocol::assureBox (const TQString & aBox, bool readonly)
-{
- if (aBox.isEmpty()) return false;
-
- imapCommand *cmd = 0;
-
- if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
- {
- // open the box with the appropriate mode
- kdDebug(7116) << "IMAP4Protocol::assureBox - opening box" << endl;
- selectInfo = imapInfo();
- cmd = doCommand (imapCommand::clientSelect (aBox, readonly));
- bool ok = cmd->result() == "OK";
- TQString cmdInfo = cmd->resultInfo();
- completeQueue.removeRef (cmd);
-
- if (!ok)
- {
- bool found = false;
- cmd = doCommand (imapCommand::clientList ("", aBox));
- if (cmd->result () == "OK")
- {
- for (TQValueListIterator < imapList > it = listResponses.begin ();
- it != listResponses.end (); ++it)
- {
- if (aBox == (*it).name ()) found = true;
- }
- }
- completeQueue.removeRef (cmd);
- if (found) {
- if (cmdInfo.find("permission", 0, false) != -1) {
- // not allowed to enter this folder
- error(ERR_ACCESS_DENIED, cmdInfo);
- } else {
- error(ERR_SLAVE_DEFINED, i18n("Unable to open folder %1. The server replied: %2").arg(aBox).arg(cmdInfo));
- }
- } else {
- error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
- }
- return false;
- }
- }
- else
- {
- // Give the server a chance to deliver updates every ten seconds.
- // Doing this means a server roundtrip and since assureBox is called
- // after every mail, we do it with a timeout.
- kdDebug(7116) << "IMAP4Protocol::assureBox - reusing box" << endl;
- if ( mTimeOfLastNoop.secsTo( TQDateTime::currentDateTime() ) > 10 ) {
- cmd = doCommand (imapCommand::clientNoop ());
- completeQueue.removeRef (cmd);
- mTimeOfLastNoop = TQDateTime::currentDateTime();
- kdDebug(7116) << "IMAP4Protocol::assureBox - noop timer fired" << endl;
- }
- }
-
- // if it is the mode we want
- if (!getSelected().readWrite() && !readonly)
- {
- error(TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);
- return false;
- }
-
- return true;
-}