68 #include <sys/types.h>
73 #include <sasl/sasl.h>
77 #include <qdatetime.h>
79 #include <kprotocolmanager.h>
80 #include <kcomponentdata.h>
81 #include <kmessagebox.h>
83 #include <kio/connection.h>
84 #include <kio/slaveinterface.h>
86 #include <kmimetype.h>
91 #include "kdemacros.h"
93 #define IMAP_PROTOCOL "imap"
94 #define IMAP_SSL_PROTOCOL "imaps"
95 const int ImapPort = 143;
96 const int ImapsPort = 993;
102 void sigalrm_handler (
int);
103 KDE_EXPORT
int kdemain (
int argc,
char **argv);
107 kdemain (
int argc,
char **argv)
109 kDebug(7116) <<
"IMAP4::kdemain";
111 KComponentData instance (
"kio_imap4");
114 fprintf(stderr,
"Usage: kio_imap4 protocol domain-socket1 domain-socket2\n");
124 if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
126 else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
130 slave->dispatchLoop ();
139 sigchld_handler (
int signo)
144 const int save_errno = errno;
147 while (signo == SIGCHLD)
149 pid = waitpid (-1, &status, WNOHANG);
155 KDE_signal (SIGCHLD, sigchld_handler);
163 IMAP4Protocol::IMAP4Protocol (
const QByteArray & pool,
const QByteArray & app,
bool isSSL)
164 :TCPSlaveBase ((isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool, app, isSSL),
168 relayEnabled( false ),
169 cacheOutput( false ),
170 decodeContent( false ),
171 outputBuffer(&outputCache),
172 outputBufferIndex(0),
175 mTimeOfLastNoop( QDateTime() )
177 readBuffer[0] = 0x00;
180 IMAP4Protocol::~IMAP4Protocol ()
182 disconnectFromHost();
183 kDebug(7116) <<
"IMAP4: Finishing";
189 if (!makeLogin())
return;
190 kDebug(7116) <<
"IMAP4::get -" << _url.prettyUrl();
191 QString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
192 enum IMAP_TYPE aEnum =
193 parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
194 if (aEnum != ITYPE_ATTACH)
195 mimeType (getMimeType(aEnum));
196 if (aInfo ==
"DECODE")
197 decodeContent =
true;
199 if (aSequence ==
"0:0" && getState() == ISTATE_SELECT)
202 completeQueue.removeAll(cmd);
205 if (aSequence.isEmpty ())
212 if (!assureBox (aBox,
true))
return;
215 if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
216 && selectInfo.uidValidity () != aValidity.toULong ())
219 error (ERR_COULD_NOT_READ, _url.prettyUrl());
232 QString aUpper = aSection.toUpper();
233 if (aUpper.contains(
"STRUCTURE"))
235 aSection =
"BODYSTRUCTURE";
237 else if (aUpper.contains(
"ENVELOPE"))
239 aSection =
"UID RFC822.SIZE FLAGS ENVELOPE";
240 if (hasCapability(
"IMAP4rev1")) {
241 aSection +=
" BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
244 aSection +=
" RFC822.HEADER.LINES (REFERENCES)";
247 else if (aUpper ==
"HEADER")
249 aSection =
"UID RFC822.HEADER RFC822.SIZE FLAGS";
251 else if (aUpper.contains(
"BODY.PEEK["))
253 if (aUpper.contains(
"BODY.PEEK[]"))
255 if (!hasCapability(
"IMAP4rev1"))
256 aSection.replace(
"BODY.PEEK[]",
"RFC822.PEEK");
258 aSection.prepend(
"UID RFC822.SIZE FLAGS ");
260 else if (aSection.isEmpty())
262 aSection =
"UID BODY[] RFC822.SIZE FLAGS";
264 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
269 (
"Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
270 if (selectInfo.recentAvailable ())
271 outputLineStr (
"X-Recent: " +
272 QString::number(selectInfo.recent ()) +
"\r\n");
273 if (selectInfo.countAvailable ())
274 outputLineStr (
"X-Count: " + QString::number(selectInfo.count ()) +
276 if (selectInfo.unseenAvailable ())
277 outputLineStr (
"X-Unseen: " +
278 QString::number(selectInfo.unseen ()) +
"\r\n");
279 if (selectInfo.uidValidityAvailable ())
280 outputLineStr (
"X-uidValidity: " +
281 QString::number(selectInfo.uidValidity ()) +
283 if (selectInfo.uidNextAvailable ())
284 outputLineStr (
"X-UidNext: " +
285 QString::number(selectInfo.uidNext ()) +
"\r\n");
286 if (selectInfo.flagsAvailable ())
287 outputLineStr (
"X-Flags: " + QString::number(selectInfo.flags ()) +
289 if (selectInfo.permanentFlagsAvailable ())
290 outputLineStr (
"X-PermanentFlags: " +
291 QString::number(selectInfo.permanentFlags ()) +
"\r\n");
292 if (selectInfo.readWriteAvailable ()) {
293 if (selectInfo.readWrite()) {
304 if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
307 if (aSequence !=
"0:0")
309 QString contentEncoding;
310 if (aEnum == ITYPE_ATTACH && decodeContent)
313 QString mySection = aSection;
314 mySection.replace(
']',
".MIME]");
318 while (!parseLoop ()) {}
320 while (!cmd->isComplete ());
321 completeQueue.removeAll (cmd);
323 if (getLastHandled() && getLastHandled()->getHeader())
324 contentEncoding = getLastHandled()->getHeader()->getEncoding();
334 aUpper = aSection.toUpper();
337 while (!(res = parseLoop())) {}
338 if (res == -1)
break;
341 imapCache *cache = getLastHandled ();
343 lastone = cache->getHeader ();
345 if (cmd && !cmd->isComplete ())
347 if ( aUpper.contains(
"BODYSTRUCTURE")
348 || aUpper.contains(
"FLAGS")
349 || aUpper.contains(
"UID")
350 || aUpper.contains(
"ENVELOPE")
351 || (aUpper.contains(
"BODY.PEEK[0]")
352 && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
354 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
359 if (cache->getUid () != 0)
360 outputLineStr (
"X-UID: " +
361 QString::number(cache->getUid ()) +
"\r\n");
362 if (cache->getSize () != 0)
363 outputLineStr (
"X-Length: " +
364 QString::number(cache->getSize ()) +
"\r\n");
365 if (!cache->getDate ().isEmpty())
366 outputLineStr (
"X-Date: " + cache->getDate () +
"\r\n");
367 if (cache->getFlags () != 0)
368 outputLineStr (
"X-Flags: " +
369 QString::number(cache->getFlags ()) +
"\r\n");
370 }
else cacheOutput =
true;
371 if ( lastone && !decodeContent )
372 lastone->outputPart (*
this);
378 while (cmd && !cmd->isComplete ());
379 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
385 completeQueue.removeAll (cmd);
390 data (QByteArray ());
393 relayEnabled =
false;
395 kDebug(7116) <<
"IMAP4::get - finished";
401 kDebug(7116) <<
" IMAP4::listDir -" << _url.prettyUrl();
403 if (_url.path().isEmpty())
412 QString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
414 enum IMAP_TYPE myType =
415 parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
416 myDelimiter, myInfo,
true);
418 if (!makeLogin())
return;
420 if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
422 QString listStr = myBox;
425 if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
426 mySection !=
"FOLDERONLY")
427 listStr += myDelimiter;
429 if (mySection.isEmpty())
432 }
else if (mySection ==
"COMPLETE") {
435 kDebug(7116) <<
"IMAP4Protocol::listDir - listStr=" << listStr;
438 (myLType ==
"LSUB" || myLType ==
"LSUBNOCHECK")));
439 if (cmd->result () ==
"OK")
444 if ( aURL.path().contains(
';') )
445 aURL.setPath(aURL.path().left(aURL.path().indexOf(
';')));
447 kDebug(7116) <<
"IMAP4Protocol::listDir - got" << listResponses.count ();
449 if (myLType ==
"LSUB")
452 QList<imapList> listResponsesSave = listResponses;
454 for (QList< imapList >::Iterator it = listResponsesSave.begin ();
455 it != listResponsesSave.end (); ++it)
458 for (QList< imapList >::Iterator it2 = listResponses.begin ();
459 it2 != listResponses.end (); ++it2)
461 if ((*it2).name() == (*it).name())
470 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
472 kDebug(7116) <<
"IMAP4Protocol::listDir - suppress" << (*it).name();
474 listResponses = listResponsesSave;
478 for (QList< imapList >::Iterator it = listResponses.begin ();
479 it != listResponses.end (); ++it)
481 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
485 listEntry (entry,
true);
489 error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyUrl());
490 completeQueue.removeAll (cmd);
493 completeQueue.removeAll (cmd);
495 if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
496 && myLType !=
"LIST" && myLType !=
"LSUB" && myLType !=
"LSUBNOCHECK")
499 aURL.setQuery (QString());
500 const QString encodedUrl = aURL.url(KUrl::LeaveTrailingSlash);
502 if (!_url.query ().isEmpty ())
504 QString query = KUrl::fromPercentEncoding (_url.query().toLatin1());
505 query = query.right (query.length () - 1);
506 if (!query.isEmpty())
510 if (!assureBox (myBox,
true))
return;
512 if (!selectInfo.countAvailable() || selectInfo.count())
515 if (cmd->result() !=
"OK")
517 error(ERR_UNSUPPORTED_ACTION, _url.prettyUrl());
518 completeQueue.removeAll (cmd);
521 completeQueue.removeAll (cmd);
523 QStringList list = getResults ();
526 if (selectInfo.uidNextAvailable ())
527 stretch = QString::number(selectInfo.uidNext ()).length ();
531 for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd();
534 fake.setUid((*it).toULong());
535 doListEntry (encodedUrl, stretch, &fake);
538 listEntry (entry,
true);
544 if (!assureBox (myBox,
true))
return;
546 kDebug(7116) <<
"IMAP4: select returned:";
547 if (selectInfo.recentAvailable ())
548 kDebug(7116) <<
"Recent:" << selectInfo.recent () <<
"d";
549 if (selectInfo.countAvailable ())
550 kDebug(7116) <<
"Count:" << selectInfo.count () <<
"d";
551 if (selectInfo.unseenAvailable ())
552 kDebug(7116) <<
"Unseen:" << selectInfo.unseen () <<
"d";
553 if (selectInfo.uidValidityAvailable ())
554 kDebug(7116) <<
"uidValidity:" << selectInfo.uidValidity () <<
"d";
555 if (selectInfo.flagsAvailable ())
556 kDebug(7116) <<
"Flags:" << selectInfo.flags () <<
"d";
557 if (selectInfo.permanentFlagsAvailable ())
558 kDebug(7116) <<
"PermanentFlags:" << selectInfo.permanentFlags () <<
"d";
559 if (selectInfo.readWriteAvailable ())
560 kDebug(7116) <<
"Access:" << (selectInfo.readWrite ()?
"Read/Write" :
"Read only");
563 if (selectInfo.uidValidityAvailable ()
564 && selectInfo.uidValidity () != myValidity.toULong ())
569 newUrl.setPath (
'/' + myBox +
";UIDVALIDITY=" +
570 QString::number(selectInfo.uidValidity ()));
571 kDebug(7116) <<
"IMAP4::listDir - redirecting to" << newUrl.prettyUrl();
572 redirection (newUrl);
578 if (selectInfo.count () > 0)
582 if (selectInfo.uidNextAvailable ())
583 stretch = QString::number(selectInfo.uidNext ()).length ();
587 if (mySequence.isEmpty()) mySequence =
"1:*";
589 bool withSubject = mySection.isEmpty();
590 if (mySection.isEmpty()) mySection =
"UID RFC822.SIZE ENVELOPE";
592 bool withFlags = mySection.toUpper().contains(
"FLAGS") ;
595 clientFetch (mySequence, mySection));
599 while (!parseLoop ()) {}
601 cache = getLastHandled ();
603 if (cache && !fetch->isComplete())
604 doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
606 while (!fetch->isComplete ());
608 listEntry (entry,
true);
612 if ( !selectInfo.alert().isNull() ) {
613 if ( !myBox.isEmpty() ) {
614 warning( i18n(
"Message from %1 while processing '%2': %3", myHost, myBox, selectInfo.alert() ) );
616 warning( i18n(
"Message from %1: %2", myHost, selectInfo.alert() ) );
618 selectInfo.setAlert( 0 );
621 kDebug(7116) <<
"IMAP4Protocol::listDir - Finishing listDir";
626 IMAP4Protocol::setHost (
const QString & _host, quint16 _port,
627 const QString & _user,
const QString & _pass)
629 if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
632 if (!myHost.isEmpty ())
636 myPort = (mySSL) ? ImapsPort : ImapPort;
650 mProcessedSize += buffer.size();
651 processedSize( mProcessedSize );
652 }
else if (cacheOutput)
655 if ( !outputBuffer.isOpen() ) {
656 outputBuffer.open(QIODevice::WriteOnly);
658 outputBuffer.seek( outputBufferIndex );
659 outputBuffer.write(buffer, buffer.size());
660 outputBufferIndex += buffer.size();
674 const long int bufLen = 8192;
677 while (buffer.size() < len )
679 ssize_t readLen = myRead(buf, qMin(len - buffer.size(), bufLen - 1));
682 kDebug(7116) <<
"parseRead: readLen == 0 - connection broken";
683 error (ERR_CONNECTION_BROKEN, myHost);
684 setState(ISTATE_CONNECT);
688 if (relay > buffer.size())
690 QByteArray relayData;
691 ssize_t relbuf = relay - buffer.size();
692 int currentRelay = qMin(relbuf, readLen);
693 relayData = QByteArray::fromRawData(buf, currentRelay);
698 QBuffer stream( &buffer );
699 stream.open (QIODevice::WriteOnly);
700 stream.seek (buffer.size ());
701 stream.write (buf, readLen);
705 return (buffer.size() == len);
711 if (myHost.isEmpty())
return false;
715 if (readBufferLen > 0)
717 while (copyLen < readBufferLen && readBuffer[copyLen] !=
'\n') copyLen++;
718 if (copyLen < readBufferLen) copyLen++;
721 QByteArray relayData;
723 if (copyLen < (ssize_t) relay)
725 relayData = QByteArray::fromRawData (readBuffer, relay);
732 int oldsize = buffer.size();
733 buffer.resize(oldsize + copyLen);
734 memcpy(buffer.data() + oldsize, readBuffer, copyLen);
738 readBufferLen -= copyLen;
740 memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
741 if (buffer[buffer.size() - 1] ==
'\n')
return true;
745 kDebug(7116) <<
"parseReadLine - connection broken";
746 error (ERR_CONNECTION_BROKEN, myHost);
747 setState(ISTATE_CONNECT);
751 if (!waitForResponse( responseTimeout() ))
753 error(ERR_SERVER_TIMEOUT, myHost);
754 setState(ISTATE_CONNECT);
758 readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
759 if (readBufferLen == 0)
761 kDebug(7116) <<
"parseReadLine: readBufferLen == 0 - connection broken";
762 error (ERR_CONNECTION_BROKEN, myHost);
763 setState(ISTATE_CONNECT);
771 IMAP4Protocol::setSubURL (
const KUrl & _url)
773 kDebug(7116) <<
"IMAP4::setSubURL -" << _url.prettyUrl();
774 KIO::TCPSlaveBase::setSubUrl (_url);
778 IMAP4Protocol::put (
const KUrl & _url,
int, KIO::JobFlags)
780 kDebug(7116) <<
"IMAP4::put -" << _url.prettyUrl();
782 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
783 enum IMAP_TYPE aType =
784 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
787 if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
789 if (aBox[aBox.length () - 1] ==
'/')
790 aBox = aBox.right (aBox.length () - 1);
793 if (cmd->result () !=
"OK") {
794 error (ERR_COULD_NOT_WRITE, _url.prettyUrl());
795 completeQueue.removeAll (cmd);
798 completeQueue.removeAll (cmd);
802 QList < QByteArray* > bufferList;
809 QByteArray *buffer =
new QByteArray ();
811 result = readData (*buffer);
814 bufferList.append (buffer);
824 error (ERR_ABORTED, _url.prettyUrl());
830 while (!parseLoop ()) {}
833 if (!cmd->isComplete () && !getContinuation ().isEmpty ())
839 QListIterator<QByteArray *> it(bufferList);
841 while (it.hasNext() && sendOk)
846 (write (buffer->data (), buffer->size ()) ==
847 (ssize_t) buffer->size ());
848 wrote += buffer->size ();
849 processedSize(wrote);
853 error (ERR_CONNECTION_BROKEN, myHost);
854 completeQueue.removeAll (cmd);
855 setState(ISTATE_CONNECT);
862 while (!cmd->isComplete () && getState() != ISTATE_NO)
864 if ( getState() == ISTATE_NO ) {
867 error( ERR_CONNECTION_BROKEN, myHost );
868 completeQueue.removeAll (cmd);
872 else if (cmd->result () !=
"OK") {
873 error( ERR_SLAVE_DEFINED, cmd->resultInfo() );
874 completeQueue.removeAll (cmd);
879 if (hasCapability(
"UIDPLUS"))
881 QString uid = cmd->resultInfo();
882 if ( uid.contains(
"APPENDUID") )
884 uid = uid.section(
' ', 2, 2);
885 uid.truncate(uid.length()-1);
886 infoMessage(
"UID "+uid);
890 else if (aBox == getCurrentBox ())
894 clientSelect (aBox, !selectInfo.readWrite ()));
895 completeQueue.removeAll (cmd);
903 error (ERR_SLAVE_DEFINED, cmd->resultInfo());
904 completeQueue.removeAll (cmd);
908 completeQueue.removeAll (cmd);
917 kDebug(7116) <<
"IMAP4::mkdir -" << _url.prettyUrl();
918 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
919 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
920 kDebug(7116) <<
"IMAP4::mkdir - create" << aBox;
923 if (cmd->result () !=
"OK")
925 kDebug(7116) <<
"IMAP4::mkdir -" << cmd->resultInfo();
926 error (ERR_COULD_NOT_MKDIR, _url.prettyUrl());
927 completeQueue.removeAll (cmd);
930 completeQueue.removeAll (cmd);
933 enum IMAP_TYPE type =
934 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
935 if (type == ITYPE_BOX)
937 bool ask = ( aInfo.contains(
"ASKUSER" ) );
939 messageBox(QuestionYesNo,
940 i18n(
"The following folder will be created on the server: %1 "
941 "What do you want to store in this folder?", aBox ),
942 i18n(
"Create Folder"),
943 i18n(
"&Messages"), i18n(
"&Subfolders")) == KMessageBox::No )
946 completeQueue.removeAll (cmd);
948 if (cmd->result () !=
"OK")
950 error (ERR_COULD_NOT_MKDIR, _url.prettyUrl());
951 completeQueue.removeAll (cmd);
954 completeQueue.removeAll (cmd);
959 completeQueue.removeAll(cmd);
965 IMAP4Protocol::copy (
const KUrl & src,
const KUrl & dest,
int, KIO::JobFlags flags)
967 kDebug(7116) <<
"IMAP4::copy - [" << ((flags & KIO::Overwrite) ?
"Overwrite" :
"NoOverwrite") <<
"]" << src.prettyUrl() <<
" ->" << dest.prettyUrl();
968 QString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
969 QString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
970 enum IMAP_TYPE sType =
971 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
972 enum IMAP_TYPE dType =
973 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
976 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
979 int sub = dBox.indexOf (sBox);
986 QString subDir = dBox.right (dBox.length () - dBox.lastIndexOf (
'/'));
987 QString topDir = dBox.left (sub);
988 testDir.setPath (
'/' + topDir);
990 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
993 kDebug(7116) <<
"IMAP4::copy - checking this destination" << topDir;
995 if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
997 kDebug(7116) <<
"IMAP4::copy - assuming this destination" << topDir;
1004 topDir =
'/' + topDir + subDir;
1005 testDir.setPath (topDir);
1006 kDebug(7116) <<
"IMAP4::copy - checking this destination" << topDir;
1008 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
1010 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
1016 if (cmd->result () ==
"OK")
1018 kDebug(7116) <<
"IMAP4::copy - assuming this destination" << topDir;
1024 completeQueue.removeAll (cmd);
1026 if (cmd->result () ==
"OK")
1029 error (ERR_COULD_NOT_WRITE, dest.prettyUrl());
1031 completeQueue.removeAll (cmd);
1037 if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
1040 if (!assureBox(sBox,
true))
return;
1041 kDebug(7116) <<
"IMAP4::copy -" << sBox <<
" ->" << dBox;
1046 if (cmd->result () !=
"OK")
1048 kError(5006) <<
"IMAP4::copy -" << cmd->resultInfo();
1049 error (ERR_COULD_NOT_WRITE, dest.prettyUrl());
1050 completeQueue.removeAll (cmd);
1053 if (hasCapability(
"UIDPLUS"))
1055 QString uid = cmd->resultInfo();
1056 if ( uid.contains(
"COPYUID") )
1058 uid = uid.section(
' ', 2, 3);
1059 uid.truncate(uid.length()-1);
1060 infoMessage(
"UID "+uid);
1064 completeQueue.removeAll (cmd);
1068 error (ERR_ACCESS_DENIED, src.prettyUrl());
1077 kDebug(7116) <<
"IMAP4::del - [" << (isFile ?
"File" :
"NoFile") <<
"]" << _url.prettyUrl();
1078 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1079 enum IMAP_TYPE aType =
1080 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1085 case ITYPE_DIR_AND_BOX:
1086 if (!aSequence.isEmpty ())
1088 if (aSequence ==
"*")
1090 if (!assureBox (aBox,
false))
return;
1092 if (cmd->result () !=
"OK") {
1093 error (ERR_CANNOT_DELETE, _url.prettyUrl());
1094 completeQueue.removeAll (cmd);
1097 completeQueue.removeAll (cmd);
1102 if (!assureBox (aBox,
false))
return;
1105 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1106 if (cmd->result () !=
"OK") {
1107 error (ERR_CANNOT_DELETE, _url.prettyUrl());
1108 completeQueue.removeAll (cmd);
1111 completeQueue.removeAll (cmd);
1116 if (getCurrentBox() == aBox)
1119 completeQueue.removeAll(cmd);
1120 setState(ISTATE_LOGIN);
1124 completeQueue.removeAll(cmd);
1127 if (cmd->result () !=
"OK")
1129 completeQueue.removeAll(cmd);
1130 if (!assureBox(aBox,
false))
return;
1131 bool stillOk =
true;
1134 CommandPtr cmd = doCommand(
1136 if (cmd->result () !=
"OK") stillOk =
false;
1137 completeQueue.removeAll(cmd);
1142 if (cmd->result () !=
"OK") stillOk =
false;
1143 completeQueue.removeAll(cmd);
1144 setState(ISTATE_LOGIN);
1149 if (cmd->result () !=
"OK") stillOk =
false;
1150 completeQueue.removeAll(cmd);
1154 error (ERR_COULD_NOT_RMDIR, _url.prettyUrl());
1158 completeQueue.removeAll (cmd);
1166 if (cmd->result () !=
"OK") {
1167 error (ERR_COULD_NOT_RMDIR, _url.prettyUrl());
1168 completeQueue.removeAll (cmd);
1171 completeQueue.removeAll (cmd);
1178 if (!assureBox (aBox,
false))
return;
1181 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1182 if (cmd->result () !=
"OK") {
1183 error (ERR_CANNOT_DELETE, _url.prettyUrl());
1184 completeQueue.removeAll (cmd);
1187 completeQueue.removeAll (cmd);
1193 error (ERR_CANNOT_DELETE, _url.prettyUrl());
1218 kDebug(7116) <<
"IMAP4Protocol::special";
1219 if (!makeLogin())
return;
1221 QDataStream stream( aData );
1232 stream >> src >> dest;
1233 copy(src, dest, 0, KIO::DefaultFlags);
1239 infoMessage(imapCapabilities.join(
" "));
1247 if (cmd->result () !=
"OK")
1249 kDebug(7116) <<
"NOOP did not succeed - connection broken";
1250 completeQueue.removeAll (cmd);
1251 error (ERR_CONNECTION_BROKEN, myHost);
1254 completeQueue.removeAll (cmd);
1262 infoMessage( imapNamespaces.join(
",") );
1271 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1272 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1274 if (cmd->result () !=
"OK")
1276 completeQueue.removeAll (cmd);
1277 error(ERR_SLAVE_DEFINED, i18n(
"Unsubscribe of folder %1 "
1278 "failed. The server returned: %2",
1280 cmd->resultInfo()));
1283 completeQueue.removeAll (cmd);
1292 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1293 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1295 if (cmd->result () !=
"OK")
1297 completeQueue.removeAll (cmd);
1298 error(ERR_SLAVE_DEFINED, i18n(
"Subscribe of folder %1 "
1299 "failed. The server returned: %2",
1301 cmd->resultInfo()));
1304 completeQueue.removeAll (cmd);
1313 if ( hasCapability(
"ACL" ) ) {
1316 error( ERR_UNSUPPORTED_ACTION, QString::fromLatin1(
"ACL") );
1325 if ( hasCapability(
"ANNOTATEMORE" ) ) {
1328 error( ERR_UNSUPPORTED_ACTION, QString::fromLatin1(
"ANNOTATEMORE") );
1337 if ( hasCapability(
"QUOTA" ) ) {
1338 specialQuotaCommand( cmd, stream );
1340 error( ERR_UNSUPPORTED_ACTION, QString::fromLatin1(
"QUOTA") );
1348 QByteArray newFlags;
1349 stream >> _url >> newFlags;
1351 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1352 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1353 if (!assureBox(aBox,
false))
return;
1356 QByteArray knownFlags =
"\\SEEN \\ANSWERED \\FLAGGED \\DRAFT";
1357 const imapInfo info = getSelected();
1358 if ( info.permanentFlagsAvailable() && (info.permanentFlags() & imapInfo::User) ) {
1359 knownFlags +=
" KMAILFORWARDED KMAILTODO KMAILWATCHED KMAILIGNORED $FORWARDED $TODO $WATCHED $IGNORED";
1363 clientStore (aSequence,
"-FLAGS.SILENT", knownFlags));
1364 if (cmd->result () !=
"OK")
1366 completeQueue.removeAll (cmd);
1367 error(ERR_SLAVE_DEFINED, i18n(
"Changing the flags of message %1 "
1368 "failed with %2.", _url.prettyUrl(), cmd->result()));
1371 completeQueue.removeAll (cmd);
1372 if (!newFlags.isEmpty())
1375 clientStore (aSequence,
"+FLAGS.SILENT", newFlags));
1376 if (cmd->result () !=
"OK")
1378 completeQueue.removeAll (cmd);
1379 error(ERR_SLAVE_DEFINED, i18n(
"Silent Changing the flags of message %1 "
1380 "failed with %2.", _url.prettyUrl(), cmd->result()));
1383 completeQueue.removeAll (cmd);
1393 QByteArray newFlags;
1394 stream >> _url >> seen;
1396 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1397 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1398 if ( !assureBox(aBox,
true) )
1407 if (cmd->result () !=
"OK")
1409 completeQueue.removeAll (cmd);
1410 error(ERR_SLAVE_DEFINED,
1411 i18n(
"Changing the flags of message %1 failed.", _url.prettyUrl() ) );
1414 completeQueue.removeAll (cmd);
1432 kWarning(7116) <<
"Unknown command in special():" << tmp;
1433 error( ERR_UNSUPPORTED_ACTION, QString(QChar(tmp)) );
1444 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1445 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1451 stream >> user >> acl;
1452 kDebug(7116) <<
"SETACL" << aBox << user << acl;
1454 if (cmd->result () !=
"OK")
1456 error(ERR_SLAVE_DEFINED, i18n(
"Setting the Access Control List on folder %1 "
1457 "for user %2 failed. The server returned: %3",
1460 cmd->resultInfo()));
1463 completeQueue.removeAll (cmd);
1471 kDebug(7116) <<
"DELETEACL" << aBox << user;
1473 if (cmd->result () !=
"OK")
1475 error(ERR_SLAVE_DEFINED, i18n(
"Deleting the Access Control List on folder %1 "
1476 "for user %2 failed. The server returned: %3",
1479 cmd->resultInfo()));
1482 completeQueue.removeAll (cmd);
1488 kDebug(7116) <<
"GETACL" << aBox;
1490 if (cmd->result () !=
"OK")
1492 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1493 "failed. The server returned: %2",
1495 cmd->resultInfo()));
1502 kDebug(7116) << getResults();
1503 infoMessage(getResults().join(
"\"" ));
1510 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
1515 kDebug(7116) <<
"MYRIGHTS" << aBox;
1517 if (cmd->result () !=
"OK")
1519 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1520 "failed. The server returned: %2",
1522 cmd->resultInfo()));
1525 QStringList lst = getResults();
1526 kDebug(7116) <<
"myrights results:" << lst;
1527 if ( !lst.isEmpty() ) {
1528 Q_ASSERT( lst.count() == 1 );
1529 infoMessage( lst.first() );
1535 kWarning(7116) <<
"Unknown special ACL command:" << command;
1536 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
1543 kDebug(7116) <<
"IMAP4Protocol::specialSearchCommand";
1546 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1547 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1548 if (!assureBox(aBox,
true))
return;
1551 if (cmd->result () !=
"OK")
1553 error(ERR_SLAVE_DEFINED, i18n(
"Searching of folder %1 "
1554 "failed. The server returned: %2",
1556 cmd->resultInfo()));
1559 completeQueue.removeAll(cmd);
1560 QStringList lst = getResults();
1561 kDebug(7116) <<
"IMAP4Protocol::specialSearchCommand '" << aSection <<
1563 infoMessage( lst.join(
" " ) );
1571 kDebug(7116) <<
"IMAP4Protocol::specialCustomCommand" << endl;
1573 QString command, arguments;
1576 stream >> command >> arguments;
1582 if ( type ==
'N' ) {
1583 kDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: normal mode" << endl;
1585 if (cmd->result () !=
"OK")
1587 error( ERR_SLAVE_DEFINED,
1588 i18n(
"Custom command %1:%2 failed. The server returned: %3",
1589 command, arguments, cmd->resultInfo() ) );
1592 completeQueue.removeAll(cmd);
1593 QStringList lst = getResults();
1594 kDebug(7116) <<
"IMAP4Protocol::specialCustomCommand '" << command <<
1596 "' returns " << lst << endl;
1597 infoMessage( lst.join(
" " ) );
1605 if ( type ==
'E' ) {
1606 kDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: extended mode" << endl;
1608 while ( !parseLoop () ) {};
1611 if (!cmd->isComplete () && !getContinuation ().isEmpty ())
1613 const QByteArray buffer = arguments.toUtf8();
1616 bool sendOk = (write (buffer.data (), buffer.size ()) == (ssize_t)buffer.size ());
1617 processedSize( buffer.size() );
1620 error ( ERR_CONNECTION_BROKEN, myHost );
1621 completeQueue.removeAll ( cmd );
1622 setState(ISTATE_CONNECT);
1631 while (!parseLoop ()) {};
1633 while (!cmd->isComplete ());
1635 completeQueue.removeAll (cmd);
1637 QStringList lst = getResults();
1638 kDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: returns " << lst << endl;
1639 infoMessage( lst.join(
" " ) );
1651 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1652 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1662 QMap<QString, QString> attributes;
1663 stream >> entry >> attributes;
1664 kDebug(7116) <<
"SETANNOTATION" << aBox << entry << attributes.count() <<
" attributes";
1666 if (cmd->result () !=
"OK")
1668 error(ERR_SLAVE_DEFINED, i18n(
"Setting the annotation %1 on folder %2 "
1669 " failed. The server returned: %3",
1672 cmd->resultInfo()));
1675 completeQueue.removeAll (cmd);
1686 QStringList attributeNames;
1687 stream >> entry >> attributeNames;
1688 kDebug(7116) <<
"GETANNOTATION" << aBox << entry << attributeNames;
1690 if (cmd->result () !=
"OK")
1692 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the annotation %1 on folder %2 "
1693 "failed. The server returned: %3",
1696 cmd->resultInfo()));
1702 kDebug(7116) << getResults();
1703 infoMessage(getResults().join(
"\r" ));
1708 kWarning(7116) <<
"Unknown special annotate command:" << command;
1709 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
1714 IMAP4Protocol::specialQuotaCommand(
int command, QDataStream& stream )
1719 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1720 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1725 kDebug(7116) <<
"QUOTAROOT" << aBox;
1727 if (cmd->result () !=
"OK")
1729 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the quota root information on folder %1 "
1730 "failed. The server returned: %2",
1731 _url.prettyUrl(), cmd->resultInfo()));
1734 infoMessage(getResults().join(
"\r" ));
1740 kDebug(7116) <<
"GETQUOTA command";
1741 kWarning(7116) <<
"UNIMPLEMENTED";
1746 kDebug(7116) <<
"SETQUOTA command";
1747 kWarning(7116) <<
"UNIMPLEMENTED";
1751 kWarning(7116) <<
"Unknown special quota command:" << command;
1752 error( ERR_UNSUPPORTED_ACTION, QString(QChar(command)) );
1758 IMAP4Protocol::rename (
const KUrl & src,
const KUrl & dest, KIO::JobFlags flags)
1760 kDebug(7116) <<
"IMAP4::rename - [" << ((flags & KIO::Overwrite) ?
"Overwrite" :
"NoOverwrite") <<
"]" << src <<
" ->" << dest;
1761 QString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
1762 QString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
1763 enum IMAP_TYPE sType =
1764 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo,
false);
1765 enum IMAP_TYPE dType =
1766 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo,
false);
1768 if (dType == ITYPE_UNKNOWN)
1774 case ITYPE_DIR_AND_BOX:
1776 if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
1778 kDebug(7116) <<
"IMAP4::rename - close" << getCurrentBox();
1781 bool ok = cmd->result() ==
"OK";
1782 completeQueue.removeAll(cmd);
1785 error(ERR_SLAVE_DEFINED, i18n(
"Unable to close mailbox."));
1788 setState(ISTATE_LOGIN);
1791 if (cmd->result () !=
"OK") {
1792 error (ERR_CANNOT_RENAME, cmd->result ());
1793 completeQueue.removeAll (cmd);
1796 completeQueue.removeAll (cmd);
1803 error (ERR_CANNOT_RENAME, src.prettyUrl());
1809 error (ERR_CANNOT_RENAME, src.prettyUrl());
1816 IMAP4Protocol::slave_status ()
1818 bool connected = (getState() != ISTATE_NO) && isConnected();
1819 kDebug(7116) <<
"IMAP4::slave_status" << connected;
1820 slaveStatus ( connected ? myHost : QString(), connected );
1824 IMAP4Protocol::dispatch (
int command,
const QByteArray & data)
1826 kDebug(7116) <<
"IMAP4::dispatch - command=" << command;
1827 KIO::TCPSlaveBase::dispatch (command, data);
1833 kDebug(7116) <<
"IMAP4::stat -" << _url.prettyUrl();
1834 QString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1836 enum IMAP_TYPE aType =
1837 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
1842 entry.insert( UDSEntry::UDS_NAME, aBox);
1844 if (!aSection.isEmpty())
1846 if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
1849 bool ok = cmd->result() ==
"OK";
1850 completeQueue.removeAll(cmd);
1853 error(ERR_SLAVE_DEFINED, i18n(
"Unable to close mailbox."));
1856 setState(ISTATE_LOGIN);
1860 if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1865 ok = cmd->result() ==
"OK";
1866 cmdInfo = cmd->resultInfo();
1867 completeQueue.removeAll(cmd);
1873 if (cmd->result () ==
"OK")
1875 for (QList< imapList >::Iterator it = listResponses.begin ();
1876 it != listResponses.end (); ++it)
1878 if (aBox == (*it).name ()) found =
true;
1881 completeQueue.removeAll (cmd);
1883 error(ERR_SLAVE_DEFINED, i18n(
"Unable to get information about folder %1. The server replied: %2", aBox, cmdInfo));
1885 error(KIO::ERR_DOES_NOT_EXIST, aBox);
1888 if ((aSection ==
"UIDNEXT" && getStatus().uidNextAvailable())
1889 || (aSection ==
"UNSEEN" && getStatus().unseenAvailable()))
1891 entry.insert( UDSEntry::UDS_SIZE, (aSection ==
"UIDNEXT") ? getStatus().uidNext()
1892 : getStatus().unseen());
1895 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
1896 aType == ITYPE_ATTACH)
1900 if (aBox == getCurrentBox ())
1901 validity = selectInfo.uidValidity ();
1909 completeQueue.removeAll (cmd);
1910 validity = getStatus ().uidValidity ();
1913 #warning This is temporary since Dec 2000 and makes most of the below code invalid
1917 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
1920 if (validity > 0 && validity != aValidity.toULong ())
1925 newUrl.setPath (
'/' + aBox +
";UIDVALIDITY=" +
1926 QString::number(validity));
1927 kDebug(7116) <<
"IMAP4::stat - redirecting to" << newUrl.prettyUrl();
1928 redirection (newUrl);
1931 else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1938 if (validity > 0 && validity != aValidity.toULong ())
1940 aType = ITYPE_UNKNOWN;
1941 kDebug(7116) <<
"IMAP4::stat - url has invalid validity [" << validity <<
"d]" << _url.prettyUrl();
1946 entry.insert( UDSEntry::UDS_MIME_TYPE,getMimeType (aType));
1952 entry.insert( UDSEntry::UDS_FILE_TYPE, S_IFDIR);
1956 case ITYPE_DIR_AND_BOX:
1957 entry.insert(UDSEntry::UDS_FILE_TYPE, S_IFDIR);
1962 entry.insert(UDSEntry::UDS_FILE_TYPE, S_IFREG);
1966 error (ERR_DOES_NOT_EXIST, _url.prettyUrl());
1971 kDebug(7116) <<
"IMAP4::stat - Finishing stat";
1975 void IMAP4Protocol::openConnection()
1977 if (makeLogin()) connected();
1980 void IMAP4Protocol::closeConnection()
1982 if (getState() == ISTATE_NO)
return;
1983 if (getState() == ISTATE_SELECT && metaData(
"expunge") ==
"auto")
1986 completeQueue.removeAll (cmd);
1988 if (getState() != ISTATE_CONNECT)
1991 completeQueue.removeAll (cmd);
1993 disconnectFromHost();
1994 setState(ISTATE_NO);
1995 completeQueue.clear();
2002 bool IMAP4Protocol::makeLogin ()
2004 if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
2007 kDebug(7116) <<
"IMAP4::makeLogin - checking login";
2008 bool alreadyConnected = getState() == ISTATE_CONNECT;
2009 kDebug(7116) <<
"IMAP4::makeLogin - alreadyConnected" << alreadyConnected;
2010 if (alreadyConnected || connectToHost (( mySSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL ), myHost,
2015 setState(ISTATE_CONNECT);
2017 myAuth = metaData(
"auth");
2018 myTLS = metaData(
"tls");
2019 kDebug(7116) <<
"myAuth:" << myAuth;
2024 if (!alreadyConnected)
while (!parseLoop ()) {}
2026 if (!unhandled.isEmpty()) greeting = unhandled.first().trimmed();
2028 cmd = doCommand (CommandPtr(
new imapCommand (
"CAPABILITY",
"")));
2030 kDebug(7116) <<
"IMAP4: setHost: capability";
2031 for (QStringList::const_iterator it = imapCapabilities.constBegin ();
2032 it != imapCapabilities.constEnd (); ++it)
2034 kDebug(7116) <<
"'" << (*it) <<
"'";
2036 completeQueue.removeAll (cmd);
2038 if (!hasCapability(
"IMAP4") && !hasCapability(
"IMAP4rev1"))
2040 error(ERR_COULD_NOT_LOGIN, i18n(
"The server %1 supports neither "
2041 "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2",
2047 if (metaData(
"nologin") ==
"on")
return true;
2049 if (myTLS ==
"on" && !hasCapability(QString(
"STARTTLS")))
2051 error(ERR_COULD_NOT_LOGIN, i18n(
"The server does not support TLS.\n"
2052 "Disable this security feature to connect unencrypted."));
2056 if ((myTLS ==
"on" ) &&
2057 hasCapability(QString(
"STARTTLS")))
2060 if (cmd->result () ==
"OK")
2062 completeQueue.removeAll(cmd);
2065 kDebug(7116) <<
"TLS mode has been enabled.";
2066 CommandPtr cmd2 = doCommand (CommandPtr(
new imapCommand (
"CAPABILITY",
"")));
2067 for (QStringList::const_iterator it = imapCapabilities.constBegin ();
2068 it != imapCapabilities.constEnd (); ++it)
2070 kDebug(7116) <<
"'" << (*it) <<
"'";
2072 completeQueue.removeAll (cmd2);
2074 kWarning(7116) <<
"TLS mode setup has failed. Aborting.";
2075 error (ERR_COULD_NOT_LOGIN, i18n(
"Starting TLS failed."));
2079 }
else completeQueue.removeAll(cmd);
2082 if (!myAuth.isEmpty () && myAuth !=
"*"
2083 && !hasCapability (QString (
"AUTH=") + myAuth))
2085 error (ERR_COULD_NOT_LOGIN, i18n(
"The authentication method %1 is not "
2086 "supported by the server.", myAuth));
2091 if ( greeting.contains( QRegExp(
"Cyrus IMAP4 v2.1" ) ) ) {
2092 removeCapability(
"ANNOTATEMORE" );
2096 QRegExp regExp(
"Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)", Qt::CaseInsensitive );
2097 if ( regExp.indexIn( greeting ) >= 0 ) {
2098 const int major = regExp.cap( 1 ).toInt();
2099 const int minor = regExp.cap( 2 ).toInt();
2100 const int patch = regExp.cap( 3 ).toInt();
2101 if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
2102 kDebug(7116) <<
"Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support";
2103 imapCapabilities.append(
"x-kmail-sharedseen" );
2107 kDebug(7116) <<
"IMAP4::makeLogin - attempting login";
2109 KIO::AuthInfo authInfo;
2110 authInfo.username = myUser;
2111 authInfo.password = myPass;
2112 authInfo.prompt = i18n (
"Username and password for your IMAP account:");
2114 kDebug(7116) <<
"IMAP4::makeLogin - open_PassDlg said user=" << myUser <<
" pass=xx";
2117 if (myAuth.isEmpty () || myAuth ==
"*")
2119 if (myUser.isEmpty () || myPass.isEmpty ()) {
2120 if(openPasswordDialog (authInfo)) {
2121 myUser = authInfo.username;
2122 myPass = authInfo.password;
2125 if (!clientLogin (myUser, myPass, resultInfo))
2126 error(ERR_SLAVE_DEFINED, i18n(
"Unable to login. Probably the "
2127 "password is wrong.\nThe server %1 replied:\n%2", myHost, resultInfo));
2131 if (!clientAuthenticate (
this, authInfo, myHost, myAuth, mySSL, resultInfo))
2132 error(ERR_SLAVE_DEFINED, i18n(
"Unable to authenticate via %1.\n" "The server %2 replied:\n%3", myAuth, myHost, resultInfo));
2134 myUser = authInfo.username;
2135 myPass = authInfo.password;
2138 if ( hasCapability(
"NAMESPACE") )
2142 if (cmd->result () ==
"OK")
2144 kDebug(7116) <<
"makeLogin - registered namespaces";
2146 completeQueue.removeAll (cmd);
2150 if (cmd->result () ==
"OK")
2152 QList< imapList >::Iterator it = listResponses.begin();
2153 if ( it != listResponses.end() )
2155 namespaceToDelimiter[QString()] = (*it).hierarchyDelimiter();
2156 kDebug(7116) <<
"makeLogin - delimiter for empty ns='" << (*it).hierarchyDelimiter() <<
"'";
2157 if ( !hasCapability(
"NAMESPACE") )
2160 QString nsentry = QString::number( 0 ) +
"==" + (*it).hierarchyDelimiter();
2161 imapNamespaces.append( nsentry );
2165 completeQueue.removeAll (cmd);
2167 kDebug(7116) <<
"makeLogin - NO login";
2170 return getState() == ISTATE_LOGIN;
2177 QByteArray writer = aStr.toUtf8();
2178 int len = writer.length();
2181 if (len == 0 || (writer[len - 1] !=
'\n')) {
2187 write(writer.data(), len);
2191 IMAP4Protocol::getMimeType (
enum IMAP_TYPE aType)
2196 return "inode/directory";
2200 return "message/digest";
2203 case ITYPE_DIR_AND_BOX:
2204 return "message/directory";
2208 return "message/rfc822";
2213 return "application/octet-stream";
2218 return "unknown/unknown";
2225 IMAP4Protocol::doListEntry (
const KUrl & _url,
int stretch, imapCache * cache,
2226 bool withFlags,
bool withSubject)
2229 aURL.setQuery (QString());
2230 const QString encodedUrl = aURL.url(KUrl::LeaveTrailingSlash);
2231 doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
2237 IMAP4Protocol::doListEntry (
const QString & encodedUrl,
int stretch, imapCache * cache,
2238 bool withFlags,
bool withSubject)
2246 const QString uid = QString::number(cache->getUid());
2250 tmp =
"0000000000000000" + uid;
2251 tmp = tmp.right (stretch);
2259 entry.insert (UDSEntry::UDS_NAME,tmp);
2262 if (tmp[tmp.length () - 1] !=
'/')
2264 tmp +=
";UID=" + uid;
2265 entry.insert( UDSEntry::UDS_URL, tmp);
2267 entry.insert(UDSEntry::UDS_FILE_TYPE,S_IFREG);
2269 entry.insert(UDSEntry::UDS_SIZE, cache->getSize());
2271 entry.insert( UDSEntry::UDS_MIME_TYPE, QString::fromLatin1(
"message/rfc822"));
2273 entry.insert(UDSEntry::UDS_USER,myUser);
2275 entry.insert( KIO::UDSEntry::UDS_ACCESS, (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR);
2277 listEntry (entry,
false);
2282 IMAP4Protocol::doListEntry (
const KUrl & _url,
const QString & myBox,
2283 const imapList & item,
bool appendPath)
2286 aURL.setQuery (QString());
2288 int hdLen = item.hierarchyDelimiter().length();
2292 QString mailboxName = item.name ();
2295 if ( mailboxName.startsWith(myBox) && mailboxName.length() > myBox.length())
2298 mailboxName.right (mailboxName.length () - myBox.length ());
2300 if (mailboxName[0] ==
'/')
2301 mailboxName = mailboxName.right (mailboxName.length () - 1);
2302 if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
2303 mailboxName = mailboxName.right(mailboxName.length () - hdLen);
2304 if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
2305 mailboxName.truncate(mailboxName.length () - hdLen);
2308 if (!item.hierarchyDelimiter().isEmpty() &&
2309 mailboxName.contains(item.hierarchyDelimiter()) )
2310 tmp = mailboxName.section(item.hierarchyDelimiter(), -1);
2318 if (!tmp.isEmpty ())
2320 entry.insert(UDSEntry::UDS_NAME,tmp);
2322 if (!item.noSelect ())
2324 if (!item.noInferiors ())
2326 tmp =
"message/directory";
2328 tmp =
"message/digest";
2330 entry.insert(UDSEntry::UDS_MIME_TYPE,tmp);
2335 entry.insert(UDSEntry::UDS_FILE_TYPE,S_IFDIR);
2337 else if (!item.noInferiors ())
2339 entry.insert(UDSEntry::UDS_MIME_TYPE, QString::fromLatin1(
"inode/directory"));
2343 entry.insert(UDSEntry::UDS_FILE_TYPE,S_IFDIR);
2347 entry.insert(UDSEntry::UDS_MIME_TYPE,QString::fromLatin1(
"unknown/unknown"));
2350 QString path = aURL.path();
2353 if (path[path.length() - 1] ==
'/' && !path.isEmpty() && path !=
"/")
2354 path.truncate(path.length() - 1);
2355 if (!path.isEmpty() && path !=
"/"
2356 && path.right(hdLen) != item.hierarchyDelimiter()) {
2357 path += item.hierarchyDelimiter();
2359 path += mailboxName;
2360 if (path.toUpper() ==
"/INBOX/") {
2362 path = path.toUpper();
2366 tmp = aURL.url(KUrl::LeaveTrailingSlash);
2367 entry.insert(UDSEntry::UDS_URL, tmp);
2369 entry.insert( UDSEntry::UDS_USER, myUser);
2371 entry.insert( UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR | S_IWUSR);
2373 entry.insert( UDSEntry::UDS_EXTRA,item.attributesAsString());
2375 listEntry (entry,
false);
2382 QString & _section, QString & _type, QString & _uid,
2383 QString & _validity, QString & _hierarchyDelimiter,
2384 QString & _info,
bool cache)
2386 enum IMAP_TYPE retVal;
2387 retVal = ITYPE_UNKNOWN;
2393 QString myNamespace = namespaceForBox( _box );
2394 kDebug(7116) <<
"IMAP4::parseURL - namespace=" << myNamespace;
2395 if ( namespaceToDelimiter.contains(myNamespace) )
2397 _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
2398 kDebug(7116) <<
"IMAP4::parseURL - delimiter=" << _hierarchyDelimiter;
2401 if (!_box.isEmpty ())
2403 kDebug(7116) <<
"IMAP4::parseURL - box=" << _box;
2407 if (getCurrentBox () != _box ||
2408 _type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK")
2413 retVal = ITYPE_DIR_AND_BOX;
2420 if (cmd->result () ==
"OK")
2422 for (QList< imapList >::Iterator it = listResponses.begin ();
2423 it != listResponses.end (); ++it)
2426 if (_box == (*it).name ())
2428 if ( !(*it).hierarchyDelimiter().isEmpty() )
2429 _hierarchyDelimiter = (*it).hierarchyDelimiter();
2430 if ((*it).noSelect ())
2434 else if ((*it).noInferiors ())
2440 retVal = ITYPE_DIR_AND_BOX;
2445 if ( retVal == ITYPE_UNKNOWN &&
2446 namespaceToDelimiter.contains(_box) ) {
2450 kDebug(7116) <<
"IMAP4::parseURL - got error for" << _box;
2452 completeQueue.removeAll (cmd);
2461 kDebug(7116) <<
"IMAP4::parseURL: no login!";
2467 kDebug(7116) <<
"IMAP4: parseURL: box [root]";
2472 if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
2474 if (!_uid.isEmpty ())
2476 if ( !_uid.contains(
':') && !_uid.contains(
',') && !_uid.contains(
'*') )
2480 if (retVal == ITYPE_MSG)
2482 if ( ( _section.contains(
"BODY.PEEK[", Qt::CaseInsensitive) ||
2483 _section.contains(
"BODY[", Qt::CaseInsensitive) ) &&
2484 !_section.contains(
".MIME") &&
2485 !_section.contains(
".HEADER") )
2486 retVal = ITYPE_ATTACH;
2488 if ( _hierarchyDelimiter.isEmpty() &&
2489 (_type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK") )
2493 if (!_box.isEmpty())
2495 int start = _url.path().lastIndexOf(_box);
2497 _hierarchyDelimiter = _url.path().mid(start-1, start);
2498 kDebug(7116) <<
"IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
2499 <<
"from URL" << _url.path();
2501 if (_hierarchyDelimiter.isEmpty())
2502 _hierarchyDelimiter =
'/';
2504 kDebug(7116) <<
"IMAP4::parseURL - return" << retVal;
2513 len = _str.length();
2518 if ( !outputBuffer.isOpen() ) {
2519 outputBuffer.open(QIODevice::WriteOnly);
2521 outputBuffer.seek( outputBufferIndex );
2522 outputBuffer.write(_str.data(), len);
2523 outputBufferIndex += len;
2528 bool relay = relayEnabled;
2530 relayEnabled =
true;
2531 temp = QByteArray::fromRawData (_str.data (), len);
2535 relayEnabled = relay;
2542 if (outputBufferIndex == 0)
2544 outputBuffer.close();
2545 outputCache.resize(outputBufferIndex);
2550 if ( contentEncoding.startsWith(QLatin1String(
"quoted-printable"), Qt::CaseInsensitive) )
2551 decoded = KCodecs::quotedPrintableDecode(outputCache);
2552 else if ( contentEncoding.startsWith(QLatin1String(
"base64"), Qt::CaseInsensitive) )
2553 decoded = QByteArray::fromBase64( outputCache );
2555 decoded = outputCache;
2557 QString mimetype = KMimeType::findByContent( decoded )->name();
2558 kDebug(7116) <<
"IMAP4::flushOutput - mimeType" << mimetype;
2560 decodeContent =
false;
2563 data( outputCache );
2565 mProcessedSize += outputBufferIndex;
2566 processedSize( mProcessedSize );
2567 outputBufferIndex = 0;
2568 outputCache[0] =
'\0';
2569 outputBuffer.setBuffer(&outputCache);
2572 ssize_t IMAP4Protocol::myRead(
void *data, ssize_t len)
2576 ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
2577 memcpy(data, readBuffer, copyLen);
2578 readBufferLen -= copyLen;
2579 if (readBufferLen) memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
2582 if (!isConnected())
return 0;
2583 waitForResponse( responseTimeout() );
2584 return read((
char*)data, len);
2588 IMAP4Protocol::assureBox (
const QString & aBox,
bool readonly)
2590 if (aBox.isEmpty())
return false;
2594 if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
2597 kDebug(7116) <<
"IMAP4Protocol::assureBox - opening box";
2598 selectInfo = imapInfo();
2600 bool ok = cmd->result() ==
"OK";
2601 QString cmdInfo = cmd->resultInfo();
2602 completeQueue.removeAll (cmd);
2608 if (cmd->result () ==
"OK")
2610 for (QList< imapList >::Iterator it = listResponses.begin ();
2611 it != listResponses.end (); ++it)
2613 if (aBox == (*it).name ()) found =
true;
2616 completeQueue.removeAll (cmd);
2618 if ( cmdInfo.contains(
"permission", Qt::CaseInsensitive) ) {
2620 error(ERR_ACCESS_DENIED, cmdInfo);
2622 error(ERR_SLAVE_DEFINED, i18n(
"Unable to open folder %1. The server replied: %2", aBox, cmdInfo));
2625 error(KIO::ERR_DOES_NOT_EXIST, aBox);
2635 kDebug(7116) <<
"IMAP4Protocol::assureBox - reusing box";
2636 if ( mTimeOfLastNoop.secsTo( QDateTime::currentDateTime() ) > 10 ) {
2638 completeQueue.removeAll (cmd);
2639 mTimeOfLastNoop = QDateTime::currentDateTime();
2640 kDebug(7116) <<
"IMAP4Protocol::assureBox - noop timer fired";
2645 if (!getSelected().readWrite() && !readonly)
2647 error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);