65 #include "rfcdecoder.h"
72 #include <sys/types.h>
77 #include <sasl/sasl.h>
82 #include <tqdatetime.h>
84 #include <kprotocolmanager.h>
85 #include <kmessagebox.h>
87 #include <kio/connection.h>
88 #include <kio/slaveinterface.h>
89 #include <kio/passdlg.h>
91 #include <kmimetype.h>
94 #include "kdepimmacros.h"
96 #define IMAP_PROTOCOL "imap"
97 #define IMAP_SSL_PROTOCOL "imaps"
103 void sigalrm_handler (
int);
104 KDE_EXPORT
int kdemain (
int argc,
char **argv);
108 kdemain (
int argc,
char **argv)
110 kdDebug(7116) <<
"IMAP4::kdemain" << endl;
112 KInstance instance (
"kio_imap4");
115 fprintf(stderr,
"Usage: kio_imap4 protocol domain-socket1 domain-socket2\n");
120 if ( sasl_client_init( NULL ) != SASL_OK ) {
121 fprintf(stderr,
"SASL library initialization failed!\n");
129 if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
131 else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
135 slave->dispatchLoop ();
146 sigchld_handler (
int signo)
150 while (
true && signo == SIGCHLD)
152 pid = waitpid (-1, &status, WNOHANG);
158 signal (SIGCHLD, sigchld_handler);
164 IMAP4Protocol::IMAP4Protocol (
const TQCString & pool,
const TQCString & app,
bool isSSL):TCPSlaveBase ((isSSL ? 993 : 143),
165 (isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool,
166 app, isSSL), imapParser (),
mimeIO (), outputBuffer(outputCache)
168 outputBufferIndex = 0;
170 readBuffer[0] = 0x00;
171 relayEnabled =
false;
174 decodeContent =
false;
175 mTimeOfLastNoop = TQDateTime();
178 IMAP4Protocol::~IMAP4Protocol ()
181 kdDebug(7116) <<
"IMAP4: Finishing" << endl;
187 if (!makeLogin())
return;
188 kdDebug(7116) <<
"IMAP4::get - " << _url.prettyURL() << endl;
189 TQString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
190 enum IMAP_TYPE aEnum =
191 parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
192 if (aEnum != ITYPE_ATTACH)
193 mimeType (getMimeType(aEnum));
194 if (aInfo ==
"DECODE")
195 decodeContent =
true;
197 if (aSequence ==
"0:0" && getState() == ISTATE_SELECT)
200 completeQueue.removeRef(cmd);
203 if (aSequence.isEmpty ())
210 if (!assureBox (aBox,
true))
return;
213 if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
214 && selectInfo.uidValidity () != aValidity.toULong ())
217 error (ERR_COULD_NOT_READ, _url.prettyURL());
230 TQString aUpper = aSection.upper();
231 if (aUpper.find (
"STRUCTURE") != -1)
233 aSection =
"BODYSTRUCTURE";
235 else if (aUpper.find (
"ENVELOPE") != -1)
237 aSection =
"UID RFC822.SIZE FLAGS ENVELOPE";
238 if (hasCapability(
"IMAP4rev1")) {
239 aSection +=
" BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
242 aSection +=
" RFC822.HEADER.LINES (REFERENCES)";
245 else if (aUpper ==
"HEADER")
247 aSection =
"UID RFC822.HEADER RFC822.SIZE FLAGS";
249 else if (aUpper.find (
"BODY.PEEK[") != -1)
251 if (aUpper.find (
"BODY.PEEK[]") != -1)
253 if (!hasCapability(
"IMAP4rev1"))
254 aSection.replace(
"BODY.PEEK[]",
"RFC822.PEEK");
256 aSection.prepend(
"UID RFC822.SIZE FLAGS ");
258 else if (aSection.isEmpty())
260 aSection =
"UID BODY[] RFC822.SIZE FLAGS";
262 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
267 (
"Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
268 if (selectInfo.recentAvailable ())
269 outputLineStr (
"X-Recent: " +
270 TQString::number(selectInfo.recent ()) +
"\r\n");
271 if (selectInfo.countAvailable ())
272 outputLineStr (
"X-Count: " + TQString::number(selectInfo.count ()) +
274 if (selectInfo.unseenAvailable ())
275 outputLineStr (
"X-Unseen: " +
276 TQString::number(selectInfo.unseen ()) +
"\r\n");
277 if (selectInfo.uidValidityAvailable ())
278 outputLineStr (
"X-uidValidity: " +
279 TQString::number(selectInfo.uidValidity ()) +
281 if (selectInfo.uidNextAvailable ())
282 outputLineStr (
"X-UidNext: " +
283 TQString::number(selectInfo.uidNext ()) +
"\r\n");
284 if (selectInfo.flagsAvailable ())
285 outputLineStr (
"X-Flags: " + TQString::number(selectInfo.flags ()) +
287 if (selectInfo.permanentFlagsAvailable ())
288 outputLineStr (
"X-PermanentFlags: " +
289 TQString::number(selectInfo.permanentFlags ()) +
"\r\n");
290 if (selectInfo.readWriteAvailable ()) {
291 if (selectInfo.readWrite()) {
302 if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
305 if (aSequence !=
"0:0")
307 TQString contentEncoding;
308 if (aEnum == ITYPE_ATTACH && decodeContent)
311 TQString mySection = aSection;
312 mySection.replace(
"]",
".MIME]");
316 while (!parseLoop ()) ;
319 completeQueue.removeRef (cmd);
321 if (getLastHandled() && getLastHandled()->getHeader())
322 contentEncoding = getLastHandled()->getHeader()->getEncoding();
332 aUpper = aSection.upper();
335 while (!(res = parseLoop())) ;
336 if (res == -1)
break;
339 imapCache *cache = getLastHandled ();
341 lastone = cache->getHeader ();
345 if ((aUpper.find (
"BODYSTRUCTURE") != -1)
346 || (aUpper.find (
"FLAGS") != -1)
347 || (aUpper.find (
"UID") != -1)
348 || (aUpper.find (
"ENVELOPE") != -1)
349 || (aUpper.find (
"BODY.PEEK[0]") != -1
350 && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
352 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
357 if (cache && cache->getUid () != 0)
358 outputLineStr (
"X-UID: " +
359 TQString::number(cache->getUid ()) +
"\r\n");
360 if (cache && cache->getSize () != 0)
361 outputLineStr (
"X-Length: " +
362 TQString::number(cache->getSize ()) +
"\r\n");
363 if (cache && !cache->getDate ().isEmpty())
364 outputLineStr (
"X-Date: " + cache->getDate () +
"\r\n");
365 if (cache && cache->getFlags () != 0)
366 outputLineStr (
"X-Flags: " +
367 TQString::number(cache->getFlags ()) +
"\r\n");
368 }
else cacheOutput =
true;
369 if ( lastone && !decodeContent )
370 lastone->outputPart (*
this);
377 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
383 completeQueue.removeRef (cmd);
388 data (TQByteArray ());
391 relayEnabled =
false;
393 kdDebug(7116) <<
"IMAP4::get - finished" << endl;
399 kdDebug(7116) <<
" IMAP4::listDir - " << _url.prettyURL() << endl;
401 if (_url.path().isEmpty())
410 TQString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
412 enum IMAP_TYPE myType =
413 parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
414 myDelimiter, myInfo,
true);
416 if (!makeLogin())
return;
418 if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
420 TQString listStr = myBox;
423 if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
424 mySection !=
"FOLDERONLY")
425 listStr += myDelimiter;
427 if (mySection.isEmpty())
430 }
else if (mySection ==
"COMPLETE") {
433 kdDebug(7116) <<
"IMAP4Protocol::listDir - listStr=" << listStr << endl;
436 (myLType ==
"LSUB" || myLType ==
"LSUBNOCHECK")));
437 if (cmd->
result () ==
"OK")
439 TQString mailboxName;
443 if (aURL.path().find(
';') != -1)
444 aURL.setPath(aURL.path().left(aURL.path().find(
';')));
446 kdDebug(7116) <<
"IMAP4Protocol::listDir - got " << listResponses.count () << endl;
448 if (myLType ==
"LSUB")
451 TQValueList<imapList> listResponsesSave = listResponses;
453 for (TQValueListIterator < imapList > it = listResponsesSave.begin ();
454 it != listResponsesSave.end (); ++it)
457 for (TQValueListIterator < imapList > it2 = listResponses.begin ();
458 it2 != listResponses.end (); ++it2)
460 if ((*it2).name() == (*it).name())
469 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
471 kdDebug(7116) <<
"IMAP4Protocol::listDir - suppress " << (*it).name() << endl;
473 listResponses = listResponsesSave;
477 for (TQValueListIterator < imapList > it = listResponses.begin ();
478 it != listResponses.end (); ++it)
480 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
484 listEntry (entry,
true);
488 error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyURL());
489 completeQueue.removeRef (cmd);
492 completeQueue.removeRef (cmd);
494 if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
495 && myLType !=
"LIST" && myLType !=
"LSUB" && myLType !=
"LSUBNOCHECK")
498 aURL.setQuery (TQString());
499 const TQString encodedUrl = aURL.url(0, 106);
501 if (!_url.query ().isEmpty ())
503 TQString query = KURL::decode_string (_url.query ());
504 query = query.right (query.length () - 1);
505 if (!query.isEmpty())
509 if (!assureBox (myBox,
true))
return;
511 if (!selectInfo.countAvailable() || selectInfo.count())
514 if (cmd->
result() !=
"OK")
516 error(ERR_UNSUPPORTED_ACTION, _url.prettyURL());
517 completeQueue.removeRef (cmd);
520 completeQueue.removeRef (cmd);
522 TQStringList list = getResults ();
525 if (selectInfo.uidNextAvailable ())
526 stretch = TQString::number(selectInfo.uidNext ()).length ();
530 for (TQStringList::ConstIterator it = list.begin(); it != list.end();
533 fake.setUid((*it).toULong());
534 doListEntry (encodedUrl, stretch, &fake);
537 listEntry (entry,
true);
543 if (!assureBox (myBox,
true))
return;
545 kdDebug(7116) <<
"IMAP4: select returned:" << endl;
546 if (selectInfo.recentAvailable ())
547 kdDebug(7116) <<
"Recent: " << selectInfo.recent () <<
"d" << endl;
548 if (selectInfo.countAvailable ())
549 kdDebug(7116) <<
"Count: " << selectInfo.count () <<
"d" << endl;
550 if (selectInfo.unseenAvailable ())
551 kdDebug(7116) <<
"Unseen: " << selectInfo.unseen () <<
"d" << endl;
552 if (selectInfo.uidValidityAvailable ())
553 kdDebug(7116) <<
"uidValidity: " << selectInfo.uidValidity () <<
"d" << endl;
554 if (selectInfo.flagsAvailable ())
555 kdDebug(7116) <<
"Flags: " << selectInfo.flags () <<
"d" << endl;
556 if (selectInfo.permanentFlagsAvailable ())
557 kdDebug(7116) <<
"PermanentFlags: " << selectInfo.permanentFlags () <<
"d" << endl;
558 if (selectInfo.readWriteAvailable ())
559 kdDebug(7116) <<
"Access: " << (selectInfo.readWrite ()?
"Read/Write" :
"Read only") << endl;
562 if (selectInfo.uidValidityAvailable ()
563 && selectInfo.uidValidity () != myValidity.toULong ())
568 newUrl.setPath (
"/" + myBox +
";UIDVALIDITY=" +
569 TQString::number(selectInfo.uidValidity ()));
570 kdDebug(7116) <<
"IMAP4::listDir - redirecting to " << newUrl.prettyURL() << endl;
571 redirection (newUrl);
577 if (selectInfo.count () > 0)
581 if (selectInfo.uidNextAvailable ())
582 stretch = TQString::number(selectInfo.uidNext ()).length ();
586 if (mySequence.isEmpty()) mySequence =
"1:*";
588 bool withSubject = mySection.isEmpty();
589 if (mySection.isEmpty()) mySection =
"UID RFC822.SIZE ENVELOPE";
591 bool withFlags = mySection.upper().find(
"FLAGS") != -1;
594 clientFetch (mySequence, mySection));
598 while (!parseLoop ()) ;
600 cache = getLastHandled ();
603 doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
607 listEntry (entry,
true);
611 if ( !selectInfo.alert().isNull() ) {
612 if ( !myBox.isEmpty() ) {
613 warning( i18n(
"Message from %1 while processing '%2': %3" ).arg( myHost, myBox, selectInfo.alert() ) );
615 warning( i18n(
"Message from %1: %2" ).arg( myHost, TQString(selectInfo.alert()) ) );
617 selectInfo.setAlert( 0 );
620 kdDebug(7116) <<
"IMAP4Protocol::listDir - Finishing listDir" << endl;
625 IMAP4Protocol::setHost (
const TQString & _host,
int _port,
626 const TQString & _user,
const TQString & _pass)
628 if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
631 if (!myHost.isEmpty ())
646 mProcessedSize += buffer.size();
647 processedSize( mProcessedSize );
648 }
else if (cacheOutput)
651 if ( !outputBuffer.isOpen() ) {
652 outputBuffer.open(IO_WriteOnly);
654 outputBuffer.at(outputBufferIndex);
655 outputBuffer.writeBlock(buffer, buffer.size());
656 outputBufferIndex += buffer.size();
671 while (buffer.size() < len)
673 ssize_t readLen = myRead(buf, TQMIN(len - buffer.size(),
sizeof(buf) - 1));
676 kdDebug(7116) <<
"parseRead: readLen == 0 - connection broken" << endl;
677 error (ERR_CONNECTION_BROKEN, myHost);
678 setState(ISTATE_CONNECT);
682 if (relay > buffer.size())
684 TQByteArray relayData;
685 ssize_t relbuf = relay - buffer.size();
686 int currentRelay = TQMIN(relbuf, readLen);
687 relayData.setRawData(buf, currentRelay);
689 relayData.resetRawData(buf, currentRelay);
692 TQBuffer stream (buffer);
693 stream.open (IO_WriteOnly);
694 stream.at (buffer.size ());
695 stream.writeBlock (buf, readLen);
699 return (buffer.size() == len);
705 if (myHost.isEmpty())
return FALSE;
709 if (readBufferLen > 0)
711 while (copyLen < readBufferLen && readBuffer[copyLen] !=
'\n') copyLen++;
712 if (copyLen < readBufferLen) copyLen++;
715 TQByteArray relayData;
717 if (copyLen < (ssize_t) relay)
719 relayData.setRawData (readBuffer, relay);
721 relayData.resetRawData (readBuffer, relay);
726 TQBuffer stream (buffer);
728 stream.open (IO_WriteOnly);
729 stream.at (buffer.size ());
730 stream.writeBlock (readBuffer, copyLen);
735 readBufferLen -= copyLen;
737 memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
738 if (buffer[buffer.size() - 1] ==
'\n')
return TRUE;
740 if (!isConnectionValid())
742 kdDebug(7116) <<
"parseReadLine - connection broken" << endl;
743 error (ERR_CONNECTION_BROKEN, myHost);
744 setState(ISTATE_CONNECT);
748 if (!waitForResponse( responseTimeout() ))
750 error(ERR_SERVER_TIMEOUT, myHost);
751 setState(ISTATE_CONNECT);
755 readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
756 if (readBufferLen == 0)
758 kdDebug(7116) <<
"parseReadLine: readBufferLen == 0 - connection broken" << endl;
759 error (ERR_CONNECTION_BROKEN, myHost);
760 setState(ISTATE_CONNECT);
768 IMAP4Protocol::setSubURL (
const KURL & _url)
770 kdDebug(7116) <<
"IMAP4::setSubURL - " << _url.prettyURL() << endl;
771 KIO::TCPSlaveBase::setSubURL (_url);
775 IMAP4Protocol::put (
const KURL & _url,
int,
bool,
bool)
777 kdDebug(7116) <<
"IMAP4::put - " << _url.prettyURL() << endl;
779 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
780 enum IMAP_TYPE aType =
781 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
784 if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
786 if (aBox[aBox.length () - 1] ==
'/')
787 aBox = aBox.right (aBox.length () - 1);
790 if (cmd->
result () !=
"OK") {
791 error (ERR_COULD_NOT_WRITE, _url.prettyURL());
792 completeQueue.removeRef (cmd);
795 completeQueue.removeRef (cmd);
799 TQPtrList < TQByteArray > bufferList;
806 TQByteArray *buffer =
new TQByteArray ();
808 result = readData (*buffer);
811 bufferList.append (buffer);
821 error (ERR_ABORTED, _url.prettyURL());
827 while (!parseLoop ()) ;
830 if (!cmd->
isComplete () && !getContinuation ().isEmpty ())
837 while (!bufferList.isEmpty () && sendOk)
839 buffer = bufferList.take (0);
842 (write (buffer->data (), buffer->size ()) ==
843 (ssize_t) buffer->size ());
844 wrote += buffer->size ();
845 processedSize(wrote);
849 error (ERR_CONNECTION_BROKEN, myHost);
850 completeQueue.removeRef (cmd);
851 setState(ISTATE_CONNECT);
858 while (!cmd->
isComplete () && getState() != ISTATE_NO)
860 if ( getState() == ISTATE_NO ) {
863 error( ERR_CONNECTION_BROKEN, myHost );
864 completeQueue.removeRef (cmd);
868 else if (cmd->
result () !=
"OK") {
869 error( ERR_SLAVE_DEFINED, cmd->
resultInfo() );
870 completeQueue.removeRef (cmd);
875 if (hasCapability(
"UIDPLUS"))
878 if (uid.find(
"APPENDUID") != -1)
880 uid = uid.section(
" ", 2, 2);
881 uid.truncate(uid.length()-1);
882 infoMessage(
"UID "+uid);
886 else if (aBox == getCurrentBox ())
890 clientSelect (aBox, !selectInfo.readWrite ()));
891 completeQueue.removeRef (cmd);
900 completeQueue.removeRef (cmd);
904 completeQueue.removeRef (cmd);
913 kdDebug(7116) <<
"IMAP4::mkdir - " << _url.prettyURL() << endl;
914 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
915 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
916 kdDebug(7116) <<
"IMAP4::mkdir - create " << aBox << endl;
919 if (cmd->
result () !=
"OK")
921 kdDebug(7116) <<
"IMAP4::mkdir - " << cmd->
resultInfo() << endl;
922 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
923 completeQueue.removeRef (cmd);
926 completeQueue.removeRef (cmd);
929 enum IMAP_TYPE type =
930 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
931 if (type == ITYPE_BOX)
933 bool ask = ( aInfo.find(
"ASKUSER" ) != -1 );
935 messageBox(QuestionYesNo,
936 i18n(
"The following folder will be created on the server: %1 "
937 "What do you want to store in this folder?").arg( aBox ),
938 i18n(
"Create Folder"),
939 i18n(
"&Messages"), i18n(
"&Subfolders")) == KMessageBox::No )
942 completeQueue.removeRef (cmd);
944 if (cmd->
result () !=
"OK")
946 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
947 completeQueue.removeRef (cmd);
950 completeQueue.removeRef (cmd);
955 completeQueue.removeRef(cmd);
961 IMAP4Protocol::copy (
const KURL & src,
const KURL & dest,
int,
bool overwrite)
963 kdDebug(7116) <<
"IMAP4::copy - [" << (overwrite ?
"Overwrite" :
"NoOverwrite") <<
"] " << src.prettyURL() <<
" -> " << dest.prettyURL() << endl;
964 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
965 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
966 enum IMAP_TYPE sType =
967 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
968 enum IMAP_TYPE dType =
969 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
972 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
975 int sub = dBox.find (sBox);
982 TQString subDir = dBox.right (dBox.length () - dBox.findRev (
'/'));
983 TQString topDir = dBox.left (sub);
984 testDir.setPath (
"/" + topDir);
986 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
989 kdDebug(7116) <<
"IMAP4::copy - checking this destination " << topDir << endl;
991 if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
993 kdDebug(7116) <<
"IMAP4::copy - assuming this destination " << topDir << endl;
1000 topDir =
"/" + topDir + subDir;
1001 testDir.setPath (topDir);
1002 kdDebug(7116) <<
"IMAP4::copy - checking this destination " << topDir << endl;
1004 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
1006 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
1012 if (cmd->
result () ==
"OK")
1014 kdDebug(7116) <<
"IMAP4::copy - assuming this destination " << topDir << endl;
1020 completeQueue.removeRef (cmd);
1022 if (cmd->
result () ==
"OK")
1025 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
1027 completeQueue.removeRef (cmd);
1033 if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
1036 if (!assureBox(sBox,
true))
return;
1037 kdDebug(7116) <<
"IMAP4::copy - " << sBox <<
" -> " << dBox << endl;
1042 if (cmd->
result () !=
"OK")
1044 kdError(5006) <<
"IMAP4::copy - " << cmd->
resultInfo() << endl;
1045 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
1046 completeQueue.removeRef (cmd);
1049 if (hasCapability(
"UIDPLUS"))
1052 if (uid.find(
"COPYUID") != -1)
1054 uid = uid.section(
" ", 2, 3);
1055 uid.truncate(uid.length()-1);
1056 infoMessage(
"UID "+uid);
1060 completeQueue.removeRef (cmd);
1064 error (ERR_ACCESS_DENIED, src.prettyURL());
1073 kdDebug(7116) <<
"IMAP4::del - [" << (isFile ?
"File" :
"NoFile") <<
"] " << _url.prettyURL() << endl;
1074 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1075 enum IMAP_TYPE aType =
1076 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1081 case ITYPE_DIR_AND_BOX:
1082 if (!aSequence.isEmpty ())
1084 if (aSequence ==
"*")
1086 if (!assureBox (aBox,
false))
return;
1088 if (cmd->
result () !=
"OK") {
1089 error (ERR_CANNOT_DELETE, _url.prettyURL());
1090 completeQueue.removeRef (cmd);
1093 completeQueue.removeRef (cmd);
1098 if (!assureBox (aBox,
false))
return;
1101 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1102 if (cmd->
result () !=
"OK") {
1103 error (ERR_CANNOT_DELETE, _url.prettyURL());
1104 completeQueue.removeRef (cmd);
1107 completeQueue.removeRef (cmd);
1112 if (getCurrentBox() == aBox)
1115 completeQueue.removeRef(cmd);
1116 setState(ISTATE_LOGIN);
1120 completeQueue.removeRef(cmd);
1123 if (cmd->
result () !=
"OK")
1125 completeQueue.removeRef(cmd);
1126 if (!assureBox(aBox,
false))
return;
1127 bool stillOk =
true;
1132 if (cmd->
result () !=
"OK") stillOk =
false;
1133 completeQueue.removeRef(cmd);
1138 if (cmd->
result () !=
"OK") stillOk =
false;
1139 completeQueue.removeRef(cmd);
1140 setState(ISTATE_LOGIN);
1145 if (cmd->
result () !=
"OK") stillOk =
false;
1146 completeQueue.removeRef(cmd);
1150 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
1154 completeQueue.removeRef (cmd);
1162 if (cmd->
result () !=
"OK") {
1163 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
1164 completeQueue.removeRef (cmd);
1167 completeQueue.removeRef (cmd);
1174 if (!assureBox (aBox,
false))
return;
1177 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1178 if (cmd->
result () !=
"OK") {
1179 error (ERR_CANNOT_DELETE, _url.prettyURL());
1180 completeQueue.removeRef (cmd);
1183 completeQueue.removeRef (cmd);
1189 error (ERR_CANNOT_DELETE, _url.prettyURL());
1214 kdDebug(7116) <<
"IMAP4Protocol::special" << endl;
1215 if (!makeLogin())
return;
1217 TQDataStream stream(aData, IO_ReadOnly);
1228 stream >> src >> dest;
1229 copy(src, dest, 0, FALSE);
1235 infoMessage(imapCapabilities.join(
" "));
1243 if (cmd->
result () !=
"OK")
1245 kdDebug(7116) <<
"NOOP did not succeed - connection broken" << endl;
1246 completeQueue.removeRef (cmd);
1247 error (ERR_CONNECTION_BROKEN, myHost);
1250 completeQueue.removeRef (cmd);
1258 infoMessage( imapNamespaces.join(
",") );
1267 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1268 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1270 if (cmd->
result () !=
"OK")
1272 completeQueue.removeRef (cmd);
1273 error(ERR_SLAVE_DEFINED, i18n(
"Unsubscribe of folder %1 "
1274 "failed. The server returned: %2")
1275 .arg(_url.prettyURL())
1279 completeQueue.removeRef (cmd);
1288 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1289 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1291 if (cmd->
result () !=
"OK")
1293 completeQueue.removeRef (cmd);
1294 error(ERR_SLAVE_DEFINED, i18n(
"Subscribe of folder %1 "
1295 "failed. The server returned: %2")
1296 .arg(_url.prettyURL())
1300 completeQueue.removeRef (cmd);
1309 if ( hasCapability(
"ACL" ) ) {
1312 error( ERR_UNSUPPORTED_ACTION,
"ACL" );
1321 if ( hasCapability(
"ANNOTATEMORE" ) ) {
1324 error( ERR_UNSUPPORTED_ACTION,
"ANNOTATEMORE" );
1333 if ( hasCapability(
"QUOTA" ) ) {
1334 specialQuotaCommand( cmd, stream );
1336 error( ERR_UNSUPPORTED_ACTION,
"QUOTA" );
1345 stream >> _url >> newFlags;
1347 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1348 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1349 if (!assureBox(aBox,
false))
return;
1352 TQCString knownFlags =
"\\SEEN \\ANSWERED \\FLAGGED \\DRAFT";
1353 const imapInfo info = getSelected();
1354 if ( info.permanentFlagsAvailable() && (info.permanentFlags() & imapInfo::User) ) {
1355 knownFlags +=
" KMAILFORWARDED KMAILTODO KMAILWATCHED KMAILIGNORED $FORWARDED $TODO $WATCHED $IGNORED";
1359 clientStore (aSequence,
"-FLAGS.SILENT", knownFlags));
1360 if (cmd->
result () !=
"OK")
1362 completeQueue.removeRef (cmd);
1363 error(ERR_COULD_NOT_WRITE, i18n(
"Changing the flags of message %1 "
1364 "failed.").arg(_url.prettyURL()));
1367 completeQueue.removeRef (cmd);
1368 if (!newFlags.isEmpty())
1371 clientStore (aSequence,
"+FLAGS.SILENT", newFlags));
1372 if (cmd->
result () !=
"OK")
1374 completeQueue.removeRef (cmd);
1375 error(ERR_COULD_NOT_WRITE, i18n(
"Changing the flags of message %1 "
1376 "failed.").arg(_url.prettyURL()));
1379 completeQueue.removeRef (cmd);
1390 stream >> _url >> seen;
1392 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1393 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1394 if ( !assureBox(aBox,
true) )
1403 if (cmd->
result () !=
"OK")
1405 completeQueue.removeRef (cmd);
1406 error(ERR_COULD_NOT_WRITE, i18n(
"Changing the flags of message %1 "
1407 "failed.").arg(_url.prettyURL()));
1410 completeQueue.removeRef (cmd);
1428 kdWarning(7116) <<
"Unknown command in special(): " << tmp << endl;
1429 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(tmp)) );
1440 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1441 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1447 stream >> user >> acl;
1448 kdDebug(7116) <<
"SETACL " << aBox <<
" " << user <<
" " << acl << endl;
1450 if (cmd->
result () !=
"OK")
1452 error(ERR_SLAVE_DEFINED, i18n(
"Setting the Access Control List on folder %1 "
1453 "for user %2 failed. The server returned: %3")
1454 .arg(_url.prettyURL())
1459 completeQueue.removeRef (cmd);
1467 kdDebug(7116) <<
"DELETEACL " << aBox <<
" " << user << endl;
1469 if (cmd->
result () !=
"OK")
1471 error(ERR_SLAVE_DEFINED, i18n(
"Deleting the Access Control List on folder %1 "
1472 "for user %2 failed. The server returned: %3")
1473 .arg(_url.prettyURL())
1478 completeQueue.removeRef (cmd);
1484 kdDebug(7116) <<
"GETACL " << aBox << endl;
1486 if (cmd->
result () !=
"OK")
1488 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1489 "failed. The server returned: %2")
1490 .arg(_url.prettyURL())
1498 kdDebug(7116) << getResults() << endl;
1499 infoMessage(getResults().join(
"\"" ));
1506 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1511 kdDebug(7116) <<
"MYRIGHTS " << aBox << endl;
1513 if (cmd->
result () !=
"OK")
1515 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1516 "failed. The server returned: %2")
1517 .arg(_url.prettyURL())
1521 TQStringList lst = getResults();
1522 kdDebug(7116) <<
"myrights results: " << lst << endl;
1523 if ( !lst.isEmpty() ) {
1524 Q_ASSERT( lst.count() == 1 );
1525 infoMessage( lst.first() );
1531 kdWarning(7116) <<
"Unknown special ACL command:" << command << endl;
1532 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1539 kdDebug(7116) <<
"IMAP4Protocol::specialSearchCommand" << endl;
1542 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1543 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1544 if (!assureBox(aBox,
false))
return;
1547 if (cmd->
result () !=
"OK")
1549 error(ERR_SLAVE_DEFINED, i18n(
"Searching of folder %1 "
1550 "failed. The server returned: %2")
1555 completeQueue.removeRef(cmd);
1556 TQStringList lst = getResults();
1557 kdDebug(7116) <<
"IMAP4Protocol::specialSearchCommand '" << aSection <<
1558 "' returns " << lst << endl;
1559 infoMessage( lst.join(
" " ) );
1567 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand" << endl;
1569 TQString command, arguments;
1572 stream >> command >> arguments;
1578 if ( type ==
'N' ) {
1579 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: normal mode" << endl;
1581 if (cmd->
result () !=
"OK")
1583 error(ERR_SLAVE_DEFINED, i18n(
"Custom command %1:%2 "
1584 "failed. The server returned: %3")
1590 completeQueue.removeRef(cmd);
1591 TQStringList lst = getResults();
1592 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand '" << command <<
1594 "' returns " << lst << endl;
1595 infoMessage( lst.join(
" " ) );
1603 if ( type ==
'E' ) {
1604 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: extended mode" << endl;
1606 while ( !parseLoop () ) ;
1609 if (!cmd->
isComplete () && !getContinuation ().isEmpty ())
1611 const TQByteArray buffer = arguments.utf8();
1614 bool sendOk = (write (buffer.data (), buffer.size ()) == (ssize_t)buffer.size ());
1615 processedSize( buffer.size() );
1618 error ( ERR_CONNECTION_BROKEN, myHost );
1619 completeQueue.removeRef ( cmd );
1620 setState(ISTATE_CONNECT);
1629 while (!parseLoop ()) ;
1633 completeQueue.removeRef (cmd);
1635 TQStringList lst = getResults();
1636 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: returns " << lst << endl;
1637 infoMessage( lst.join(
" " ) );
1649 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1650 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1660 TQMap<TQString, TQString> attributes;
1661 stream >> entry >> attributes;
1662 kdDebug(7116) <<
"SETANNOTATION " << aBox <<
" " << entry <<
" " << attributes.count() <<
" attributes" << endl;
1664 if (cmd->
result () !=
"OK")
1666 error(ERR_SLAVE_DEFINED, i18n(
"Setting the annotation %1 on folder %2 "
1667 " failed. The server returned: %3")
1669 .arg(_url.prettyURL())
1673 completeQueue.removeRef (cmd);
1684 TQStringList attributeNames;
1685 stream >> entry >> attributeNames;
1686 kdDebug(7116) <<
"GETANNOTATION " << aBox <<
" " << entry <<
" " << attributeNames << endl;
1688 if (cmd->
result () !=
"OK")
1690 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the annotation %1 on folder %2 "
1691 "failed. The server returned: %3")
1693 .arg(_url.prettyURL())
1700 kdDebug(7116) << getResults() << endl;
1701 infoMessage(getResults().join(
"\r" ));
1706 kdWarning(7116) <<
"Unknown special annotate command:" << command << endl;
1707 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1712 IMAP4Protocol::specialQuotaCommand(
int command, TQDataStream& stream )
1717 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1718 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1723 kdDebug(7116) <<
"QUOTAROOT " << aBox << endl;
1725 if (cmd->
result () !=
"OK")
1727 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the quota root information on folder %1 "
1728 "failed. The server returned: %2")
1729 .arg(_url.prettyURL())
1733 infoMessage(getResults().join(
"\r" ));
1739 kdDebug(7116) <<
"GEQUOTA command" << endl;
1740 kdWarning(7116) <<
"UNIMPLEMENTED" << endl;
1745 kdDebug(7116) <<
"SEQUOTA command" << endl;
1746 kdWarning(7116) <<
"UNIMPLEMENTED" << endl;
1750 kdWarning(7116) <<
"Unknown special quota command:" << command << endl;
1751 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1756 IMAP4Protocol::rename (
const KURL & src,
const KURL & dest,
bool overwrite)
1758 kdDebug(7116) <<
"IMAP4::rename - [" << (overwrite ?
"Overwrite" :
"NoOverwrite") <<
"] " << src.prettyURL() <<
" -> " << dest.prettyURL() << endl;
1759 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
1760 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
1761 enum IMAP_TYPE sType =
1762 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo,
false);
1763 enum IMAP_TYPE dType =
1764 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo,
false);
1766 if (dType == ITYPE_UNKNOWN)
1772 case ITYPE_DIR_AND_BOX:
1774 if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
1776 kdDebug(7116) <<
"IMAP4::rename - close " << getCurrentBox() << endl;
1779 bool ok = cmd->
result() ==
"OK";
1780 completeQueue.removeRef(cmd);
1783 kdWarning(7116) <<
"Unable to close mailbox!" << endl;
1784 error(ERR_CANNOT_RENAME, src.path());
1787 setState(ISTATE_LOGIN);
1790 if (cmd->
result () !=
"OK") {
1791 error (ERR_CANNOT_RENAME, src.path());
1792 completeQueue.removeRef (cmd);
1795 completeQueue.removeRef (cmd);
1802 error (ERR_CANNOT_RENAME, src.path());
1808 error (ERR_CANNOT_RENAME, src.path());
1815 IMAP4Protocol::slave_status ()
1817 bool connected = (getState() != ISTATE_NO) && isConnectionValid();
1818 kdDebug(7116) <<
"IMAP4::slave_status " << connected << endl;
1819 slaveStatus ( connected ? myHost : TQString(), connected );
1823 IMAP4Protocol::dispatch (
int command,
const TQByteArray & data)
1825 kdDebug(7116) <<
"IMAP4::dispatch - command=" << command << endl;
1826 KIO::TCPSlaveBase::dispatch (command, data);
1832 kdDebug(7116) <<
"IMAP4::stat - " << _url.prettyURL() << endl;
1833 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1835 enum IMAP_TYPE aType =
1836 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
1842 atom.m_uds = UDS_NAME;
1844 entry.append (atom);
1846 if (!aSection.isEmpty())
1848 if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
1851 bool ok = cmd->
result() ==
"OK";
1852 completeQueue.removeRef(cmd);
1855 error(ERR_COULD_NOT_STAT, aBox);
1858 setState(ISTATE_LOGIN);
1862 if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1867 ok = cmd->
result() ==
"OK";
1869 completeQueue.removeRef(cmd);
1875 if (cmd->
result () ==
"OK")
1877 for (TQValueListIterator < imapList > it = listResponses.begin ();
1878 it != listResponses.end (); ++it)
1880 if (aBox == (*it).name ()) found =
true;
1883 completeQueue.removeRef (cmd);
1885 error(ERR_COULD_NOT_STAT, aBox);
1887 error(KIO::ERR_DOES_NOT_EXIST, aBox);
1890 if ((aSection ==
"UIDNEXT" && geStatus().uidNextAvailable())
1891 || (aSection ==
"UNSEEN" && geStatus().unseenAvailable()))
1893 atom.m_uds = UDS_SIZE;
1894 atom.m_str = TQString();
1895 atom.m_long = (aSection ==
"UIDNEXT") ? geStatus().uidNext()
1896 : geStatus().unseen();
1900 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
1901 aType == ITYPE_ATTACH)
1905 if (aBox == getCurrentBox ())
1906 validity = selectInfo.uidValidity ();
1914 completeQueue.removeRef (cmd);
1915 validity = geStatus ().uidValidity ();
1919 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
1922 if (validity > 0 && validity != aValidity.toULong ())
1927 newUrl.setPath (
"/" + aBox +
";UIDVALIDITY=" +
1928 TQString::number(validity));
1929 kdDebug(7116) <<
"IMAP4::stat - redirecting to " << newUrl.prettyURL() << endl;
1930 redirection (newUrl);
1933 else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1940 if (validity > 0 && validity != aValidity.toULong ())
1942 aType = ITYPE_UNKNOWN;
1943 kdDebug(7116) <<
"IMAP4::stat - url has invalid validity [" << validity <<
"d] " << _url.prettyURL() << endl;
1948 atom.m_uds = UDS_MIME_TYPE;
1949 atom.m_str = getMimeType (aType);
1950 entry.append (atom);
1952 kdDebug(7116) <<
"IMAP4: stat: " << atom.m_str << endl;
1956 atom.m_uds = UDS_FILE_TYPE;
1957 atom.m_str = TQString();
1958 atom.m_long = S_IFDIR;
1959 entry.append (atom);
1963 case ITYPE_DIR_AND_BOX:
1964 atom.m_uds = UDS_FILE_TYPE;
1965 atom.m_str = TQString();
1966 atom.m_long = S_IFDIR;
1967 entry.append (atom);
1972 atom.m_uds = UDS_FILE_TYPE;
1973 atom.m_str = TQString();
1974 atom.m_long = S_IFREG;
1975 entry.append (atom);
1979 error (ERR_DOES_NOT_EXIST, _url.prettyURL());
1984 kdDebug(7116) <<
"IMAP4::stat - Finishing stat" << endl;
1988 void IMAP4Protocol::openConnection()
1990 if (makeLogin()) connected();
1993 void IMAP4Protocol::closeConnection()
1995 if (getState() == ISTATE_NO)
return;
1996 if (getState() == ISTATE_SELECT && metaData(
"expunge") ==
"auto")
1999 completeQueue.removeRef (cmd);
2001 if (getState() != ISTATE_CONNECT)
2004 completeQueue.removeRef (cmd);
2007 setState(ISTATE_NO);
2008 completeQueue.clear();
2011 currentBox = TQString();
2015 bool IMAP4Protocol::makeLogin ()
2017 if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
2020 kdDebug(7116) <<
"IMAP4::makeLogin - checking login" << endl;
2021 bool alreadyConnected = getState() == ISTATE_CONNECT;
2022 kdDebug(7116) <<
"IMAP4::makeLogin - alreadyConnected " << alreadyConnected << endl;
2023 if (alreadyConnected || connectToHost (myHost.latin1(), myPort))
2027 setState(ISTATE_CONNECT);
2029 myAuth = metaData(
"auth");
2030 myTLS = metaData(
"tls");
2031 kdDebug(7116) <<
"myAuth: " << myAuth << endl;
2036 if (!alreadyConnected)
while (!parseLoop ()) ;
2038 if (!unhandled.isEmpty()) greeting = unhandled.first().stripWhiteSpace();
2040 cmd = doCommand (
new imapCommand (
"CAPABILITY",
""));
2042 kdDebug(7116) <<
"IMAP4: setHost: capability" << endl;
2043 for (TQStringList::Iterator it = imapCapabilities.begin ();
2044 it != imapCapabilities.end (); ++it)
2046 kdDebug(7116) <<
"'" << (*it) <<
"'" << endl;
2048 completeQueue.removeRef (cmd);
2050 if (!hasCapability(
"IMAP4") && !hasCapability(
"IMAP4rev1"))
2052 error(ERR_COULD_NOT_LOGIN, i18n(
"The server %1 supports neither "
2053 "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2")
2054 .arg(myHost).arg(greeting));
2059 if (metaData(
"nologin") ==
"on")
return TRUE;
2061 if (myTLS ==
"on" && !hasCapability(TQString(
"STARTTLS")))
2063 error(ERR_COULD_NOT_LOGIN, i18n(
"The server does not support TLS.\n"
2064 "Disable this security feature to connect unencrypted."));
2068 if ((myTLS ==
"on" || (canUseTLS() && myTLS !=
"off")) &&
2069 hasCapability(TQString(
"STARTTLS")))
2072 if (cmd->
result () ==
"OK")
2074 completeQueue.removeRef(cmd);
2075 int tlsrc = startTLS();
2078 kdDebug(7116) <<
"TLS mode has been enabled." << endl;
2080 for (TQStringList::Iterator it = imapCapabilities.begin ();
2081 it != imapCapabilities.end (); ++it)
2083 kdDebug(7116) <<
"'" << (*it) <<
"'" << endl;
2085 completeQueue.removeRef (cmd2);
2087 kdWarning(7116) <<
"TLS mode setup has failed. Aborting." << endl;
2088 error (ERR_COULD_NOT_LOGIN, i18n(
"Starting TLS failed."));
2092 }
else completeQueue.removeRef(cmd);
2095 if (myAuth.isEmpty () || myAuth ==
"*") {
2096 if (hasCapability (TQString (
"LOGINDISABLED"))) {
2097 error (ERR_COULD_NOT_LOGIN, i18n(
"LOGIN is disabled by the server."));
2103 if (!hasCapability (TQString (
"AUTH=") + myAuth)) {
2104 error (ERR_COULD_NOT_LOGIN, i18n(
"The authentication method %1 is not "
2105 "supported by the server.").arg(myAuth));
2111 if ( greeting.contains( TQRegExp(
"Cyrus IMAP4 v2.1" ) ) ) {
2112 removeCapability(
"ANNOTATEMORE" );
2116 TQRegExp regExp(
"Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)",
false );
2117 if ( regExp.search( greeting ) >= 0 ) {
2118 const int major = regExp.cap( 1 ).toInt();
2119 const int minor = regExp.cap( 2 ).toInt();
2120 const int patch = regExp.cap( 3 ).toInt();
2121 if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
2122 kdDebug(7116) << k_funcinfo <<
"Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support" << endl;
2123 imapCapabilities.append(
"x-kmail-sharedseen" );
2127 kdDebug(7116) <<
"IMAP4::makeLogin - attempting login" << endl;
2129 KIO::AuthInfo authInfo;
2130 authInfo.username = myUser;
2131 authInfo.password = myPass;
2132 authInfo.prompt = i18n (
"Username and password for your IMAP account:");
2134 kdDebug(7116) <<
"IMAP4::makeLogin - open_PassDlg said user=" << myUser <<
" pass=xx" << endl;
2136 TQString resultInfo;
2137 if (myAuth.isEmpty () || myAuth ==
"*")
2139 if (myUser.isEmpty () || myPass.isEmpty ()) {
2140 if(openPassDlg (authInfo)) {
2141 myUser = authInfo.username;
2142 myPass = authInfo.password;
2145 if (!clientLogin (myUser, myPass, resultInfo))
2146 error(KIO::ERR_COULD_NOT_AUTHENTICATE, i18n(
"Unable to login. Probably the "
2147 "password is wrong.\nThe server %1 replied:\n%2").arg(myHost).arg(resultInfo));
2151 #ifdef HAVE_LIBSASL2
2152 if (!clientAuthenticate (
this, authInfo, myHost, myAuth, mySSL, resultInfo))
2153 error(KIO::ERR_COULD_NOT_AUTHENTICATE, i18n(
"Unable to authenticate via %1.\n"
2154 "The server %2 replied:\n%3").arg(myAuth).arg(myHost).arg(resultInfo));
2156 myUser = authInfo.username;
2157 myPass = authInfo.password;
2160 error(KIO::ERR_COULD_NOT_LOGIN, i18n(
"SASL authentication is not compiled into kio_imap4."));
2163 if ( hasCapability(
"NAMESPACE") )
2167 if (cmd->
result () ==
"OK")
2169 kdDebug(7116) <<
"makeLogin - registered namespaces" << endl;
2171 completeQueue.removeRef (cmd);
2175 if (cmd->
result () ==
"OK")
2177 TQValueListIterator < imapList > it = listResponses.begin();
2178 if ( it == listResponses.end() )
2182 completeQueue.removeRef (cmd);
2184 if (cmd->
result () ==
"OK")
2186 it = listResponses.begin();
2189 if ( it != listResponses.end() )
2191 namespaceToDelimiter[TQString()] = (*it).hierarchyDelimiter();
2192 kdDebug(7116) <<
"makeLogin - delimiter for empty ns='" <<
2193 (*it).hierarchyDelimiter() <<
"'" << endl;
2194 if ( !hasCapability(
"NAMESPACE") )
2197 TQString nsentry = TQString::number( 0 ) +
"=="
2198 + (*it).hierarchyDelimiter();
2199 imapNamespaces.append( nsentry );
2203 completeQueue.removeRef (cmd);
2205 kdDebug(7116) <<
"makeLogin - NO login" << endl;
2208 return getState() == ISTATE_LOGIN;
2215 TQCString writer = aStr.utf8();
2216 int len = writer.length();
2219 if (len == 0 || (writer[len - 1] !=
'\n')) {
2225 write(writer.data(), len);
2229 IMAP4Protocol::getMimeType (
enum IMAP_TYPE aType)
2234 return "inode/directory";
2238 return "message/digest";
2241 case ITYPE_DIR_AND_BOX:
2242 return "message/directory";
2246 return "message/rfc822";
2251 return "application/octet-stream";
2256 return "unknown/unknown";
2263 IMAP4Protocol::doListEntry (
const KURL & _url,
int stretch, imapCache * cache,
2264 bool withFlags,
bool withSubject)
2267 aURL.setQuery (TQString());
2268 const TQString encodedUrl = aURL.url(0, 106);
2269 doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
2275 IMAP4Protocol::doListEntry (
const TQString & encodedUrl,
int stretch, imapCache * cache,
2276 bool withFlags,
bool withSubject)
2285 const TQString uid = TQString::number(cache->getUid());
2287 atom.m_uds = UDS_NAME;
2292 atom.m_str =
"0000000000000000" + atom.m_str;
2293 atom.m_str = atom.m_str.right (stretch);
2301 entry.append (atom);
2303 atom.m_uds = UDS_URL;
2304 atom.m_str = encodedUrl;
2305 if (atom.m_str[atom.m_str.length () - 1] !=
'/')
2307 atom.m_str +=
";UID=" + uid;
2309 entry.append (atom);
2311 atom.m_uds = UDS_FILE_TYPE;
2312 atom.m_str = TQString();
2313 atom.m_long = S_IFREG;
2314 entry.append (atom);
2316 atom.m_uds = UDS_SIZE;
2317 atom.m_long = cache->getSize();
2318 entry.append (atom);
2320 atom.m_uds = UDS_MIME_TYPE;
2321 atom.m_str =
"message/rfc822";
2323 entry.append (atom);
2325 atom.m_uds = UDS_USER;
2326 atom.m_str = myUser;
2327 entry.append (atom);
2329 atom.m_uds = KIO::UDS_ACCESS;
2330 atom.m_long = (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR;
2331 entry.append (atom);
2333 listEntry (entry,
false);
2338 IMAP4Protocol::doListEntry (
const KURL & _url,
const TQString & myBox,
2339 const imapList & item,
bool appendPath)
2342 aURL.setQuery (TQString());
2345 int hdLen = item.hierarchyDelimiter().length();
2349 TQString mailboxName = item.name ();
2352 if (mailboxName.find (myBox) == 0 && mailboxName.length() > myBox.length())
2355 mailboxName.right (mailboxName.length () - myBox.length ());
2357 if (mailboxName[0] ==
'/')
2358 mailboxName = mailboxName.right (mailboxName.length () - 1);
2359 if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
2360 mailboxName = mailboxName.right(mailboxName.length () - hdLen);
2361 if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
2362 mailboxName.truncate(mailboxName.length () - hdLen);
2364 atom.m_uds = UDS_NAME;
2365 if (!item.hierarchyDelimiter().isEmpty() &&
2366 mailboxName.find(item.hierarchyDelimiter()) != -1)
2367 atom.m_str = mailboxName.section(item.hierarchyDelimiter(), -1);
2369 atom.m_str = mailboxName;
2372 if (atom.m_str.isEmpty ())
2375 if (!atom.m_str.isEmpty ())
2378 entry.append (atom);
2380 if (!item.noSelect ())
2382 atom.m_uds = UDS_MIME_TYPE;
2383 if (!item.noInferiors ())
2385 atom.m_str =
"message/directory";
2387 atom.m_str =
"message/digest";
2390 entry.append (atom);
2394 atom.m_uds = UDS_FILE_TYPE;
2395 atom.m_str = TQString();
2396 atom.m_long = S_IFDIR;
2397 entry.append (atom);
2399 else if (!item.noInferiors ())
2401 atom.m_uds = UDS_MIME_TYPE;
2402 atom.m_str =
"inode/directory";
2404 entry.append (atom);
2408 atom.m_uds = UDS_FILE_TYPE;
2409 atom.m_str = TQString();
2410 atom.m_long = S_IFDIR;
2411 entry.append (atom);
2415 atom.m_uds = UDS_MIME_TYPE;
2416 atom.m_str =
"unknown/unknown";
2418 entry.append (atom);
2421 atom.m_uds = UDS_URL;
2422 TQString path = aURL.path();
2423 atom.m_str = aURL.url (0, 106);
2426 if (path[path.length() - 1] ==
'/' && !path.isEmpty() && path !=
"/")
2427 path.truncate(path.length() - 1);
2428 if (!path.isEmpty() && path !=
"/"
2429 && path.right(hdLen) != item.hierarchyDelimiter()) {
2430 path += item.hierarchyDelimiter();
2432 path += mailboxName;
2433 if (path.upper() ==
"/INBOX/") {
2435 path = path.upper();
2439 atom.m_str = aURL.url(0, 106);
2441 entry.append (atom);
2443 atom.m_uds = UDS_USER;
2444 atom.m_str = myUser;
2445 entry.append (atom);
2447 atom.m_uds = UDS_ACCESS;
2448 atom.m_long = S_IRUSR | S_IXUSR | S_IWUSR;
2449 entry.append (atom);
2451 atom.m_uds = UDS_EXTRA;
2452 atom.m_str = item.attributesAsString();
2454 entry.append (atom);
2456 listEntry (entry,
false);
2463 TQString & _section, TQString & _type, TQString & _uid,
2464 TQString & _validity, TQString & _hierarchyDelimiter,
2465 TQString & _info,
bool cache)
2467 enum IMAP_TYPE retVal;
2468 retVal = ITYPE_UNKNOWN;
2470 imapParser::parseURL (_url, _box, _section, _type, _uid, _validity, _info);
2474 TQString myNamespace = namespaceForBox( _box );
2475 kdDebug(7116) <<
"IMAP4::parseURL - namespace=" << myNamespace << endl;
2476 if ( namespaceToDelimiter.contains(myNamespace) )
2478 _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
2479 kdDebug(7116) <<
"IMAP4::parseURL - delimiter=" << _hierarchyDelimiter << endl;
2482 if (!_box.isEmpty ())
2484 kdDebug(7116) <<
"IMAP4::parseURL - box=" << _box << endl;
2488 if (getCurrentBox () != _box ||
2489 _type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK")
2494 retVal = ITYPE_DIR_AND_BOX;
2501 if (cmd->
result () ==
"OK")
2503 for (TQValueListIterator < imapList > it = listResponses.begin ();
2504 it != listResponses.end (); ++it)
2507 if (_box == (*it).name ())
2509 if ( !(*it).hierarchyDelimiter().isEmpty() )
2510 _hierarchyDelimiter = (*it).hierarchyDelimiter();
2511 if ((*it).noSelect ())
2515 else if ((*it).noInferiors ())
2521 retVal = ITYPE_DIR_AND_BOX;
2526 if ( retVal == ITYPE_UNKNOWN &&
2527 namespaceToDelimiter.contains(_box) ) {
2531 kdDebug(7116) <<
"IMAP4::parseURL - got error for " << _box << endl;
2533 completeQueue.removeRef (cmd);
2542 kdDebug(7116) <<
"IMAP4::parseURL: no login!" << endl;
2548 kdDebug(7116) <<
"IMAP4: parseURL: box [root]" << endl;
2553 if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
2555 if (!_uid.isEmpty ())
2557 if (_uid.find (
':') == -1 && _uid.find (
',') == -1
2558 && _uid.find (
'*') == -1)
2562 if (retVal == ITYPE_MSG)
2564 if ( (_section.find (
"BODY.PEEK[", 0,
false) != -1 ||
2565 _section.find (
"BODY[", 0,
false) != -1) &&
2566 _section.find(
".MIME") == -1 &&
2567 _section.find(
".HEADER") == -1 )
2568 retVal = ITYPE_ATTACH;
2570 if ( _hierarchyDelimiter.isEmpty() &&
2571 (_type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK") )
2575 if (!_box.isEmpty())
2577 int start = _url.path().findRev(_box);
2579 _hierarchyDelimiter = _url.path().mid(start-1, start);
2580 kdDebug(7116) <<
"IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
2581 <<
" from URL " << _url.path() << endl;
2583 if (_hierarchyDelimiter.isEmpty())
2584 _hierarchyDelimiter =
"/";
2586 kdDebug(7116) <<
"IMAP4::parseURL - return " << retVal << endl;
2595 len = _str.length();
2600 if ( !outputBuffer.isOpen() ) {
2601 outputBuffer.open(IO_WriteOnly);
2603 outputBuffer.at(outputBufferIndex);
2604 outputBuffer.writeBlock(_str.data(), len);
2605 outputBufferIndex += len;
2610 bool relay = relayEnabled;
2612 relayEnabled =
true;
2613 temp.setRawData (_str.data (), len);
2615 temp.resetRawData (_str.data (), len);
2617 relayEnabled = relay;
2624 if (outputBufferIndex == 0)
2626 outputBuffer.close();
2627 outputCache.resize(outputBufferIndex);
2631 TQByteArray decoded;
2632 if (contentEncoding.find(
"quoted-printable", 0,
false) == 0)
2633 decoded = KCodecs::quotedPrintableDecode(outputCache);
2634 else if (contentEncoding.find(
"base64", 0,
false) == 0)
2635 KCodecs::base64Decode(outputCache, decoded);
2637 decoded = outputCache;
2639 TQString mimetype = KMimeType::findByContent( decoded )->name();
2640 kdDebug(7116) <<
"IMAP4::flushOutput - mimeType " << mimetype << endl;
2642 decodeContent =
false;
2645 data( outputCache );
2647 mProcessedSize += outputBufferIndex;
2648 processedSize( mProcessedSize );
2649 outputBufferIndex = 0;
2650 outputCache[0] =
'\0';
2651 outputBuffer.setBuffer(outputCache);
2654 ssize_t IMAP4Protocol::myRead(
void *data, ssize_t len)
2658 ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
2659 memcpy(data, readBuffer, copyLen);
2660 readBufferLen -= copyLen;
2661 if (readBufferLen) memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
2664 if (!isConnectionValid())
return 0;
2665 waitForResponse( responseTimeout() );
2666 return read(data, len);
2670 IMAP4Protocol::assureBox (
const TQString & aBox,
bool readonly)
2672 if (aBox.isEmpty())
return false;
2676 if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
2679 kdDebug(7116) <<
"IMAP4Protocol::assureBox - opening box" << endl;
2680 selectInfo = imapInfo();
2682 bool ok = cmd->
result() ==
"OK";
2684 completeQueue.removeRef (cmd);
2690 if (cmd->
result () ==
"OK")
2692 for (TQValueListIterator < imapList > it = listResponses.begin ();
2693 it != listResponses.end (); ++it)
2695 if (aBox == (*it).name ()) found =
true;
2698 completeQueue.removeRef (cmd);
2700 if (cmdInfo.find(
"permission", 0,
false) != -1) {
2702 error(ERR_ACCESS_DENIED, cmdInfo);
2704 error(ERR_SLAVE_DEFINED, i18n(
"Unable to open folder %1. The server replied: %2").arg(aBox).arg(cmdInfo));
2707 error(KIO::ERR_DOES_NOT_EXIST, aBox);
2717 kdDebug(7116) <<
"IMAP4Protocol::assureBox - reusing box" << endl;
2718 if ( mTimeOfLastNoop.secsTo( TQDateTime::currentDateTime() ) > 10 ) {
2720 completeQueue.removeRef (cmd);
2721 mTimeOfLastNoop = TQDateTime::currentDateTime();
2722 kdDebug(7116) <<
"IMAP4Protocol::assureBox - noop timer fired" << endl;
2727 if (!getSelected().readWrite() && !readonly)
2729 error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);