65 #include "rfcdecoder.h"
72 #include <sys/types.h>
78 #include <sasl/sasl.h>
83 #include <tqdatetime.h>
85 #include <tdeprotocolmanager.h>
86 #include <tdemessagebox.h>
88 #include <tdeio/connection.h>
89 #include <tdeio/slaveinterface.h>
90 #include <tdeio/passdlg.h>
91 #include <tdelocale.h>
92 #include <kmimetype.h>
95 #include <tdemacros.h>
97 #define IMAP_PROTOCOL "imap"
98 #define IMAP_SSL_PROTOCOL "imaps"
99 const int ImapPort = 143;
100 const int ImapsPort = 993;
102 using namespace TDEIO;
106 void sigalrm_handler (
int);
107 TDE_EXPORT
int kdemain (
int argc,
char **argv);
111 kdemain (
int argc,
char **argv)
113 kdDebug(7116) <<
"IMAP4::kdemain" << endl;
115 TDEInstance instance (
"tdeio_imap4");
118 fprintf(stderr,
"Usage: tdeio_imap4 protocol domain-socket1 domain-socket2\n");
123 if ( sasl_client_init( NULL ) != SASL_OK ) {
124 fprintf(stderr,
"SASL library initialization failed!\n");
132 if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
134 else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
138 slave->dispatchLoop ();
149 sigchld_handler (
int signo)
154 const int save_errno = errno;
157 while (signo == SIGCHLD)
159 pid = waitpid (-1, &status, WNOHANG);
165 signal (SIGCHLD, sigchld_handler);
173 IMAP4Protocol::IMAP4Protocol (
const TQCString & pool,
const TQCString & app,
bool isSSL):TCPSlaveBase ((isSSL ? 993 : 143),
174 (isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool,
175 app, isSSL), imapParser (),
mimeIO (), outputBuffer(outputCache)
177 outputBufferIndex = 0;
179 readBuffer[0] = 0x00;
180 relayEnabled =
false;
183 decodeContent =
false;
184 mTimeOfLastNoop = TQDateTime();
187 IMAP4Protocol::~IMAP4Protocol ()
190 kdDebug(7116) <<
"IMAP4: Finishing" << endl;
196 if (!makeLogin())
return;
197 kdDebug(7116) <<
"IMAP4::get - " << _url.prettyURL() << endl;
198 TQString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
199 enum IMAP_TYPE aEnum =
200 parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
201 if (aEnum != ITYPE_ATTACH)
202 mimeType (getMimeType(aEnum));
203 if (aInfo ==
"DECODE")
204 decodeContent =
true;
206 if (aSequence ==
"0:0" && getState() == ISTATE_SELECT)
209 completeQueue.removeRef(cmd);
212 if (aSequence.isEmpty ())
219 if (!assureBox (aBox,
true))
return;
222 if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
223 && selectInfo.uidValidity () != aValidity.toULong ())
226 error (ERR_COULD_NOT_READ, _url.prettyURL());
239 TQString aUpper = aSection.upper();
240 if (aUpper.find (
"STRUCTURE") != -1)
242 aSection =
"BODYSTRUCTURE";
244 else if (aUpper.find (
"ENVELOPE") != -1)
246 aSection =
"UID RFC822.SIZE FLAGS ENVELOPE";
247 if (hasCapability(
"IMAP4rev1")) {
248 aSection +=
" BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
251 aSection +=
" RFC822.HEADER.LINES (REFERENCES)";
254 else if (aUpper ==
"HEADER")
256 aSection =
"UID RFC822.HEADER RFC822.SIZE FLAGS";
258 else if (aUpper.find (
"BODY.PEEK[") != -1)
260 if (aUpper.find (
"BODY.PEEK[]") != -1)
262 if (!hasCapability(
"IMAP4rev1"))
263 aSection.replace(
"BODY.PEEK[]",
"RFC822.PEEK");
265 aSection.prepend(
"UID RFC822.SIZE FLAGS ");
267 else if (aSection.isEmpty())
269 aSection =
"UID BODY[] RFC822.SIZE FLAGS";
271 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
276 (
"Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
277 if (selectInfo.recentAvailable ())
278 outputLineStr (
"X-Recent: " +
279 TQString::number(selectInfo.recent ()) +
"\r\n");
280 if (selectInfo.countAvailable ())
281 outputLineStr (
"X-Count: " + TQString::number(selectInfo.count ()) +
283 if (selectInfo.unseenAvailable ())
284 outputLineStr (
"X-Unseen: " +
285 TQString::number(selectInfo.unseen ()) +
"\r\n");
286 if (selectInfo.uidValidityAvailable ())
287 outputLineStr (
"X-uidValidity: " +
288 TQString::number(selectInfo.uidValidity ()) +
290 if (selectInfo.uidNextAvailable ())
291 outputLineStr (
"X-UidNext: " +
292 TQString::number(selectInfo.uidNext ()) +
"\r\n");
293 if (selectInfo.flagsAvailable ())
294 outputLineStr (
"X-Flags: " + TQString::number(selectInfo.flags ()) +
296 if (selectInfo.permanentFlagsAvailable ())
297 outputLineStr (
"X-PermanentFlags: " +
298 TQString::number(selectInfo.permanentFlags ()) +
"\r\n");
299 if (selectInfo.readWriteAvailable ()) {
300 if (selectInfo.readWrite()) {
311 if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
314 if (aSequence !=
"0:0")
316 TQString contentEncoding;
317 if (aEnum == ITYPE_ATTACH && decodeContent)
320 TQString mySection = aSection;
321 mySection.replace(
"]",
".MIME]");
325 while (!parseLoop ()) ;
328 completeQueue.removeRef (cmd);
330 if (getLastHandled() && getLastHandled()->getHeader())
331 contentEncoding = getLastHandled()->getHeader()->getEncoding();
341 aUpper = aSection.upper();
344 while (!(res = parseLoop())) ;
345 if (res == -1)
break;
348 imapCache *cache = getLastHandled ();
350 lastone = cache->getHeader ();
354 if ((aUpper.find (
"BODYSTRUCTURE") != -1)
355 || (aUpper.find (
"FLAGS") != -1)
356 || (aUpper.find (
"UID") != -1)
357 || (aUpper.find (
"ENVELOPE") != -1)
358 || (aUpper.find (
"BODY.PEEK[0]") != -1
359 && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
361 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
366 if (cache && cache->getUid () != 0)
367 outputLineStr (
"X-UID: " +
368 TQString::number(cache->getUid ()) +
"\r\n");
369 if (cache && cache->getSize () != 0)
370 outputLineStr (
"X-Length: " +
371 TQString::number(cache->getSize ()) +
"\r\n");
372 if (cache && !cache->getDate ().isEmpty())
373 outputLineStr (
"X-Date: " + cache->getDate () +
"\r\n");
374 if (cache && cache->getFlags () != 0)
375 outputLineStr (
"X-Flags: " +
376 TQString::number(cache->getFlags ()) +
"\r\n");
377 }
else cacheOutput =
true;
378 if ( lastone && !decodeContent )
379 lastone->outputPart (*
this);
386 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
392 completeQueue.removeRef (cmd);
397 data (TQByteArray ());
400 relayEnabled =
false;
402 kdDebug(7116) <<
"IMAP4::get - finished" << endl;
408 kdDebug(7116) <<
" IMAP4::listDir - " << _url.prettyURL() << endl;
410 if (_url.path().isEmpty())
419 TQString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
421 enum IMAP_TYPE myType =
422 parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
423 myDelimiter, myInfo,
true);
425 if (!makeLogin())
return;
427 if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
429 TQString listStr = myBox;
432 if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
433 mySection !=
"FOLDERONLY")
434 listStr += myDelimiter;
436 if (mySection.isEmpty())
439 }
else if (mySection ==
"COMPLETE") {
442 kdDebug(7116) <<
"IMAP4Protocol::listDir - listStr=" << listStr << endl;
445 (myLType ==
"LSUB" || myLType ==
"LSUBNOCHECK")));
446 if (cmd->
result () ==
"OK")
448 TQString mailboxName;
452 if (aURL.path().find(
';') != -1)
453 aURL.setPath(aURL.path().left(aURL.path().find(
';')));
455 kdDebug(7116) <<
"IMAP4Protocol::listDir - got " << listResponses.count () << endl;
457 if (myLType ==
"LSUB")
460 TQValueList<imapList> listResponsesSave = listResponses;
462 for (TQValueListIterator < imapList > it = listResponsesSave.begin ();
463 it != listResponsesSave.end (); ++it)
466 for (TQValueListIterator < imapList > it2 = listResponses.begin ();
467 it2 != listResponses.end (); ++it2)
469 if ((*it2).name() == (*it).name())
478 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
480 kdDebug(7116) <<
"IMAP4Protocol::listDir - suppress " << (*it).name() << endl;
482 listResponses = listResponsesSave;
486 for (TQValueListIterator < imapList > it = listResponses.begin ();
487 it != listResponses.end (); ++it)
489 doListEntry (aURL, myBox, (*it), (mySection !=
"FOLDERONLY"));
493 listEntry (entry,
true);
497 error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyURL());
498 completeQueue.removeRef (cmd);
501 completeQueue.removeRef (cmd);
503 if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
504 && myLType !=
"LIST" && myLType !=
"LSUB" && myLType !=
"LSUBNOCHECK")
507 aURL.setQuery (TQString());
508 const TQString encodedUrl = aURL.url(0, 106);
510 if (!_url.query ().isEmpty ())
512 TQString query = KURL::decode_string (_url.query ());
513 query = query.right (query.length () - 1);
514 if (!query.isEmpty())
518 if (!assureBox (myBox,
true))
return;
520 if (!selectInfo.countAvailable() || selectInfo.count())
523 if (cmd->
result() !=
"OK")
525 error(ERR_UNSUPPORTED_ACTION, _url.prettyURL());
526 completeQueue.removeRef (cmd);
529 completeQueue.removeRef (cmd);
531 TQStringList list = getResults ();
534 if (selectInfo.uidNextAvailable ())
535 stretch = TQString::number(selectInfo.uidNext ()).length ();
539 for (TQStringList::ConstIterator it = list.begin(); it != list.end();
542 fake.setUid((*it).toULong());
543 doListEntry (encodedUrl, stretch, &fake);
546 listEntry (entry,
true);
552 if (!assureBox (myBox,
true))
return;
554 kdDebug(7116) <<
"IMAP4: select returned:" << endl;
555 if (selectInfo.recentAvailable ())
556 kdDebug(7116) <<
"Recent: " << selectInfo.recent () <<
"d" << endl;
557 if (selectInfo.countAvailable ())
558 kdDebug(7116) <<
"Count: " << selectInfo.count () <<
"d" << endl;
559 if (selectInfo.unseenAvailable ())
560 kdDebug(7116) <<
"Unseen: " << selectInfo.unseen () <<
"d" << endl;
561 if (selectInfo.uidValidityAvailable ())
562 kdDebug(7116) <<
"uidValidity: " << selectInfo.uidValidity () <<
"d" << endl;
563 if (selectInfo.flagsAvailable ())
564 kdDebug(7116) <<
"Flags: " << selectInfo.flags () <<
"d" << endl;
565 if (selectInfo.permanentFlagsAvailable ())
566 kdDebug(7116) <<
"PermanentFlags: " << selectInfo.permanentFlags () <<
"d" << endl;
567 if (selectInfo.readWriteAvailable ())
568 kdDebug(7116) <<
"Access: " << (selectInfo.readWrite ()?
"Read/Write" :
"Read only") << endl;
571 if (selectInfo.uidValidityAvailable ()
572 && selectInfo.uidValidity () != myValidity.toULong ())
577 newUrl.setPath (
"/" + myBox +
";UIDVALIDITY=" +
578 TQString::number(selectInfo.uidValidity ()));
579 kdDebug(7116) <<
"IMAP4::listDir - redirecting to " << newUrl.prettyURL() << endl;
580 redirection (newUrl);
586 if (selectInfo.count () > 0)
590 if (selectInfo.uidNextAvailable ())
591 stretch = TQString::number(selectInfo.uidNext ()).length ();
595 if (mySequence.isEmpty()) mySequence =
"1:*";
597 bool withSubject = mySection.isEmpty();
598 if (mySection.isEmpty()) mySection =
"UID RFC822.SIZE ENVELOPE";
600 bool withFlags = mySection.upper().find(
"FLAGS") != -1;
603 clientFetch (mySequence, mySection));
607 while (!parseLoop ()) ;
609 cache = getLastHandled ();
612 doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
616 listEntry (entry,
true);
620 if ( !selectInfo.alert().isNull() ) {
621 if ( !myBox.isEmpty() ) {
622 warning( i18n(
"Message from %1 while processing '%2': %3" ).arg( myHost, myBox, selectInfo.alert() ) );
624 warning( i18n(
"Message from %1: %2" ).arg( myHost, TQString(selectInfo.alert()) ) );
626 selectInfo.setAlert( 0 );
629 kdDebug(7116) <<
"IMAP4Protocol::listDir - Finishing listDir" << endl;
634 IMAP4Protocol::setHost (
const TQString & _host,
int _port,
635 const TQString & _user,
const TQString & _pass)
637 if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
640 if (!myHost.isEmpty ())
644 myPort = (mySSL) ? ImapsPort : ImapPort;
658 mProcessedSize += buffer.size();
659 processedSize( mProcessedSize );
660 }
else if (cacheOutput)
663 if ( !outputBuffer.isOpen() ) {
664 outputBuffer.open(IO_WriteOnly);
666 outputBuffer.at(outputBufferIndex);
667 outputBuffer.writeBlock(buffer, buffer.size());
668 outputBufferIndex += buffer.size();
683 while (buffer.size() < len)
685 ssize_t readLen = myRead(buf, TQMIN(len - buffer.size(),
sizeof(buf) - 1));
688 kdDebug(7116) <<
"parseRead: readLen == 0 - connection broken" << endl;
689 error (ERR_CONNECTION_BROKEN, myHost);
690 setState(ISTATE_CONNECT);
694 if (relay > buffer.size())
696 TQByteArray relayData;
697 ssize_t relbuf = relay - buffer.size();
698 int currentRelay = TQMIN(relbuf, readLen);
699 relayData.setRawData(buf, currentRelay);
701 relayData.resetRawData(buf, currentRelay);
704 TQBuffer stream (buffer);
705 stream.open (IO_WriteOnly);
706 stream.at (buffer.size ());
707 stream.writeBlock (buf, readLen);
711 return (buffer.size() == len);
717 if (myHost.isEmpty())
return FALSE;
721 if (readBufferLen > 0)
723 while (copyLen < readBufferLen && readBuffer[copyLen] !=
'\n') copyLen++;
724 if (copyLen < readBufferLen) copyLen++;
727 TQByteArray relayData;
729 if (copyLen < (ssize_t) relay)
731 relayData.setRawData (readBuffer, relay);
733 relayData.resetRawData (readBuffer, relay);
738 TQBuffer stream (buffer);
740 stream.open (IO_WriteOnly);
741 stream.at (buffer.size ());
742 stream.writeBlock (readBuffer, copyLen);
747 readBufferLen -= copyLen;
749 memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
750 if (buffer[buffer.size() - 1] ==
'\n')
return TRUE;
752 if (!isConnectionValid())
754 kdDebug(7116) <<
"parseReadLine - connection broken" << endl;
755 error (ERR_CONNECTION_BROKEN, myHost);
756 setState(ISTATE_CONNECT);
760 if (!waitForResponse( responseTimeout() ))
762 error(ERR_SERVER_TIMEOUT, myHost);
763 setState(ISTATE_CONNECT);
767 readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
768 if (readBufferLen == 0)
770 kdDebug(7116) <<
"parseReadLine: readBufferLen == 0 - connection broken" << endl;
771 error (ERR_CONNECTION_BROKEN, myHost);
772 setState(ISTATE_CONNECT);
780 IMAP4Protocol::setSubURL (
const KURL & _url)
782 kdDebug(7116) <<
"IMAP4::setSubURL - " << _url.prettyURL() << endl;
783 TDEIO::TCPSlaveBase::setSubURL (_url);
787 IMAP4Protocol::put (
const KURL & _url,
int,
bool,
bool)
789 kdDebug(7116) <<
"IMAP4::put - " << _url.prettyURL() << endl;
791 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
792 enum IMAP_TYPE aType =
793 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
796 if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
798 if (aBox[aBox.length () - 1] ==
'/')
799 aBox = aBox.right (aBox.length () - 1);
802 if (cmd->
result () !=
"OK") {
803 error (ERR_COULD_NOT_WRITE, _url.prettyURL());
804 completeQueue.removeRef (cmd);
807 completeQueue.removeRef (cmd);
811 TQPtrList < TQByteArray > bufferList;
818 TQByteArray *buffer =
new TQByteArray ();
820 result = readData (*buffer);
823 bufferList.append (buffer);
833 error (ERR_ABORTED, _url.prettyURL());
839 while (!parseLoop ()) ;
842 if (!cmd->
isComplete () && !getContinuation ().isEmpty ())
849 while (!bufferList.isEmpty () && sendOk)
851 buffer = bufferList.take (0);
854 (write (buffer->data (), buffer->size ()) ==
855 (ssize_t) buffer->size ());
856 wrote += buffer->size ();
857 processedSize(wrote);
861 error (ERR_CONNECTION_BROKEN, myHost);
862 completeQueue.removeRef (cmd);
863 setState(ISTATE_CONNECT);
870 while (!cmd->
isComplete () && getState() != ISTATE_NO)
872 if ( getState() == ISTATE_NO ) {
875 error( ERR_CONNECTION_BROKEN, myHost );
876 completeQueue.removeRef (cmd);
880 else if (cmd->
result () !=
"OK") {
881 error( ERR_SLAVE_DEFINED, cmd->
resultInfo() );
882 completeQueue.removeRef (cmd);
887 if (hasCapability(
"UIDPLUS"))
890 if (uid.find(
"APPENDUID") != -1)
892 uid = uid.section(
" ", 2, 2);
893 uid.truncate(uid.length()-1);
894 infoMessage(
"UID "+uid);
898 else if (aBox == getCurrentBox ())
902 clientSelect (aBox, !selectInfo.readWrite ()));
903 completeQueue.removeRef (cmd);
912 completeQueue.removeRef (cmd);
916 completeQueue.removeRef (cmd);
925 kdDebug(7116) <<
"IMAP4::mkdir - " << _url.prettyURL() << endl;
926 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
927 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
928 kdDebug(7116) <<
"IMAP4::mkdir - create " << aBox << endl;
931 if (cmd->
result () !=
"OK")
933 kdDebug(7116) <<
"IMAP4::mkdir - " << cmd->
resultInfo() << endl;
934 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
935 completeQueue.removeRef (cmd);
938 completeQueue.removeRef (cmd);
941 enum IMAP_TYPE type =
942 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
943 if (type == ITYPE_BOX)
945 bool ask = ( aInfo.find(
"ASKUSER" ) != -1 );
947 messageBox(QuestionYesNo,
948 i18n(
"The following folder will be created on the server: %1 "
949 "What do you want to store in this folder?").arg( aBox ),
950 i18n(
"Create Folder"),
951 i18n(
"&Messages"), i18n(
"&Subfolders")) == KMessageBox::No )
954 completeQueue.removeRef (cmd);
956 if (cmd->
result () !=
"OK")
958 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
959 completeQueue.removeRef (cmd);
962 completeQueue.removeRef (cmd);
967 completeQueue.removeRef(cmd);
973 IMAP4Protocol::copy (
const KURL & src,
const KURL & dest,
int,
bool overwrite)
975 kdDebug(7116) <<
"IMAP4::copy - [" << (overwrite ?
"Overwrite" :
"NoOverwrite") <<
"] " << src.prettyURL() <<
" -> " << dest.prettyURL() << endl;
976 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
977 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
978 enum IMAP_TYPE sType =
979 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
980 enum IMAP_TYPE dType =
981 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
984 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
987 int sub = dBox.find (sBox);
994 TQString subDir = dBox.right (dBox.length () - dBox.findRev (
'/'));
995 TQString topDir = dBox.left (sub);
996 testDir.setPath (
"/" + topDir);
998 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
1001 kdDebug(7116) <<
"IMAP4::copy - checking this destination " << topDir << endl;
1003 if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
1005 kdDebug(7116) <<
"IMAP4::copy - assuming this destination " << topDir << endl;
1012 topDir =
"/" + topDir + subDir;
1013 testDir.setPath (topDir);
1014 kdDebug(7116) <<
"IMAP4::copy - checking this destination " << topDir << endl;
1016 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
1018 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
1024 if (cmd->
result () ==
"OK")
1026 kdDebug(7116) <<
"IMAP4::copy - assuming this destination " << topDir << endl;
1032 completeQueue.removeRef (cmd);
1034 if (cmd->
result () ==
"OK")
1037 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
1039 completeQueue.removeRef (cmd);
1045 if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
1048 if (!assureBox(sBox,
true))
return;
1049 kdDebug(7116) <<
"IMAP4::copy - " << sBox <<
" -> " << dBox << endl;
1054 if (cmd->
result () !=
"OK")
1056 kdError(5006) <<
"IMAP4::copy - " << cmd->
resultInfo() << endl;
1057 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
1058 completeQueue.removeRef (cmd);
1061 if (hasCapability(
"UIDPLUS"))
1064 if (uid.find(
"COPYUID") != -1)
1066 uid = uid.section(
" ", 2, 3);
1067 uid.truncate(uid.length()-1);
1068 infoMessage(
"UID "+uid);
1072 completeQueue.removeRef (cmd);
1076 error (ERR_ACCESS_DENIED, src.prettyURL());
1085 kdDebug(7116) <<
"IMAP4::del - [" << (isFile ?
"File" :
"NoFile") <<
"] " << _url.prettyURL() << endl;
1086 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1087 enum IMAP_TYPE aType =
1088 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1093 case ITYPE_DIR_AND_BOX:
1094 if (!aSequence.isEmpty ())
1096 if (aSequence ==
"*")
1098 if (!assureBox (aBox,
false))
return;
1100 if (cmd->
result () !=
"OK") {
1101 error (ERR_CANNOT_DELETE, _url.prettyURL());
1102 completeQueue.removeRef (cmd);
1105 completeQueue.removeRef (cmd);
1110 if (!assureBox (aBox,
false))
return;
1113 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1114 if (cmd->
result () !=
"OK") {
1115 error (ERR_CANNOT_DELETE, _url.prettyURL());
1116 completeQueue.removeRef (cmd);
1119 completeQueue.removeRef (cmd);
1124 if (getCurrentBox() == aBox)
1127 completeQueue.removeRef(cmd);
1128 setState(ISTATE_LOGIN);
1132 completeQueue.removeRef(cmd);
1135 if (cmd->
result () !=
"OK")
1137 completeQueue.removeRef(cmd);
1138 if (!assureBox(aBox,
false))
return;
1139 bool stillOk =
true;
1144 if (cmd->
result () !=
"OK") stillOk =
false;
1145 completeQueue.removeRef(cmd);
1150 if (cmd->
result () !=
"OK") stillOk =
false;
1151 completeQueue.removeRef(cmd);
1152 setState(ISTATE_LOGIN);
1157 if (cmd->
result () !=
"OK") stillOk =
false;
1158 completeQueue.removeRef(cmd);
1162 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
1166 completeQueue.removeRef (cmd);
1174 if (cmd->
result () !=
"OK") {
1175 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
1176 completeQueue.removeRef (cmd);
1179 completeQueue.removeRef (cmd);
1186 if (!assureBox (aBox,
false))
return;
1189 clientStore (aSequence,
"+FLAGS.SILENT",
"\\DELETED"));
1190 if (cmd->
result () !=
"OK") {
1191 error (ERR_CANNOT_DELETE, _url.prettyURL());
1192 completeQueue.removeRef (cmd);
1195 completeQueue.removeRef (cmd);
1201 error (ERR_CANNOT_DELETE, _url.prettyURL());
1226 kdDebug(7116) <<
"IMAP4Protocol::special" << endl;
1227 if (!makeLogin())
return;
1229 TQDataStream stream(aData, IO_ReadOnly);
1240 stream >> src >> dest;
1241 copy(src, dest, 0, FALSE);
1247 infoMessage(imapCapabilities.join(
" "));
1255 if (cmd->
result () !=
"OK")
1257 kdDebug(7116) <<
"NOOP did not succeed - connection broken" << endl;
1258 completeQueue.removeRef (cmd);
1259 error (ERR_CONNECTION_BROKEN, myHost);
1262 completeQueue.removeRef (cmd);
1270 infoMessage( imapNamespaces.join(
",") );
1279 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1280 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1282 if (cmd->
result () !=
"OK")
1284 completeQueue.removeRef (cmd);
1285 error(ERR_SLAVE_DEFINED, i18n(
"Unsubscribe of folder %1 "
1286 "failed. The server returned: %2")
1287 .arg(_url.prettyURL())
1291 completeQueue.removeRef (cmd);
1300 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1301 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1303 if (cmd->
result () !=
"OK")
1305 completeQueue.removeRef (cmd);
1306 error(ERR_SLAVE_DEFINED, i18n(
"Subscribe of folder %1 "
1307 "failed. The server returned: %2")
1308 .arg(_url.prettyURL())
1312 completeQueue.removeRef (cmd);
1321 if ( hasCapability(
"ACL" ) ) {
1324 error( ERR_UNSUPPORTED_ACTION,
"ACL" );
1333 if ( hasCapability(
"ANNOTATEMORE" ) ) {
1336 error( ERR_UNSUPPORTED_ACTION,
"ANNOTATEMORE" );
1345 if ( hasCapability(
"QUOTA" ) ) {
1346 specialQuotaCommand( cmd, stream );
1348 error( ERR_UNSUPPORTED_ACTION,
"QUOTA" );
1357 stream >> _url >> newFlags;
1359 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1360 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1361 if (!assureBox(aBox,
false))
return;
1364 TQCString knownFlags =
"\\SEEN \\ANSWERED \\FLAGGED \\DRAFT";
1365 const imapInfo info = getSelected();
1366 if ( info.permanentFlagsAvailable() && (info.permanentFlags() & imapInfo::User) ) {
1367 knownFlags +=
" KMAILFORWARDED KMAILTODO KMAILWATCHED KMAILIGNORED $FORWARDED $TODO $WATCHED $IGNORED";
1371 clientStore (aSequence,
"-FLAGS.SILENT", knownFlags));
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);
1380 if (!newFlags.isEmpty())
1383 clientStore (aSequence,
"+FLAGS.SILENT", newFlags));
1384 if (cmd->
result () !=
"OK")
1386 completeQueue.removeRef (cmd);
1387 error(ERR_COULD_NOT_WRITE, i18n(
"Changing the flags of message %1 "
1388 "failed.").arg(_url.prettyURL()));
1391 completeQueue.removeRef (cmd);
1402 stream >> _url >> seen;
1404 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1405 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1406 if ( !assureBox(aBox,
true) )
1415 if (cmd->
result () !=
"OK")
1417 completeQueue.removeRef (cmd);
1418 error(ERR_COULD_NOT_WRITE, i18n(
"Changing the flags of message %1 "
1419 "failed.").arg(_url.prettyURL()));
1422 completeQueue.removeRef (cmd);
1440 kdWarning(7116) <<
"Unknown command in special(): " << tmp << endl;
1441 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(tmp)) );
1452 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1453 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1459 stream >> user >> acl;
1460 kdDebug(7116) <<
"SETACL " << aBox <<
" " << user <<
" " << acl << endl;
1462 if (cmd->
result () !=
"OK")
1464 error(ERR_SLAVE_DEFINED, i18n(
"Setting the Access Control List on folder %1 "
1465 "for user %2 failed. The server returned: %3")
1466 .arg(_url.prettyURL())
1471 completeQueue.removeRef (cmd);
1479 kdDebug(7116) <<
"DELETEACL " << aBox <<
" " << user << endl;
1481 if (cmd->
result () !=
"OK")
1483 error(ERR_SLAVE_DEFINED, i18n(
"Deleting the Access Control List on folder %1 "
1484 "for user %2 failed. The server returned: %3")
1485 .arg(_url.prettyURL())
1490 completeQueue.removeRef (cmd);
1496 kdDebug(7116) <<
"GETACL " << aBox << endl;
1498 if (cmd->
result () !=
"OK")
1500 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1501 "failed. The server returned: %2")
1502 .arg(_url.prettyURL())
1510 kdDebug(7116) << getResults() << endl;
1511 infoMessage(getResults().join(
"\"" ));
1518 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1523 kdDebug(7116) <<
"MYRIGHTS " << aBox << endl;
1525 if (cmd->
result () !=
"OK")
1527 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the Access Control List on folder %1 "
1528 "failed. The server returned: %2")
1529 .arg(_url.prettyURL())
1533 TQStringList lst = getResults();
1534 kdDebug(7116) <<
"myrights results: " << lst << endl;
1535 if ( !lst.isEmpty() ) {
1536 Q_ASSERT( lst.count() == 1 );
1537 infoMessage( lst.first() );
1543 kdWarning(7116) <<
"Unknown special ACL command:" << command << endl;
1544 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1551 kdDebug(7116) <<
"IMAP4Protocol::specialSearchCommand" << endl;
1554 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1555 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1556 if (!assureBox(aBox,
true))
return;
1559 if (cmd->
result () !=
"OK")
1561 error(ERR_SLAVE_DEFINED, i18n(
"Searching of folder %1 "
1562 "failed. The server returned: %2")
1567 completeQueue.removeRef(cmd);
1568 TQStringList lst = getResults();
1569 kdDebug(7116) <<
"IMAP4Protocol::specialSearchCommand '" << aSection <<
1570 "' returns " << lst << endl;
1571 infoMessage( lst.join(
" " ) );
1579 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand" << endl;
1581 TQString command, arguments;
1584 stream >> command >> arguments;
1590 if ( type ==
'N' ) {
1591 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: normal mode" << endl;
1593 if (cmd->
result () !=
"OK")
1595 error(ERR_SLAVE_DEFINED, i18n(
"Custom command %1:%2 "
1596 "failed. The server returned: %3")
1602 completeQueue.removeRef(cmd);
1603 TQStringList lst = getResults();
1604 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand '" << command <<
1606 "' returns " << lst << endl;
1607 infoMessage( lst.join(
" " ) );
1615 if ( type ==
'E' ) {
1616 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: extended mode" << endl;
1618 while ( !parseLoop () ) ;
1621 if (!cmd->
isComplete () && !getContinuation ().isEmpty ())
1623 const TQByteArray buffer = arguments.utf8();
1626 bool sendOk = (write (buffer.data (), buffer.size ()) == (ssize_t)buffer.size ());
1627 processedSize( buffer.size() );
1630 error ( ERR_CONNECTION_BROKEN, myHost );
1631 completeQueue.removeRef ( cmd );
1632 setState(ISTATE_CONNECT);
1641 while (!parseLoop ()) ;
1645 completeQueue.removeRef (cmd);
1647 TQStringList lst = getResults();
1648 kdDebug(7116) <<
"IMAP4Protocol::specialCustomCommand: returns " << lst << endl;
1649 infoMessage( lst.join(
" " ) );
1661 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1662 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1672 TQMap<TQString, TQString> attributes;
1673 stream >> entry >> attributes;
1674 kdDebug(7116) <<
"SETANNOTATION " << aBox <<
" " << entry <<
" " << attributes.count() <<
" attributes" << endl;
1676 if (cmd->
result () !=
"OK")
1678 error(ERR_SLAVE_DEFINED, i18n(
"Setting the annotation %1 on folder %2 "
1679 " failed. The server returned: %3")
1681 .arg(_url.prettyURL())
1685 completeQueue.removeRef (cmd);
1696 TQStringList attributeNames;
1697 stream >> entry >> attributeNames;
1698 kdDebug(7116) <<
"GETANNOTATION " << aBox <<
" " << entry <<
" " << attributeNames << endl;
1700 if (cmd->
result () !=
"OK")
1702 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the annotation %1 on folder %2 "
1703 "failed. The server returned: %3")
1705 .arg(_url.prettyURL())
1712 kdDebug(7116) << getResults() << endl;
1713 infoMessage(getResults().join(
"\r" ));
1718 kdWarning(7116) <<
"Unknown special annotate command:" << command << endl;
1719 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1724 IMAP4Protocol::specialQuotaCommand(
int command, TQDataStream& stream )
1729 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1730 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
1735 kdDebug(7116) <<
"QUOTAROOT " << aBox << endl;
1737 if (cmd->
result () !=
"OK")
1739 error(ERR_SLAVE_DEFINED, i18n(
"Retrieving the quota root information on folder %1 "
1740 "failed. The server returned: %2")
1741 .arg(_url.prettyURL())
1745 infoMessage(getResults().join(
"\r" ));
1751 kdDebug(7116) <<
"GETQUOTA command" << endl;
1752 kdWarning(7116) <<
"UNIMPLEMENTED" << endl;
1757 kdDebug(7116) <<
"SETQUOTA command" << endl;
1758 kdWarning(7116) <<
"UNIMPLEMENTED" << endl;
1762 kdWarning(7116) <<
"Unknown special quota command:" << command << endl;
1763 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
1768 IMAP4Protocol::rename (
const KURL & src,
const KURL & dest,
bool overwrite)
1770 kdDebug(7116) <<
"IMAP4::rename - [" << (overwrite ?
"Overwrite" :
"NoOverwrite") <<
"] " << src.prettyURL() <<
" -> " << dest.prettyURL() << endl;
1771 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
1772 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
1773 enum IMAP_TYPE sType =
1774 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo,
false);
1775 enum IMAP_TYPE dType =
1776 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo,
false);
1778 if (dType == ITYPE_UNKNOWN)
1784 case ITYPE_DIR_AND_BOX:
1786 if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
1788 kdDebug(7116) <<
"IMAP4::rename - close " << getCurrentBox() << endl;
1791 bool ok = cmd->
result() ==
"OK";
1792 completeQueue.removeRef(cmd);
1795 kdWarning(7116) <<
"Unable to close mailbox!" << endl;
1796 error(ERR_CANNOT_RENAME, src.path());
1799 setState(ISTATE_LOGIN);
1802 if (cmd->
result () !=
"OK") {
1803 error (ERR_CANNOT_RENAME, src.path());
1804 completeQueue.removeRef (cmd);
1807 completeQueue.removeRef (cmd);
1814 error (ERR_CANNOT_RENAME, src.path());
1820 error (ERR_CANNOT_RENAME, src.path());
1827 IMAP4Protocol::slave_status ()
1829 bool connected = (getState() != ISTATE_NO) && isConnectionValid();
1830 kdDebug(7116) <<
"IMAP4::slave_status " << connected << endl;
1831 slaveStatus ( connected ? myHost : TQString(), connected );
1835 IMAP4Protocol::dispatch (
int command,
const TQByteArray & data)
1837 kdDebug(7116) <<
"IMAP4::dispatch - command=" << command << endl;
1838 TDEIO::TCPSlaveBase::dispatch (command, data);
1844 kdDebug(7116) <<
"IMAP4::stat - " << _url.prettyURL() << endl;
1845 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
1847 enum IMAP_TYPE aType =
1848 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
1854 atom.m_uds = UDS_NAME;
1856 entry.append (atom);
1858 if (!aSection.isEmpty())
1860 if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
1863 bool ok = cmd->
result() ==
"OK";
1864 completeQueue.removeRef(cmd);
1867 error(ERR_COULD_NOT_STAT, aBox);
1870 setState(ISTATE_LOGIN);
1874 if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1879 ok = cmd->
result() ==
"OK";
1881 completeQueue.removeRef(cmd);
1887 if (cmd->
result () ==
"OK")
1889 for (TQValueListIterator < imapList > it = listResponses.begin ();
1890 it != listResponses.end (); ++it)
1892 if (aBox == (*it).name ()) found =
true;
1895 completeQueue.removeRef (cmd);
1897 error(ERR_COULD_NOT_STAT, aBox);
1899 error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
1902 if ((aSection ==
"UIDNEXT" && geStatus().uidNextAvailable())
1903 || (aSection ==
"UNSEEN" && geStatus().unseenAvailable()))
1905 atom.m_uds = UDS_SIZE;
1906 atom.m_str = TQString();
1907 atom.m_long = (aSection ==
"UIDNEXT") ? geStatus().uidNext()
1908 : geStatus().unseen();
1912 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
1913 aType == ITYPE_ATTACH)
1917 if (aBox == getCurrentBox ())
1918 validity = selectInfo.uidValidity ();
1926 completeQueue.removeRef (cmd);
1927 validity = geStatus ().uidValidity ();
1931 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
1934 if (validity > 0 && validity != aValidity.toULong ())
1939 newUrl.setPath (
"/" + aBox +
";UIDVALIDITY=" +
1940 TQString::number(validity));
1941 kdDebug(7116) <<
"IMAP4::stat - redirecting to " << newUrl.prettyURL() << endl;
1942 redirection (newUrl);
1945 else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
1952 if (validity > 0 && validity != aValidity.toULong ())
1954 aType = ITYPE_UNKNOWN;
1955 kdDebug(7116) <<
"IMAP4::stat - url has invalid validity [" << validity <<
"d] " << _url.prettyURL() << endl;
1960 atom.m_uds = UDS_MIME_TYPE;
1961 atom.m_str = getMimeType (aType);
1962 entry.append (atom);
1964 kdDebug(7116) <<
"IMAP4: stat: " << atom.m_str << endl;
1968 atom.m_uds = UDS_FILE_TYPE;
1969 atom.m_str = TQString();
1970 atom.m_long = S_IFDIR;
1971 entry.append (atom);
1975 case ITYPE_DIR_AND_BOX:
1976 atom.m_uds = UDS_FILE_TYPE;
1977 atom.m_str = TQString();
1978 atom.m_long = S_IFDIR;
1979 entry.append (atom);
1984 atom.m_uds = UDS_FILE_TYPE;
1985 atom.m_str = TQString();
1986 atom.m_long = S_IFREG;
1987 entry.append (atom);
1991 error (ERR_DOES_NOT_EXIST, _url.prettyURL());
1996 kdDebug(7116) <<
"IMAP4::stat - Finishing stat" << endl;
2000 void IMAP4Protocol::openConnection()
2002 if (makeLogin()) connected();
2005 void IMAP4Protocol::closeConnection()
2007 if (getState() == ISTATE_NO)
return;
2008 if (getState() == ISTATE_SELECT && metaData(
"expunge") ==
"auto")
2011 completeQueue.removeRef (cmd);
2013 if (getState() != ISTATE_CONNECT)
2016 completeQueue.removeRef (cmd);
2019 setState(ISTATE_NO);
2020 completeQueue.clear();
2023 currentBox = TQString();
2027 bool IMAP4Protocol::makeLogin ()
2029 if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
2032 kdDebug(7116) <<
"IMAP4::makeLogin - checking login" << endl;
2033 bool alreadyConnected = getState() == ISTATE_CONNECT;
2034 kdDebug(7116) <<
"IMAP4::makeLogin - alreadyConnected " << alreadyConnected << endl;
2035 if (alreadyConnected || connectToHost (myHost.latin1(), myPort))
2039 setState(ISTATE_CONNECT);
2041 myAuth = metaData(
"auth");
2042 myTLS = metaData(
"tls");
2043 kdDebug(7116) <<
"myAuth: " << myAuth << endl;
2048 if (!alreadyConnected)
while (!parseLoop ()) ;
2050 if (!unhandled.isEmpty()) greeting = unhandled.first().stripWhiteSpace();
2052 cmd = doCommand (
new imapCommand (
"CAPABILITY",
""));
2054 kdDebug(7116) <<
"IMAP4: setHost: capability" << endl;
2055 for (TQStringList::Iterator it = imapCapabilities.begin ();
2056 it != imapCapabilities.end (); ++it)
2058 kdDebug(7116) <<
"'" << (*it) <<
"'" << endl;
2060 completeQueue.removeRef (cmd);
2062 if (!hasCapability(
"IMAP4") && !hasCapability(
"IMAP4rev1"))
2064 error(ERR_COULD_NOT_LOGIN, i18n(
"The server %1 supports neither "
2065 "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2")
2066 .arg(myHost).arg(greeting));
2071 if (metaData(
"nologin") ==
"on")
return TRUE;
2073 if (myTLS ==
"on" && !hasCapability(TQString(
"STARTTLS")))
2075 error(ERR_COULD_NOT_LOGIN, i18n(
"The server does not support TLS.\n"
2076 "Disable this security feature to connect unencrypted."));
2080 if ((myTLS ==
"on" || (canUseTLS() && myTLS !=
"off")) &&
2081 hasCapability(TQString(
"STARTTLS")))
2084 if (cmd->
result () ==
"OK")
2086 completeQueue.removeRef(cmd);
2087 int tlsrc = startTLS();
2090 kdDebug(7116) <<
"TLS mode has been enabled." << endl;
2092 for (TQStringList::Iterator it = imapCapabilities.begin ();
2093 it != imapCapabilities.end (); ++it)
2095 kdDebug(7116) <<
"'" << (*it) <<
"'" << endl;
2097 completeQueue.removeRef (cmd2);
2099 kdWarning(7116) <<
"TLS mode setup has failed. Aborting." << endl;
2100 error (ERR_COULD_NOT_LOGIN, i18n(
"Starting TLS failed."));
2104 }
else completeQueue.removeRef(cmd);
2107 if (myAuth.isEmpty () || myAuth ==
"*") {
2108 if (hasCapability (TQString (
"LOGINDISABLED"))) {
2109 error (ERR_COULD_NOT_LOGIN, i18n(
"LOGIN is disabled by the server."));
2115 if (!hasCapability (TQString (
"AUTH=") + myAuth)) {
2116 error (ERR_COULD_NOT_LOGIN, i18n(
"The authentication method %1 is not "
2117 "supported by the server.").arg(myAuth));
2123 if ( greeting.contains( TQRegExp(
"Cyrus IMAP4 v2.1" ) ) ) {
2124 removeCapability(
"ANNOTATEMORE" );
2128 TQRegExp regExp(
"Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)",
false );
2129 if ( regExp.search( greeting ) >= 0 ) {
2130 const int major = regExp.cap( 1 ).toInt();
2131 const int minor = regExp.cap( 2 ).toInt();
2132 const int patch = regExp.cap( 3 ).toInt();
2133 if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
2134 kdDebug(7116) << k_funcinfo <<
"Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support" << endl;
2135 imapCapabilities.append(
"x-kmail-sharedseen" );
2139 kdDebug(7116) <<
"IMAP4::makeLogin - attempting login" << endl;
2141 TDEIO::AuthInfo authInfo;
2142 authInfo.username = myUser;
2143 authInfo.password = myPass;
2144 authInfo.prompt = i18n (
"Username and password for your IMAP account:");
2146 kdDebug(7116) <<
"IMAP4::makeLogin - open_PassDlg said user=" << myUser <<
" pass=xx" << endl;
2148 TQString resultInfo;
2149 if (myAuth.isEmpty () || myAuth ==
"*")
2151 if (myUser.isEmpty () || myPass.isEmpty ()) {
2152 if(openPassDlg (authInfo)) {
2153 myUser = authInfo.username;
2154 myPass = authInfo.password;
2157 if (!clientLogin (myUser, myPass, resultInfo))
2158 error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n(
"Unable to login. Probably the "
2159 "password is wrong.\nThe server %1 replied:\n%2").arg(myHost).arg(resultInfo));
2163 #ifdef HAVE_LIBSASL2
2164 if (!clientAuthenticate (
this, authInfo, myHost, myAuth, mySSL, resultInfo))
2165 error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n(
"Unable to authenticate via %1.\n"
2166 "The server %2 replied:\n%3").arg(myAuth).arg(myHost).arg(resultInfo));
2168 myUser = authInfo.username;
2169 myPass = authInfo.password;
2172 error(TDEIO::ERR_COULD_NOT_LOGIN, i18n(
"SASL authentication is not compiled into tdeio_imap4."));
2175 if ( hasCapability(
"NAMESPACE") )
2179 if (cmd->
result () ==
"OK")
2181 kdDebug(7116) <<
"makeLogin - registered namespaces" << endl;
2183 completeQueue.removeRef (cmd);
2187 if (cmd->
result () ==
"OK")
2189 TQValueListIterator < imapList > it = listResponses.begin();
2190 if ( it == listResponses.end() )
2194 completeQueue.removeRef (cmd);
2196 if (cmd->
result () ==
"OK")
2198 it = listResponses.begin();
2201 if ( it != listResponses.end() )
2203 namespaceToDelimiter[TQString()] = (*it).hierarchyDelimiter();
2204 kdDebug(7116) <<
"makeLogin - delimiter for empty ns='" <<
2205 (*it).hierarchyDelimiter() <<
"'" << endl;
2206 if ( !hasCapability(
"NAMESPACE") )
2209 TQString nsentry = TQString::number( 0 ) +
"=="
2210 + (*it).hierarchyDelimiter();
2211 imapNamespaces.append( nsentry );
2215 completeQueue.removeRef (cmd);
2217 kdDebug(7116) <<
"makeLogin - NO login" << endl;
2220 return getState() == ISTATE_LOGIN;
2227 TQCString writer = aStr.utf8();
2228 int len = writer.length();
2231 if (len == 0 || (writer[len - 1] !=
'\n')) {
2237 write(writer.data(), len);
2241 IMAP4Protocol::getMimeType (
enum IMAP_TYPE aType)
2246 return "inode/directory";
2250 return "message/digest";
2253 case ITYPE_DIR_AND_BOX:
2254 return "message/directory";
2258 return "message/rfc822";
2263 return "application/octet-stream";
2268 return "unknown/unknown";
2275 IMAP4Protocol::doListEntry (
const KURL & _url,
int stretch, imapCache * cache,
2276 bool withFlags,
bool withSubject)
2279 aURL.setQuery (TQString());
2280 const TQString encodedUrl = aURL.url(0, 106);
2281 doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
2287 IMAP4Protocol::doListEntry (
const TQString & encodedUrl,
int stretch, imapCache * cache,
2288 bool withFlags,
bool withSubject)
2297 const TQString uid = TQString::number(cache->getUid());
2299 atom.m_uds = UDS_NAME;
2304 atom.m_str =
"0000000000000000" + atom.m_str;
2305 atom.m_str = atom.m_str.right (stretch);
2313 entry.append (atom);
2315 atom.m_uds = UDS_URL;
2316 atom.m_str = encodedUrl;
2317 if (atom.m_str[atom.m_str.length () - 1] !=
'/')
2319 atom.m_str +=
";UID=" + uid;
2321 entry.append (atom);
2323 atom.m_uds = UDS_FILE_TYPE;
2324 atom.m_str = TQString();
2325 atom.m_long = S_IFREG;
2326 entry.append (atom);
2328 atom.m_uds = UDS_SIZE;
2329 atom.m_long = cache->getSize();
2330 entry.append (atom);
2332 atom.m_uds = UDS_MIME_TYPE;
2333 atom.m_str =
"message/rfc822";
2335 entry.append (atom);
2337 atom.m_uds = UDS_USER;
2338 atom.m_str = myUser;
2339 entry.append (atom);
2341 atom.m_uds = TDEIO::UDS_ACCESS;
2342 atom.m_long = (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR;
2343 entry.append (atom);
2345 listEntry (entry,
false);
2350 IMAP4Protocol::doListEntry (
const KURL & _url,
const TQString & myBox,
2351 const imapList & item,
bool appendPath)
2354 aURL.setQuery (TQString());
2357 int hdLen = item.hierarchyDelimiter().length();
2361 TQString mailboxName = item.name ();
2364 if (mailboxName.find (myBox) == 0 && mailboxName.length() > myBox.length())
2367 mailboxName.right (mailboxName.length () - myBox.length ());
2369 if (mailboxName[0] ==
'/')
2370 mailboxName = mailboxName.right (mailboxName.length () - 1);
2371 if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
2372 mailboxName = mailboxName.right(mailboxName.length () - hdLen);
2373 if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
2374 mailboxName.truncate(mailboxName.length () - hdLen);
2376 atom.m_uds = UDS_NAME;
2377 if (!item.hierarchyDelimiter().isEmpty() &&
2378 mailboxName.find(item.hierarchyDelimiter()) != -1)
2379 atom.m_str = mailboxName.section(item.hierarchyDelimiter(), -1);
2381 atom.m_str = mailboxName;
2384 if (atom.m_str.isEmpty ())
2387 if (!atom.m_str.isEmpty ())
2390 entry.append (atom);
2392 if (!item.noSelect ())
2394 atom.m_uds = UDS_MIME_TYPE;
2395 if (!item.noInferiors ())
2397 atom.m_str =
"message/directory";
2399 atom.m_str =
"message/digest";
2402 entry.append (atom);
2406 atom.m_uds = UDS_FILE_TYPE;
2407 atom.m_str = TQString();
2408 atom.m_long = S_IFDIR;
2409 entry.append (atom);
2411 else if (!item.noInferiors ())
2413 atom.m_uds = UDS_MIME_TYPE;
2414 atom.m_str =
"inode/directory";
2416 entry.append (atom);
2420 atom.m_uds = UDS_FILE_TYPE;
2421 atom.m_str = TQString();
2422 atom.m_long = S_IFDIR;
2423 entry.append (atom);
2427 atom.m_uds = UDS_MIME_TYPE;
2428 atom.m_str =
"unknown/unknown";
2430 entry.append (atom);
2433 atom.m_uds = UDS_URL;
2434 TQString path = aURL.path();
2435 atom.m_str = aURL.url (0, 106);
2438 if (path[path.length() - 1] ==
'/' && !path.isEmpty() && path !=
"/")
2439 path.truncate(path.length() - 1);
2440 if (!path.isEmpty() && path !=
"/"
2441 && path.right(hdLen) != item.hierarchyDelimiter()) {
2442 path += item.hierarchyDelimiter();
2444 path += mailboxName;
2445 if (path.upper() ==
"/INBOX/") {
2447 path = path.upper();
2451 atom.m_str = aURL.url(0, 106);
2453 entry.append (atom);
2455 atom.m_uds = UDS_USER;
2456 atom.m_str = myUser;
2457 entry.append (atom);
2459 atom.m_uds = UDS_ACCESS;
2460 atom.m_long = S_IRUSR | S_IXUSR | S_IWUSR;
2461 entry.append (atom);
2463 atom.m_uds = UDS_EXTRA;
2464 atom.m_str = item.attributesAsString();
2466 entry.append (atom);
2468 listEntry (entry,
false);
2475 TQString & _section, TQString & _type, TQString & _uid,
2476 TQString & _validity, TQString & _hierarchyDelimiter,
2477 TQString & _info,
bool cache)
2479 enum IMAP_TYPE retVal;
2480 retVal = ITYPE_UNKNOWN;
2482 imapParser::parseURL (_url, _box, _section, _type, _uid, _validity, _info);
2486 TQString myNamespace = namespaceForBox( _box );
2487 kdDebug(7116) <<
"IMAP4::parseURL - namespace=" << myNamespace << endl;
2488 if ( namespaceToDelimiter.contains(myNamespace) )
2490 _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
2491 kdDebug(7116) <<
"IMAP4::parseURL - delimiter=" << _hierarchyDelimiter << endl;
2494 if (!_box.isEmpty ())
2496 kdDebug(7116) <<
"IMAP4::parseURL - box=" << _box << endl;
2500 if (getCurrentBox () != _box ||
2501 _type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK")
2506 retVal = ITYPE_DIR_AND_BOX;
2513 if (cmd->
result () ==
"OK")
2515 for (TQValueListIterator < imapList > it = listResponses.begin ();
2516 it != listResponses.end (); ++it)
2519 if (_box == (*it).name ())
2521 if ( !(*it).hierarchyDelimiter().isEmpty() )
2522 _hierarchyDelimiter = (*it).hierarchyDelimiter();
2523 if ((*it).noSelect ())
2527 else if ((*it).noInferiors ())
2533 retVal = ITYPE_DIR_AND_BOX;
2538 if ( retVal == ITYPE_UNKNOWN &&
2539 namespaceToDelimiter.contains(_box) ) {
2543 kdDebug(7116) <<
"IMAP4::parseURL - got error for " << _box << endl;
2545 completeQueue.removeRef (cmd);
2554 kdDebug(7116) <<
"IMAP4::parseURL: no login!" << endl;
2560 kdDebug(7116) <<
"IMAP4: parseURL: box [root]" << endl;
2565 if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
2567 if (!_uid.isEmpty ())
2569 if (_uid.find (
':') == -1 && _uid.find (
',') == -1
2570 && _uid.find (
'*') == -1)
2574 if (retVal == ITYPE_MSG)
2576 if ( (_section.find (
"BODY.PEEK[", 0,
false) != -1 ||
2577 _section.find (
"BODY[", 0,
false) != -1) &&
2578 _section.find(
".MIME") == -1 &&
2579 _section.find(
".HEADER") == -1 )
2580 retVal = ITYPE_ATTACH;
2582 if ( _hierarchyDelimiter.isEmpty() &&
2583 (_type ==
"LIST" || _type ==
"LSUB" || _type ==
"LSUBNOCHECK") )
2587 if (!_box.isEmpty())
2589 int start = _url.path().findRev(_box);
2591 _hierarchyDelimiter = _url.path().mid(start-1, start);
2592 kdDebug(7116) <<
"IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
2593 <<
" from URL " << _url.path() << endl;
2595 if (_hierarchyDelimiter.isEmpty())
2596 _hierarchyDelimiter =
"/";
2598 kdDebug(7116) <<
"IMAP4::parseURL - return " << retVal << endl;
2607 len = _str.length();
2612 if ( !outputBuffer.isOpen() ) {
2613 outputBuffer.open(IO_WriteOnly);
2615 outputBuffer.at(outputBufferIndex);
2616 outputBuffer.writeBlock(_str.data(), len);
2617 outputBufferIndex += len;
2622 bool relay = relayEnabled;
2624 relayEnabled =
true;
2625 temp.setRawData (_str.data (), len);
2627 temp.resetRawData (_str.data (), len);
2629 relayEnabled = relay;
2636 if (outputBufferIndex == 0)
2638 outputBuffer.close();
2639 outputCache.resize(outputBufferIndex);
2643 TQByteArray decoded;
2644 if (contentEncoding.find(
"quoted-printable", 0,
false) == 0)
2645 decoded = KCodecs::quotedPrintableDecode(outputCache);
2646 else if (contentEncoding.find(
"base64", 0,
false) == 0)
2647 KCodecs::base64Decode(outputCache, decoded);
2649 decoded = outputCache;
2651 TQString mimetype = KMimeType::findByContent( decoded )->name();
2652 kdDebug(7116) <<
"IMAP4::flushOutput - mimeType " << mimetype << endl;
2654 decodeContent =
false;
2657 data( outputCache );
2659 mProcessedSize += outputBufferIndex;
2660 processedSize( mProcessedSize );
2661 outputBufferIndex = 0;
2662 outputCache[0] =
'\0';
2663 outputBuffer.setBuffer(outputCache);
2666 ssize_t IMAP4Protocol::myRead(
void *data, ssize_t len)
2670 ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
2671 memcpy(data, readBuffer, copyLen);
2672 readBufferLen -= copyLen;
2673 if (readBufferLen) memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
2676 if (!isConnectionValid())
return 0;
2677 waitForResponse( responseTimeout() );
2678 return read(data, len);
2682 IMAP4Protocol::assureBox (
const TQString & aBox,
bool readonly)
2684 if (aBox.isEmpty())
return false;
2688 if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
2691 kdDebug(7116) <<
"IMAP4Protocol::assureBox - opening box" << endl;
2692 selectInfo = imapInfo();
2694 bool ok = cmd->
result() ==
"OK";
2696 completeQueue.removeRef (cmd);
2702 if (cmd->
result () ==
"OK")
2704 for (TQValueListIterator < imapList > it = listResponses.begin ();
2705 it != listResponses.end (); ++it)
2707 if (aBox == (*it).name ()) found =
true;
2710 completeQueue.removeRef (cmd);
2712 if (cmdInfo.find(
"permission", 0,
false) != -1) {
2714 error(ERR_ACCESS_DENIED, cmdInfo);
2716 error(ERR_SLAVE_DEFINED, i18n(
"Unable to open folder %1. The server replied: %2").arg(aBox).arg(cmdInfo));
2719 error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
2729 kdDebug(7116) <<
"IMAP4Protocol::assureBox - reusing box" << endl;
2730 if ( mTimeOfLastNoop.secsTo( TQDateTime::currentDateTime() ) > 10 ) {
2732 completeQueue.removeRef (cmd);
2733 mTimeOfLastNoop = TQDateTime::currentDateTime();
2734 kdDebug(7116) <<
"IMAP4Protocol::assureBox - noop timer fired" << endl;
2739 if (!getSelected().readWrite() && !readonly)
2741 error(TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);
virtual void del(const KURL &_url, bool isFile)
delete a mailbox
virtual void parseRelay(const TQByteArray &buffer)
reimplement the parser relay hook to send the fetched data directly to an upper level
virtual void special(const TQByteArray &data)
Capabilites, NOOP, (Un)subscribe, Change status, Change ACL.
virtual void listDir(const KURL &_url)
list a directory/mailbox
void specialSearchCommand(TQDataStream &)
Search current folder, the search string is passed as SECTION.
void specialCustomCommand(TQDataStream &)
Send a custom command to the server.
virtual void mkdir(const KURL &url, int permissions)
create a mailbox
void specialAnnotateMoreCommand(int command, TQDataStream &stream)
Send an annotation command which is identified by command.
virtual void stat(const KURL &_url)
stat a mailbox, message, attachment
virtual bool parseReadLine(TQByteArray &buffer, ulong relay=0)
reimplement the parser
virtual void parseWriteLine(const TQString &)
reimplement the parser
virtual void get(const KURL &_url)
get a message or part of a message the data is normally sent as we get it from the server if you want...
virtual int outputLine(const TQCString &_str, int len=-1)
reimplement the mimeIO
void specialACLCommand(int command, TQDataStream &stream)
Send an ACL command which is identified by command.
enum IMAP_TYPE parseURL(const KURL &_url, TQString &_box, TQString &_section, TQString &_type, TQString &_uid, TQString &_validity, TQString &_hierarchyDelimiter, TQString &_info, bool cache=false)
Parses the given URL The return values are set by parsing the URL and querying the server.
virtual void flushOutput(TQString contentEncoding=TQString())
send out cached data to the application
virtual bool parseRead(TQByteArray &buffer, ulong len, ulong relay=0)
reimplement the parser read at least len bytes
encapulate a IMAP command
static imapCommand * clientSubscribe(const TQString &path)
Create a SUBSCRIBE command.
static imapCommand * clienStatus(const TQString &path, const TQString ¶meters)
Create a STATUS command.
static imapCommand * clientCreate(const TQString &path)
Create a CREATE command.
static imapCommand * clientNoop()
Create a NOOP command.
static imapCommand * clientRename(const TQString &src, const TQString &dest)
Create a RENAME command.
static imapCommand * clientGetQuotaroot(const TQString &box)
Create a GETQUOTAROOT command.
static imapCommand * clientMyRights(const TQString &box)
Create a MYRIGHTS command.
static imapCommand * clientList(const TQString &reference, const TQString &path, bool lsub=false)
Create a LIST command.
static imapCommand * clientSetAnnotation(const TQString &box, const TQString &entry, const TQMap< TQString, TQString > &attributes)
Create a SETANNOTATION command.
static imapCommand * clientSetACL(const TQString &box, const TQString &user, const TQString &acl)
Create a SETACL command.
static imapCommand * clientGetACL(const TQString &box)
Create a GETACL command.
static imapCommand * clientDelete(const TQString &path)
Create a DELETE command.
bool isComplete()
is it complete?
static imapCommand * clientFetch(ulong uid, const TQString &fields, bool nouid=false)
Create a FETCH command.
static imapCommand * clientDeleteACL(const TQString &box, const TQString &user)
Create a DELETEACL command.
static imapCommand * clientUnsubscribe(const TQString &path)
Create a UNSUBSCRIBE command.
static imapCommand * clientNamespace()
Create a NAMESPACE command.
static imapCommand * clientSearch(const TQString &search, bool nouid=false)
Create a SEARCH command.
static imapCommand * clientExpunge()
Create a EXPUNGE command.
const TQString & resultInfo()
get information about the result
static imapCommand * clientStartTLS()
Create a STARTTLS command.
static imapCommand * clientClose()
Create a CLOSE command.
static imapCommand * clientLogout()
Create a LOGOUT command.
static imapCommand * clientCopy(const TQString &box, const TQString &sequence, bool nouid=false)
Create a COPY command.
static imapCommand * clientSelect(const TQString &path, bool examine=false)
Create a SELECT command.
const TQString & result()
get the result of the command
static imapCommand * clientCustom(const TQString &command, const TQString &arguments)
Create a custom command.
static imapCommand * clientGetAnnotation(const TQString &box, const TQString &entry, const TQStringList &attributeNames)
Create a GETANNOTATION command.
static imapCommand * clientStore(const TQString &set, const TQString &item, const TQString &data, bool nouid=false)
Create a STORE command.
static imapCommand * clientAppend(const TQString &box, const TQString &flags, ulong size)
Create a APPEND command.