diff options
Diffstat (limited to 'kioslaves/imap4/imap4.cc')
-rw-r--r-- | kioslaves/imap4/imap4.cc | 2734 |
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; -} |