00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00059 #ifdef HAVE_CONFIG_H
00060 #include <config.h>
00061 #endif
00062
00063 #include "imap4.h"
00064
00065 #include "rfcdecoder.h"
00066
00067 #include <sys/stat.h>
00068
00069 #include <stdio.h>
00070 #include <stdlib.h>
00071 #include <signal.h>
00072 #include <sys/types.h>
00073 #include <sys/wait.h>
00074 #include <errno.h>
00075
00076 #ifdef HAVE_LIBSASL2
00077 extern "C" {
00078 #include <sasl/sasl.h>
00079 }
00080 #endif
00081
00082 #include <tqbuffer.h>
00083 #include <tqdatetime.h>
00084 #include <tqregexp.h>
00085 #include <tdeprotocolmanager.h>
00086 #include <tdemessagebox.h>
00087 #include <kdebug.h>
00088 #include <tdeio/connection.h>
00089 #include <tdeio/slaveinterface.h>
00090 #include <tdeio/passdlg.h>
00091 #include <tdelocale.h>
00092 #include <kmimetype.h>
00093 #include <kmdcodec.h>
00094
00095 #include "tdepimmacros.h"
00096
00097 #define IMAP_PROTOCOL "imap"
00098 #define IMAP_SSL_PROTOCOL "imaps"
00099 const int ImapPort = 143;
00100 const int ImapsPort = 993;
00101
00102 using namespace TDEIO;
00103
00104 extern "C"
00105 {
00106 void sigalrm_handler (int);
00107 KDE_EXPORT int kdemain (int argc, char **argv);
00108 }
00109
00110 int
00111 kdemain (int argc, char **argv)
00112 {
00113 kdDebug(7116) << "IMAP4::kdemain" << endl;
00114
00115 TDEInstance instance ("tdeio_imap4");
00116 if (argc != 4)
00117 {
00118 fprintf(stderr, "Usage: tdeio_imap4 protocol domain-socket1 domain-socket2\n");
00119 ::exit (-1);
00120 }
00121
00122 #ifdef HAVE_LIBSASL2
00123 if ( sasl_client_init( NULL ) != SASL_OK ) {
00124 fprintf(stderr, "SASL library initialization failed!\n");
00125 ::exit (-1);
00126 }
00127 #endif
00128
00129
00130
00131 IMAP4Protocol *slave;
00132 if (strcasecmp (argv[1], IMAP_SSL_PROTOCOL) == 0)
00133 slave = new IMAP4Protocol (argv[2], argv[3], true);
00134 else if (strcasecmp (argv[1], IMAP_PROTOCOL) == 0)
00135 slave = new IMAP4Protocol (argv[2], argv[3], false);
00136 else
00137 abort ();
00138 slave->dispatchLoop ();
00139 delete slave;
00140
00141 #ifdef HAVE_LIBSASL2
00142 sasl_done();
00143 #endif
00144
00145 return 0;
00146 }
00147
00148 void
00149 sigchld_handler (int signo)
00150 {
00151
00152
00153
00154 const int save_errno = errno;
00155 int pid, status;
00156
00157 while (signo == SIGCHLD)
00158 {
00159 pid = waitpid (-1, &status, WNOHANG);
00160 if (pid <= 0)
00161 {
00162
00163
00164
00165 signal (SIGCHLD, sigchld_handler);
00166 break;
00167 }
00168 }
00169
00170 errno = save_errno;
00171 }
00172
00173 IMAP4Protocol::IMAP4Protocol (const TQCString & pool, const TQCString & app, bool isSSL):TCPSlaveBase ((isSSL ? 993 : 143),
00174 (isSSL ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL), pool,
00175 app, isSSL), imapParser (), mimeIO (), outputBuffer(outputCache)
00176 {
00177 outputBufferIndex = 0;
00178 mySSL = isSSL;
00179 readBuffer[0] = 0x00;
00180 relayEnabled = false;
00181 readBufferLen = 0;
00182 cacheOutput = false;
00183 decodeContent = false;
00184 mTimeOfLastNoop = TQDateTime();
00185 }
00186
00187 IMAP4Protocol::~IMAP4Protocol ()
00188 {
00189 closeDescriptor();
00190 kdDebug(7116) << "IMAP4: Finishing" << endl;
00191 }
00192
00193 void
00194 IMAP4Protocol::get (const KURL & _url)
00195 {
00196 if (!makeLogin()) return;
00197 kdDebug(7116) << "IMAP4::get - " << _url.prettyURL() << endl;
00198 TQString aBox, aSequence, aType, aSection, aValidity, aDelimiter, aInfo;
00199 enum IMAP_TYPE aEnum =
00200 parseURL (_url, aBox, aSection, aType, aSequence, aValidity, aDelimiter, aInfo);
00201 if (aEnum != ITYPE_ATTACH)
00202 mimeType (getMimeType(aEnum));
00203 if (aInfo == "DECODE")
00204 decodeContent = true;
00205
00206 if (aSequence == "0:0" && getState() == ISTATE_SELECT)
00207 {
00208 imapCommand *cmd = doCommand (imapCommand::clientNoop());
00209 completeQueue.removeRef(cmd);
00210 }
00211
00212 if (aSequence.isEmpty ())
00213 {
00214 aSequence = "1:*";
00215 }
00216
00217 mProcessedSize = 0;
00218 imapCommand *cmd = NULL;
00219 if (!assureBox (aBox, true)) return;
00220
00221 #ifdef USE_VALIDITY
00222 if (selectInfo.uidValidityAvailable () && !aValidity.isEmpty ()
00223 && selectInfo.uidValidity () != aValidity.toULong ())
00224 {
00225
00226 error (ERR_COULD_NOT_READ, _url.prettyURL());
00227 return;
00228 }
00229 else
00230 #endif
00231 {
00232
00233
00234
00235
00236
00237
00238
00239 TQString aUpper = aSection.upper();
00240 if (aUpper.find ("STRUCTURE") != -1)
00241 {
00242 aSection = "BODYSTRUCTURE";
00243 }
00244 else if (aUpper.find ("ENVELOPE") != -1)
00245 {
00246 aSection = "UID RFC822.SIZE FLAGS ENVELOPE";
00247 if (hasCapability("IMAP4rev1")) {
00248 aSection += " BODY.PEEK[HEADER.FIELDS (REFERENCES)]";
00249 } else {
00250
00251 aSection += " RFC822.HEADER.LINES (REFERENCES)";
00252 }
00253 }
00254 else if (aUpper == "HEADER")
00255 {
00256 aSection = "UID RFC822.HEADER RFC822.SIZE FLAGS";
00257 }
00258 else if (aUpper.find ("BODY.PEEK[") != -1)
00259 {
00260 if (aUpper.find ("BODY.PEEK[]") != -1)
00261 {
00262 if (!hasCapability("IMAP4rev1"))
00263 aSection.replace("BODY.PEEK[]", "RFC822.PEEK");
00264 }
00265 aSection.prepend("UID RFC822.SIZE FLAGS ");
00266 }
00267 else if (aSection.isEmpty())
00268 {
00269 aSection = "UID BODY[] RFC822.SIZE FLAGS";
00270 }
00271 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00272 {
00273
00274 cacheOutput = true;
00275 outputLine
00276 ("Content-Type: multipart/digest; boundary=\"IMAPDIGEST\"\r\n", 55);
00277 if (selectInfo.recentAvailable ())
00278 outputLineStr ("X-Recent: " +
00279 TQString::number(selectInfo.recent ()) + "\r\n");
00280 if (selectInfo.countAvailable ())
00281 outputLineStr ("X-Count: " + TQString::number(selectInfo.count ()) +
00282 "\r\n");
00283 if (selectInfo.unseenAvailable ())
00284 outputLineStr ("X-Unseen: " +
00285 TQString::number(selectInfo.unseen ()) + "\r\n");
00286 if (selectInfo.uidValidityAvailable ())
00287 outputLineStr ("X-uidValidity: " +
00288 TQString::number(selectInfo.uidValidity ()) +
00289 "\r\n");
00290 if (selectInfo.uidNextAvailable ())
00291 outputLineStr ("X-UidNext: " +
00292 TQString::number(selectInfo.uidNext ()) + "\r\n");
00293 if (selectInfo.flagsAvailable ())
00294 outputLineStr ("X-Flags: " + TQString::number(selectInfo.flags ()) +
00295 "\r\n");
00296 if (selectInfo.permanentFlagsAvailable ())
00297 outputLineStr ("X-PermanentFlags: " +
00298 TQString::number(selectInfo.permanentFlags ()) + "\r\n");
00299 if (selectInfo.readWriteAvailable ()) {
00300 if (selectInfo.readWrite()) {
00301 outputLine ("X-Access: Read/Write\r\n", 22);
00302 } else {
00303 outputLine ("X-Access: Read only\r\n", 21);
00304 }
00305 }
00306 outputLine ("\r\n", 2);
00307 flushOutput(TQString());
00308 cacheOutput = false;
00309 }
00310
00311 if (aEnum == ITYPE_MSG || (aEnum == ITYPE_ATTACH && !decodeContent))
00312 relayEnabled = true;
00313
00314 if (aSequence != "0:0")
00315 {
00316 TQString contentEncoding;
00317 if (aEnum == ITYPE_ATTACH && decodeContent)
00318 {
00319
00320 TQString mySection = aSection;
00321 mySection.replace("]", ".MIME]");
00322 cmd = sendCommand (imapCommand::clientFetch (aSequence, mySection));
00323 do
00324 {
00325 while (!parseLoop ()) ;
00326 }
00327 while (!cmd->isComplete ());
00328 completeQueue.removeRef (cmd);
00329
00330 if (getLastHandled() && getLastHandled()->getHeader())
00331 contentEncoding = getLastHandled()->getHeader()->getEncoding();
00332
00333
00334
00335
00336 cacheOutput = true;
00337 }
00338
00339 cmd = sendCommand (imapCommand::clientFetch (aSequence, aSection));
00340 int res;
00341 aUpper = aSection.upper();
00342 do
00343 {
00344 while (!(res = parseLoop())) ;
00345 if (res == -1) break;
00346
00347 mailHeader *lastone = 0;
00348 imapCache *cache = getLastHandled ();
00349 if (cache)
00350 lastone = cache->getHeader ();
00351
00352 if (cmd && !cmd->isComplete ())
00353 {
00354 if ((aUpper.find ("BODYSTRUCTURE") != -1)
00355 || (aUpper.find ("FLAGS") != -1)
00356 || (aUpper.find ("UID") != -1)
00357 || (aUpper.find ("ENVELOPE") != -1)
00358 || (aUpper.find ("BODY.PEEK[0]") != -1
00359 && (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)))
00360 {
00361 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00362 {
00363
00364 outputLine ("--IMAPDIGEST\r\n", 14);
00365 cacheOutput = true;
00366 if (cache && cache->getUid () != 0)
00367 outputLineStr ("X-UID: " +
00368 TQString::number(cache->getUid ()) + "\r\n");
00369 if (cache && cache->getSize () != 0)
00370 outputLineStr ("X-Length: " +
00371 TQString::number(cache->getSize ()) + "\r\n");
00372 if (cache && !cache->getDate ().isEmpty())
00373 outputLineStr ("X-Date: " + cache->getDate () + "\r\n");
00374 if (cache && cache->getFlags () != 0)
00375 outputLineStr ("X-Flags: " +
00376 TQString::number(cache->getFlags ()) + "\r\n");
00377 } else cacheOutput = true;
00378 if ( lastone && !decodeContent )
00379 lastone->outputPart (*this);
00380 cacheOutput = false;
00381 flushOutput(contentEncoding);
00382 }
00383 }
00384 }
00385 while (cmd && !cmd->isComplete ());
00386 if (aEnum == ITYPE_BOX || aEnum == ITYPE_DIR_AND_BOX)
00387 {
00388
00389 outputLine ("--IMAPDIGEST--\r\n", 16);
00390 }
00391
00392 completeQueue.removeRef (cmd);
00393 }
00394 }
00395
00396
00397 data (TQByteArray ());
00398
00399 finished ();
00400 relayEnabled = false;
00401 cacheOutput = false;
00402 kdDebug(7116) << "IMAP4::get - finished" << endl;
00403 }
00404
00405 void
00406 IMAP4Protocol::listDir (const KURL & _url)
00407 {
00408 kdDebug(7116) << " IMAP4::listDir - " << _url.prettyURL() << endl;
00409
00410 if (_url.path().isEmpty())
00411 {
00412 KURL url = _url;
00413 url.setPath("/");
00414 redirection( url );
00415 finished();
00416 return;
00417 }
00418
00419 TQString myBox, mySequence, myLType, mySection, myValidity, myDelimiter, myInfo;
00420
00421 enum IMAP_TYPE myType =
00422 parseURL (_url, myBox, mySection, myLType, mySequence, myValidity,
00423 myDelimiter, myInfo, true);
00424
00425 if (!makeLogin()) return;
00426
00427 if (myType == ITYPE_DIR || myType == ITYPE_DIR_AND_BOX)
00428 {
00429 TQString listStr = myBox;
00430 imapCommand *cmd;
00431
00432 if (!listStr.isEmpty () && !listStr.endsWith(myDelimiter) &&
00433 mySection != "FOLDERONLY")
00434 listStr += myDelimiter;
00435
00436 if (mySection.isEmpty())
00437 {
00438 listStr += "%";
00439 } else if (mySection == "COMPLETE") {
00440 listStr += "*";
00441 }
00442 kdDebug(7116) << "IMAP4Protocol::listDir - listStr=" << listStr << endl;
00443 cmd =
00444 doCommand (imapCommand::clientList ("", listStr,
00445 (myLType == "LSUB" || myLType == "LSUBNOCHECK")));
00446 if (cmd->result () == "OK")
00447 {
00448 TQString mailboxName;
00449 UDSEntry entry;
00450 UDSAtom atom;
00451 KURL aURL = _url;
00452 if (aURL.path().find(';') != -1)
00453 aURL.setPath(aURL.path().left(aURL.path().find(';')));
00454
00455 kdDebug(7116) << "IMAP4Protocol::listDir - got " << listResponses.count () << endl;
00456
00457 if (myLType == "LSUB")
00458 {
00459
00460 TQValueList<imapList> listResponsesSave = listResponses;
00461 doCommand (imapCommand::clientList ("", listStr, false));
00462 for (TQValueListIterator < imapList > it = listResponsesSave.begin ();
00463 it != listResponsesSave.end (); ++it)
00464 {
00465 bool boxOk = false;
00466 for (TQValueListIterator < imapList > it2 = listResponses.begin ();
00467 it2 != listResponses.end (); ++it2)
00468 {
00469 if ((*it2).name() == (*it).name())
00470 {
00471 boxOk = true;
00472
00473 (*it) = (*it2);
00474 break;
00475 }
00476 }
00477 if (boxOk)
00478 doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
00479 else
00480 kdDebug(7116) << "IMAP4Protocol::listDir - suppress " << (*it).name() << endl;
00481 }
00482 listResponses = listResponsesSave;
00483 }
00484 else
00485 {
00486 for (TQValueListIterator < imapList > it = listResponses.begin ();
00487 it != listResponses.end (); ++it)
00488 {
00489 doListEntry (aURL, myBox, (*it), (mySection != "FOLDERONLY"));
00490 }
00491 }
00492 entry.clear ();
00493 listEntry (entry, true);
00494 }
00495 else
00496 {
00497 error (ERR_CANNOT_ENTER_DIRECTORY, _url.prettyURL());
00498 completeQueue.removeRef (cmd);
00499 return;
00500 }
00501 completeQueue.removeRef (cmd);
00502 }
00503 if ((myType == ITYPE_BOX || myType == ITYPE_DIR_AND_BOX)
00504 && myLType != "LIST" && myLType != "LSUB" && myLType != "LSUBNOCHECK")
00505 {
00506 KURL aURL = _url;
00507 aURL.setQuery (TQString());
00508 const TQString encodedUrl = aURL.url(0, 106);
00509
00510 if (!_url.query ().isEmpty ())
00511 {
00512 TQString query = KURL::decode_string (_url.query ());
00513 query = query.right (query.length () - 1);
00514 if (!query.isEmpty())
00515 {
00516 imapCommand *cmd = NULL;
00517
00518 if (!assureBox (myBox, true)) return;
00519
00520 if (!selectInfo.countAvailable() || selectInfo.count())
00521 {
00522 cmd = doCommand (imapCommand::clientSearch (query));
00523 if (cmd->result() != "OK")
00524 {
00525 error(ERR_UNSUPPORTED_ACTION, _url.prettyURL());
00526 completeQueue.removeRef (cmd);
00527 return;
00528 }
00529 completeQueue.removeRef (cmd);
00530
00531 TQStringList list = getResults ();
00532 int stretch = 0;
00533
00534 if (selectInfo.uidNextAvailable ())
00535 stretch = TQString::number(selectInfo.uidNext ()).length ();
00536 UDSEntry entry;
00537 imapCache fake;
00538
00539 for (TQStringList::ConstIterator it = list.begin(); it != list.end();
00540 ++it)
00541 {
00542 fake.setUid((*it).toULong());
00543 doListEntry (encodedUrl, stretch, &fake);
00544 }
00545 entry.clear ();
00546 listEntry (entry, true);
00547 }
00548 }
00549 }
00550 else
00551 {
00552 if (!assureBox (myBox, true)) return;
00553
00554 kdDebug(7116) << "IMAP4: select returned:" << endl;
00555 if (selectInfo.recentAvailable ())
00556 kdDebug(7116) << "Recent: " << selectInfo.recent () << "d" << endl;
00557 if (selectInfo.countAvailable ())
00558 kdDebug(7116) << "Count: " << selectInfo.count () << "d" << endl;
00559 if (selectInfo.unseenAvailable ())
00560 kdDebug(7116) << "Unseen: " << selectInfo.unseen () << "d" << endl;
00561 if (selectInfo.uidValidityAvailable ())
00562 kdDebug(7116) << "uidValidity: " << selectInfo.uidValidity () << "d" << endl;
00563 if (selectInfo.flagsAvailable ())
00564 kdDebug(7116) << "Flags: " << selectInfo.flags () << "d" << endl;
00565 if (selectInfo.permanentFlagsAvailable ())
00566 kdDebug(7116) << "PermanentFlags: " << selectInfo.permanentFlags () << "d" << endl;
00567 if (selectInfo.readWriteAvailable ())
00568 kdDebug(7116) << "Access: " << (selectInfo.readWrite ()? "Read/Write" : "Read only") << endl;
00569
00570 #ifdef USE_VALIDITY
00571 if (selectInfo.uidValidityAvailable ()
00572 && selectInfo.uidValidity () != myValidity.toULong ())
00573 {
00574
00575 KURL newUrl = _url;
00576
00577 newUrl.setPath ("/" + myBox + ";UIDVALIDITY=" +
00578 TQString::number(selectInfo.uidValidity ()));
00579 kdDebug(7116) << "IMAP4::listDir - redirecting to " << newUrl.prettyURL() << endl;
00580 redirection (newUrl);
00581
00582
00583 }
00584 else
00585 #endif
00586 if (selectInfo.count () > 0)
00587 {
00588 int stretch = 0;
00589
00590 if (selectInfo.uidNextAvailable ())
00591 stretch = TQString::number(selectInfo.uidNext ()).length ();
00592
00593 UDSEntry entry;
00594
00595 if (mySequence.isEmpty()) mySequence = "1:*";
00596
00597 bool withSubject = mySection.isEmpty();
00598 if (mySection.isEmpty()) mySection = "UID RFC822.SIZE ENVELOPE";
00599
00600 bool withFlags = mySection.upper().find("FLAGS") != -1;
00601 imapCommand *fetch =
00602 sendCommand (imapCommand::
00603 clientFetch (mySequence, mySection));
00604 imapCache *cache;
00605 do
00606 {
00607 while (!parseLoop ()) ;
00608
00609 cache = getLastHandled ();
00610
00611 if (cache && !fetch->isComplete())
00612 doListEntry (encodedUrl, stretch, cache, withFlags, withSubject);
00613 }
00614 while (!fetch->isComplete ());
00615 entry.clear ();
00616 listEntry (entry, true);
00617 }
00618 }
00619 }
00620 if ( !selectInfo.alert().isNull() ) {
00621 if ( !myBox.isEmpty() ) {
00622 warning( i18n( "Message from %1 while processing '%2': %3" ).arg( myHost, myBox, selectInfo.alert() ) );
00623 } else {
00624 warning( i18n( "Message from %1: %2" ).arg( myHost, TQString(selectInfo.alert()) ) );
00625 }
00626 selectInfo.setAlert( 0 );
00627 }
00628
00629 kdDebug(7116) << "IMAP4Protocol::listDir - Finishing listDir" << endl;
00630 finished ();
00631 }
00632
00633 void
00634 IMAP4Protocol::setHost (const TQString & _host, int _port,
00635 const TQString & _user, const TQString & _pass)
00636 {
00637 if (myHost != _host || myPort != _port || myUser != _user || myPass != _pass)
00638 {
00639
00640 if (!myHost.isEmpty ())
00641 closeConnection ();
00642 myHost = _host;
00643 if (_port == 0)
00644 myPort = (mySSL) ? ImapsPort : ImapPort;
00645 else
00646 myPort = _port;
00647 myUser = _user;
00648 myPass = _pass;
00649 }
00650 }
00651
00652 void
00653 IMAP4Protocol::parseRelay (const TQByteArray & buffer)
00654 {
00655 if (relayEnabled) {
00656
00657 data( buffer );
00658 mProcessedSize += buffer.size();
00659 processedSize( mProcessedSize );
00660 } else if (cacheOutput)
00661 {
00662
00663 if ( !outputBuffer.isOpen() ) {
00664 outputBuffer.open(IO_WriteOnly);
00665 }
00666 outputBuffer.at(outputBufferIndex);
00667 outputBuffer.writeBlock(buffer, buffer.size());
00668 outputBufferIndex += buffer.size();
00669 }
00670 }
00671
00672 void
00673 IMAP4Protocol::parseRelay (ulong len)
00674 {
00675 if (relayEnabled)
00676 totalSize (len);
00677 }
00678
00679
00680 bool IMAP4Protocol::parseRead(TQByteArray & buffer, ulong len, ulong relay)
00681 {
00682 char buf[8192];
00683 while (buffer.size() < len)
00684 {
00685 ssize_t readLen = myRead(buf, TQMIN(len - buffer.size(), sizeof(buf) - 1));
00686 if (readLen == 0)
00687 {
00688 kdDebug(7116) << "parseRead: readLen == 0 - connection broken" << endl;
00689 error (ERR_CONNECTION_BROKEN, myHost);
00690 setState(ISTATE_CONNECT);
00691 closeConnection();
00692 return FALSE;
00693 }
00694 if (relay > buffer.size())
00695 {
00696 TQByteArray relayData;
00697 ssize_t relbuf = relay - buffer.size();
00698 int currentRelay = TQMIN(relbuf, readLen);
00699 relayData.setRawData(buf, currentRelay);
00700 parseRelay(relayData);
00701 relayData.resetRawData(buf, currentRelay);
00702 }
00703 {
00704 TQBuffer stream (buffer);
00705 stream.open (IO_WriteOnly);
00706 stream.at (buffer.size ());
00707 stream.writeBlock (buf, readLen);
00708 stream.close ();
00709 }
00710 }
00711 return (buffer.size() == len);
00712 }
00713
00714
00715 bool IMAP4Protocol::parseReadLine (TQByteArray & buffer, ulong relay)
00716 {
00717 if (myHost.isEmpty()) return FALSE;
00718
00719 while (true) {
00720 ssize_t copyLen = 0;
00721 if (readBufferLen > 0)
00722 {
00723 while (copyLen < readBufferLen && readBuffer[copyLen] != '\n') copyLen++;
00724 if (copyLen < readBufferLen) copyLen++;
00725 if (relay > 0)
00726 {
00727 TQByteArray relayData;
00728
00729 if (copyLen < (ssize_t) relay)
00730 relay = copyLen;
00731 relayData.setRawData (readBuffer, relay);
00732 parseRelay (relayData);
00733 relayData.resetRawData (readBuffer, relay);
00734
00735 }
00736
00737 {
00738 TQBuffer stream (buffer);
00739
00740 stream.open (IO_WriteOnly);
00741 stream.at (buffer.size ());
00742 stream.writeBlock (readBuffer, copyLen);
00743 stream.close ();
00744
00745 }
00746
00747 readBufferLen -= copyLen;
00748 if (readBufferLen)
00749 memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
00750 if (buffer[buffer.size() - 1] == '\n') return TRUE;
00751 }
00752 if (!isConnectionValid())
00753 {
00754 kdDebug(7116) << "parseReadLine - connection broken" << endl;
00755 error (ERR_CONNECTION_BROKEN, myHost);
00756 setState(ISTATE_CONNECT);
00757 closeConnection();
00758 return FALSE;
00759 }
00760 if (!waitForResponse( responseTimeout() ))
00761 {
00762 error(ERR_SERVER_TIMEOUT, myHost);
00763 setState(ISTATE_CONNECT);
00764 closeConnection();
00765 return FALSE;
00766 }
00767 readBufferLen = read(readBuffer, IMAP_BUFFER - 1);
00768 if (readBufferLen == 0)
00769 {
00770 kdDebug(7116) << "parseReadLine: readBufferLen == 0 - connection broken" << endl;
00771 error (ERR_CONNECTION_BROKEN, myHost);
00772 setState(ISTATE_CONNECT);
00773 closeConnection();
00774 return FALSE;
00775 }
00776 }
00777 }
00778
00779 void
00780 IMAP4Protocol::setSubURL (const KURL & _url)
00781 {
00782 kdDebug(7116) << "IMAP4::setSubURL - " << _url.prettyURL() << endl;
00783 TDEIO::TCPSlaveBase::setSubURL (_url);
00784 }
00785
00786 void
00787 IMAP4Protocol::put (const KURL & _url, int, bool, bool)
00788 {
00789 kdDebug(7116) << "IMAP4::put - " << _url.prettyURL() << endl;
00790
00791 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
00792 enum IMAP_TYPE aType =
00793 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00794
00795
00796 if (aType != ITYPE_BOX && aType != ITYPE_DIR_AND_BOX)
00797 {
00798 if (aBox[aBox.length () - 1] == '/')
00799 aBox = aBox.right (aBox.length () - 1);
00800 imapCommand *cmd = doCommand (imapCommand::clientCreate (aBox));
00801
00802 if (cmd->result () != "OK") {
00803 error (ERR_COULD_NOT_WRITE, _url.prettyURL());
00804 completeQueue.removeRef (cmd);
00805 return;
00806 }
00807 completeQueue.removeRef (cmd);
00808 }
00809 else
00810 {
00811 TQPtrList < TQByteArray > bufferList;
00812 int length = 0;
00813
00814 int result;
00815
00816 do
00817 {
00818 TQByteArray *buffer = new TQByteArray ();
00819 dataReq ();
00820 result = readData (*buffer);
00821 if (result > 0)
00822 {
00823 bufferList.append (buffer);
00824 length += result;
00825 } else {
00826 delete buffer;
00827 }
00828 }
00829 while (result > 0);
00830
00831 if (result != 0)
00832 {
00833 error (ERR_ABORTED, _url.prettyURL());
00834 return;
00835 }
00836
00837 imapCommand *cmd =
00838 sendCommand (imapCommand::clientAppend (aBox, aSection, length));
00839 while (!parseLoop ()) ;
00840
00841
00842 if (!cmd->isComplete () && !getContinuation ().isEmpty ())
00843 {
00844 bool sendOk = true;
00845 ulong wrote = 0;
00846
00847 TQByteArray *buffer;
00848
00849 while (!bufferList.isEmpty () && sendOk)
00850 {
00851 buffer = bufferList.take (0);
00852
00853 sendOk =
00854 (write (buffer->data (), buffer->size ()) ==
00855 (ssize_t) buffer->size ());
00856 wrote += buffer->size ();
00857 processedSize(wrote);
00858 delete buffer;
00859 if (!sendOk)
00860 {
00861 error (ERR_CONNECTION_BROKEN, myHost);
00862 completeQueue.removeRef (cmd);
00863 setState(ISTATE_CONNECT);
00864 closeConnection();
00865 return;
00866 }
00867 }
00868 parseWriteLine ("");
00869
00870 while (!cmd->isComplete () && getState() != ISTATE_NO)
00871 parseLoop ();
00872 if ( getState() == ISTATE_NO ) {
00873
00874
00875 error( ERR_CONNECTION_BROKEN, myHost );
00876 completeQueue.removeRef (cmd);
00877 closeConnection();
00878 return;
00879 }
00880 else if (cmd->result () != "OK") {
00881 error( ERR_SLAVE_DEFINED, cmd->resultInfo() );
00882 completeQueue.removeRef (cmd);
00883 return;
00884 }
00885 else
00886 {
00887 if (hasCapability("UIDPLUS"))
00888 {
00889 TQString uid = cmd->resultInfo();
00890 if (uid.find("APPENDUID") != -1)
00891 {
00892 uid = uid.section(" ", 2, 2);
00893 uid.truncate(uid.length()-1);
00894 infoMessage("UID "+uid);
00895 }
00896 }
00897
00898 else if (aBox == getCurrentBox ())
00899 {
00900 cmd =
00901 doCommand (imapCommand::
00902 clientSelect (aBox, !selectInfo.readWrite ()));
00903 completeQueue.removeRef (cmd);
00904 }
00905 }
00906 }
00907 else
00908 {
00909
00910
00911 error (ERR_SLAVE_DEFINED, cmd->resultInfo());
00912 completeQueue.removeRef (cmd);
00913 return;
00914 }
00915
00916 completeQueue.removeRef (cmd);
00917 }
00918
00919 finished ();
00920 }
00921
00922 void
00923 IMAP4Protocol::mkdir (const KURL & _url, int)
00924 {
00925 kdDebug(7116) << "IMAP4::mkdir - " << _url.prettyURL() << endl;
00926 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
00927 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00928 kdDebug(7116) << "IMAP4::mkdir - create " << aBox << endl;
00929 imapCommand *cmd = doCommand (imapCommand::clientCreate(aBox));
00930
00931 if (cmd->result () != "OK")
00932 {
00933 kdDebug(7116) << "IMAP4::mkdir - " << cmd->resultInfo() << endl;
00934 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
00935 completeQueue.removeRef (cmd);
00936 return;
00937 }
00938 completeQueue.removeRef (cmd);
00939
00940
00941 enum IMAP_TYPE type =
00942 parseURL(_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
00943 if (type == ITYPE_BOX)
00944 {
00945 bool ask = ( aInfo.find( "ASKUSER" ) != -1 );
00946 if ( ask &&
00947 messageBox(QuestionYesNo,
00948 i18n("The following folder will be created on the server: %1 "
00949 "What do you want to store in this folder?").arg( aBox ),
00950 i18n("Create Folder"),
00951 i18n("&Messages"), i18n("&Subfolders")) == KMessageBox::No )
00952 {
00953 cmd = doCommand(imapCommand::clientDelete(aBox));
00954 completeQueue.removeRef (cmd);
00955 cmd = doCommand(imapCommand::clientCreate(aBox + aDelimiter));
00956 if (cmd->result () != "OK")
00957 {
00958 error (ERR_COULD_NOT_MKDIR, _url.prettyURL());
00959 completeQueue.removeRef (cmd);
00960 return;
00961 }
00962 completeQueue.removeRef (cmd);
00963 }
00964 }
00965
00966 cmd = doCommand(imapCommand::clientSubscribe(aBox));
00967 completeQueue.removeRef(cmd);
00968
00969 finished ();
00970 }
00971
00972 void
00973 IMAP4Protocol::copy (const KURL & src, const KURL & dest, int, bool overwrite)
00974 {
00975 kdDebug(7116) << "IMAP4::copy - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
00976 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
00977 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
00978 enum IMAP_TYPE sType =
00979 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo);
00980 enum IMAP_TYPE dType =
00981 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo);
00982
00983
00984 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
00985 {
00986
00987 int sub = dBox.find (sBox);
00988
00989
00990 if (sub > 0)
00991 {
00992 KURL testDir = dest;
00993
00994 TQString subDir = dBox.right (dBox.length () - dBox.findRev ('/'));
00995 TQString topDir = dBox.left (sub);
00996 testDir.setPath ("/" + topDir);
00997 dType =
00998 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
00999 dDelimiter, dInfo);
01000
01001 kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
01002
01003 if (dType == ITYPE_BOX || dType == ITYPE_DIR_AND_BOX)
01004 {
01005 kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
01006 dBox = topDir;
01007 }
01008 else
01009 {
01010
01011
01012 topDir = "/" + topDir + subDir;
01013 testDir.setPath (topDir);
01014 kdDebug(7116) << "IMAP4::copy - checking this destination " << topDir << endl;
01015 dType =
01016 parseURL (testDir, topDir, dSection, dLType, dSequence, dValidity,
01017 dDelimiter, dInfo);
01018 if (dType != ITYPE_BOX && dType != ITYPE_DIR_AND_BOX)
01019 {
01020
01021 imapCommand *cmd = doCommand (imapCommand::clientCreate (topDir));
01022
01023
01024 if (cmd->result () == "OK")
01025 {
01026 kdDebug(7116) << "IMAP4::copy - assuming this destination " << topDir << endl;
01027 dType = ITYPE_BOX;
01028 dBox = topDir;
01029 }
01030 else
01031 {
01032 completeQueue.removeRef (cmd);
01033 cmd = doCommand (imapCommand::clientCreate (dBox));
01034 if (cmd->result () == "OK")
01035 dType = ITYPE_BOX;
01036 else
01037 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
01038 }
01039 completeQueue.removeRef (cmd);
01040 }
01041 }
01042
01043 }
01044 }
01045 if (sType == ITYPE_MSG || sType == ITYPE_BOX || sType == ITYPE_DIR_AND_BOX)
01046 {
01047
01048 if (!assureBox(sBox, true)) return;
01049 kdDebug(7116) << "IMAP4::copy - " << sBox << " -> " << dBox << endl;
01050
01051
01052 imapCommand *cmd =
01053 doCommand (imapCommand::clientCopy (dBox, sSequence));
01054 if (cmd->result () != "OK")
01055 {
01056 kdError(5006) << "IMAP4::copy - " << cmd->resultInfo() << endl;
01057 error (ERR_COULD_NOT_WRITE, dest.prettyURL());
01058 completeQueue.removeRef (cmd);
01059 return;
01060 } else {
01061 if (hasCapability("UIDPLUS"))
01062 {
01063 TQString uid = cmd->resultInfo();
01064 if (uid.find("COPYUID") != -1)
01065 {
01066 uid = uid.section(" ", 2, 3);
01067 uid.truncate(uid.length()-1);
01068 infoMessage("UID "+uid);
01069 }
01070 }
01071 }
01072 completeQueue.removeRef (cmd);
01073 }
01074 else
01075 {
01076 error (ERR_ACCESS_DENIED, src.prettyURL());
01077 return;
01078 }
01079 finished ();
01080 }
01081
01082 void
01083 IMAP4Protocol::del (const KURL & _url, bool isFile)
01084 {
01085 kdDebug(7116) << "IMAP4::del - [" << (isFile ? "File" : "NoFile") << "] " << _url.prettyURL() << endl;
01086 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01087 enum IMAP_TYPE aType =
01088 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01089
01090 switch (aType)
01091 {
01092 case ITYPE_BOX:
01093 case ITYPE_DIR_AND_BOX:
01094 if (!aSequence.isEmpty ())
01095 {
01096 if (aSequence == "*")
01097 {
01098 if (!assureBox (aBox, false)) return;
01099 imapCommand *cmd = doCommand (imapCommand::clientExpunge ());
01100 if (cmd->result () != "OK") {
01101 error (ERR_CANNOT_DELETE, _url.prettyURL());
01102 completeQueue.removeRef (cmd);
01103 return;
01104 }
01105 completeQueue.removeRef (cmd);
01106 }
01107 else
01108 {
01109
01110 if (!assureBox (aBox, false)) return;
01111 imapCommand *cmd =
01112 doCommand (imapCommand::
01113 clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
01114 if (cmd->result () != "OK") {
01115 error (ERR_CANNOT_DELETE, _url.prettyURL());
01116 completeQueue.removeRef (cmd);
01117 return;
01118 }
01119 completeQueue.removeRef (cmd);
01120 }
01121 }
01122 else
01123 {
01124 if (getCurrentBox() == aBox)
01125 {
01126 imapCommand *cmd = doCommand(imapCommand::clientClose());
01127 completeQueue.removeRef(cmd);
01128 setState(ISTATE_LOGIN);
01129 }
01130
01131 imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
01132 completeQueue.removeRef(cmd);
01133 cmd = doCommand(imapCommand::clientDelete (aBox));
01134
01135 if (cmd->result () != "OK")
01136 {
01137 completeQueue.removeRef(cmd);
01138 if (!assureBox(aBox, false)) return;
01139 bool stillOk = true;
01140 if (stillOk)
01141 {
01142 imapCommand *cmd = doCommand(
01143 imapCommand::clientStore("1:*", "+FLAGS.SILENT", "\\DELETED"));
01144 if (cmd->result () != "OK") stillOk = false;
01145 completeQueue.removeRef(cmd);
01146 }
01147 if (stillOk)
01148 {
01149 imapCommand *cmd = doCommand(imapCommand::clientClose());
01150 if (cmd->result () != "OK") stillOk = false;
01151 completeQueue.removeRef(cmd);
01152 setState(ISTATE_LOGIN);
01153 }
01154 if (stillOk)
01155 {
01156 imapCommand *cmd = doCommand (imapCommand::clientDelete(aBox));
01157 if (cmd->result () != "OK") stillOk = false;
01158 completeQueue.removeRef(cmd);
01159 }
01160 if (!stillOk)
01161 {
01162 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
01163 return;
01164 }
01165 } else {
01166 completeQueue.removeRef (cmd);
01167 }
01168 }
01169 break;
01170
01171 case ITYPE_DIR:
01172 {
01173 imapCommand *cmd = doCommand (imapCommand::clientDelete (aBox));
01174 if (cmd->result () != "OK") {
01175 error (ERR_COULD_NOT_RMDIR, _url.prettyURL());
01176 completeQueue.removeRef (cmd);
01177 return;
01178 }
01179 completeQueue.removeRef (cmd);
01180 }
01181 break;
01182
01183 case ITYPE_MSG:
01184 {
01185
01186 if (!assureBox (aBox, false)) return;
01187 imapCommand *cmd =
01188 doCommand (imapCommand::
01189 clientStore (aSequence, "+FLAGS.SILENT", "\\DELETED"));
01190 if (cmd->result () != "OK") {
01191 error (ERR_CANNOT_DELETE, _url.prettyURL());
01192 completeQueue.removeRef (cmd);
01193 return;
01194 }
01195 completeQueue.removeRef (cmd);
01196 }
01197 break;
01198
01199 case ITYPE_UNKNOWN:
01200 case ITYPE_ATTACH:
01201 error (ERR_CANNOT_DELETE, _url.prettyURL());
01202 break;
01203 }
01204 finished ();
01205 }
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223 void
01224 IMAP4Protocol::special (const TQByteArray & aData)
01225 {
01226 kdDebug(7116) << "IMAP4Protocol::special" << endl;
01227 if (!makeLogin()) return;
01228
01229 TQDataStream stream(aData, IO_ReadOnly);
01230
01231 int tmp;
01232 stream >> tmp;
01233
01234 switch (tmp) {
01235 case 'C':
01236 {
01237
01238 KURL src;
01239 KURL dest;
01240 stream >> src >> dest;
01241 copy(src, dest, 0, FALSE);
01242 break;
01243 }
01244 case 'c':
01245 {
01246
01247 infoMessage(imapCapabilities.join(" "));
01248 finished();
01249 break;
01250 }
01251 case 'N':
01252 {
01253
01254 imapCommand *cmd = doCommand(imapCommand::clientNoop());
01255 if (cmd->result () != "OK")
01256 {
01257 kdDebug(7116) << "NOOP did not succeed - connection broken" << endl;
01258 completeQueue.removeRef (cmd);
01259 error (ERR_CONNECTION_BROKEN, myHost);
01260 return;
01261 }
01262 completeQueue.removeRef (cmd);
01263 finished();
01264 break;
01265 }
01266 case 'n':
01267 {
01268
01269
01270 infoMessage( imapNamespaces.join(",") );
01271 finished();
01272 break;
01273 }
01274 case 'U':
01275 {
01276
01277 KURL _url;
01278 stream >> _url;
01279 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01280 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01281 imapCommand *cmd = doCommand(imapCommand::clientUnsubscribe(aBox));
01282 if (cmd->result () != "OK")
01283 {
01284 completeQueue.removeRef (cmd);
01285 error(ERR_SLAVE_DEFINED, i18n("Unsubscribe of folder %1 "
01286 "failed. The server returned: %2")
01287 .arg(_url.prettyURL())
01288 .arg(cmd->resultInfo()));
01289 return;
01290 }
01291 completeQueue.removeRef (cmd);
01292 finished();
01293 break;
01294 }
01295 case 'u':
01296 {
01297
01298 KURL _url;
01299 stream >> _url;
01300 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01301 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01302 imapCommand *cmd = doCommand(imapCommand::clientSubscribe(aBox));
01303 if (cmd->result () != "OK")
01304 {
01305 completeQueue.removeRef (cmd);
01306 error(ERR_SLAVE_DEFINED, i18n("Subscribe of folder %1 "
01307 "failed. The server returned: %2")
01308 .arg(_url.prettyURL())
01309 .arg(cmd->resultInfo()));
01310 return;
01311 }
01312 completeQueue.removeRef (cmd);
01313 finished();
01314 break;
01315 }
01316 case 'A':
01317 {
01318
01319 int cmd;
01320 stream >> cmd;
01321 if ( hasCapability( "ACL" ) ) {
01322 specialACLCommand( cmd, stream );
01323 } else {
01324 error( ERR_UNSUPPORTED_ACTION, "ACL" );
01325 }
01326 break;
01327 }
01328 case 'M':
01329 {
01330
01331 int cmd;
01332 stream >> cmd;
01333 if ( hasCapability( "ANNOTATEMORE" ) ) {
01334 specialAnnotateMoreCommand( cmd, stream );
01335 } else {
01336 error( ERR_UNSUPPORTED_ACTION, "ANNOTATEMORE" );
01337 }
01338 break;
01339 }
01340 case 'Q':
01341 {
01342
01343 int cmd;
01344 stream >> cmd;
01345 if ( hasCapability( "QUOTA" ) ) {
01346 specialQuotaCommand( cmd, stream );
01347 } else {
01348 error( ERR_UNSUPPORTED_ACTION, "QUOTA" );
01349 }
01350 break;
01351 }
01352 case 'S':
01353 {
01354
01355 KURL _url;
01356 TQCString newFlags;
01357 stream >> _url >> newFlags;
01358
01359 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01360 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01361 if (!assureBox(aBox, false)) return;
01362
01363
01364 TQCString knownFlags = "\\SEEN \\ANSWERED \\FLAGGED \\DRAFT";
01365 const imapInfo info = getSelected();
01366 if ( info.permanentFlagsAvailable() && (info.permanentFlags() & imapInfo::User) ) {
01367 knownFlags += " KMAILFORWARDED KMAILTODO KMAILWATCHED KMAILIGNORED $FORWARDED $TODO $WATCHED $IGNORED";
01368 }
01369
01370 imapCommand *cmd = doCommand (imapCommand::
01371 clientStore (aSequence, "-FLAGS.SILENT", knownFlags));
01372 if (cmd->result () != "OK")
01373 {
01374 completeQueue.removeRef (cmd);
01375 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01376 "failed.").arg(_url.prettyURL()));
01377 return;
01378 }
01379 completeQueue.removeRef (cmd);
01380 if (!newFlags.isEmpty())
01381 {
01382 cmd = doCommand (imapCommand::
01383 clientStore (aSequence, "+FLAGS.SILENT", newFlags));
01384 if (cmd->result () != "OK")
01385 {
01386 completeQueue.removeRef (cmd);
01387 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01388 "failed.").arg(_url.prettyURL()));
01389 return;
01390 }
01391 completeQueue.removeRef (cmd);
01392 }
01393 finished();
01394 break;
01395 }
01396 case 's':
01397 {
01398
01399 KURL _url;
01400 bool seen;
01401 TQCString newFlags;
01402 stream >> _url >> seen;
01403
01404 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01405 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01406 if ( !assureBox(aBox, true) )
01407 return;
01408
01409 imapCommand *cmd;
01410 if ( seen )
01411 cmd = doCommand( imapCommand::clientStore( aSequence, "+FLAGS.SILENT", "\\SEEN" ) );
01412 else
01413 cmd = doCommand( imapCommand::clientStore( aSequence, "-FLAGS.SILENT", "\\SEEN" ) );
01414
01415 if (cmd->result () != "OK")
01416 {
01417 completeQueue.removeRef (cmd);
01418 error(ERR_COULD_NOT_WRITE, i18n("Changing the flags of message %1 "
01419 "failed.").arg(_url.prettyURL()));
01420 return;
01421 }
01422 completeQueue.removeRef (cmd);
01423 finished();
01424 break;
01425 }
01426
01427 case 'E':
01428 {
01429
01430 specialSearchCommand( stream );
01431 break;
01432 }
01433 case 'X':
01434 {
01435
01436 specialCustomCommand( stream );
01437 break;
01438 }
01439 default:
01440 kdWarning(7116) << "Unknown command in special(): " << tmp << endl;
01441 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(tmp)) );
01442 break;
01443 }
01444 }
01445
01446 void
01447 IMAP4Protocol::specialACLCommand( int command, TQDataStream& stream )
01448 {
01449
01450 KURL _url;
01451 stream >> _url;
01452 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01453 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01454
01455 switch( command ) {
01456 case 'S':
01457 {
01458 TQString user, acl;
01459 stream >> user >> acl;
01460 kdDebug(7116) << "SETACL " << aBox << " " << user << " " << acl << endl;
01461 imapCommand *cmd = doCommand(imapCommand::clientSetACL(aBox, user, acl));
01462 if (cmd->result () != "OK")
01463 {
01464 error(ERR_SLAVE_DEFINED, i18n("Setting the Access Control List on folder %1 "
01465 "for user %2 failed. The server returned: %3")
01466 .arg(_url.prettyURL())
01467 .arg(user)
01468 .arg(cmd->resultInfo()));
01469 return;
01470 }
01471 completeQueue.removeRef (cmd);
01472 finished();
01473 break;
01474 }
01475 case 'D':
01476 {
01477 TQString user;
01478 stream >> user;
01479 kdDebug(7116) << "DELETEACL " << aBox << " " << user << endl;
01480 imapCommand *cmd = doCommand(imapCommand::clientDeleteACL(aBox, user));
01481 if (cmd->result () != "OK")
01482 {
01483 error(ERR_SLAVE_DEFINED, i18n("Deleting the Access Control List on folder %1 "
01484 "for user %2 failed. The server returned: %3")
01485 .arg(_url.prettyURL())
01486 .arg(user)
01487 .arg(cmd->resultInfo()));
01488 return;
01489 }
01490 completeQueue.removeRef (cmd);
01491 finished();
01492 break;
01493 }
01494 case 'G':
01495 {
01496 kdDebug(7116) << "GETACL " << aBox << endl;
01497 imapCommand *cmd = doCommand(imapCommand::clientGetACL(aBox));
01498 if (cmd->result () != "OK")
01499 {
01500 error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
01501 "failed. The server returned: %2")
01502 .arg(_url.prettyURL())
01503 .arg(cmd->resultInfo()));
01504 return;
01505 }
01506
01507
01508
01509
01510 kdDebug(7116) << getResults() << endl;
01511 infoMessage(getResults().join( "\"" ));
01512 finished();
01513 break;
01514 }
01515 case 'L':
01516 {
01517
01518 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
01519 break;
01520 }
01521 case 'M':
01522 {
01523 kdDebug(7116) << "MYRIGHTS " << aBox << endl;
01524 imapCommand *cmd = doCommand(imapCommand::clientMyRights(aBox));
01525 if (cmd->result () != "OK")
01526 {
01527 error(ERR_SLAVE_DEFINED, i18n("Retrieving the Access Control List on folder %1 "
01528 "failed. The server returned: %2")
01529 .arg(_url.prettyURL())
01530 .arg(cmd->resultInfo()));
01531 return;
01532 }
01533 TQStringList lst = getResults();
01534 kdDebug(7116) << "myrights results: " << lst << endl;
01535 if ( !lst.isEmpty() ) {
01536 Q_ASSERT( lst.count() == 1 );
01537 infoMessage( lst.first() );
01538 }
01539 finished();
01540 break;
01541 }
01542 default:
01543 kdWarning(7116) << "Unknown special ACL command:" << command << endl;
01544 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
01545 }
01546 }
01547
01548 void
01549 IMAP4Protocol::specialSearchCommand( TQDataStream& stream )
01550 {
01551 kdDebug(7116) << "IMAP4Protocol::specialSearchCommand" << endl;
01552 KURL _url;
01553 stream >> _url;
01554 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01555 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01556 if (!assureBox(aBox, true)) return;
01557
01558 imapCommand *cmd = doCommand (imapCommand::clientSearch( aSection ));
01559 if (cmd->result () != "OK")
01560 {
01561 error(ERR_SLAVE_DEFINED, i18n("Searching of folder %1 "
01562 "failed. The server returned: %2")
01563 .arg(aBox)
01564 .arg(cmd->resultInfo()));
01565 return;
01566 }
01567 completeQueue.removeRef(cmd);
01568 TQStringList lst = getResults();
01569 kdDebug(7116) << "IMAP4Protocol::specialSearchCommand '" << aSection <<
01570 "' returns " << lst << endl;
01571 infoMessage( lst.join( " " ) );
01572
01573 finished();
01574 }
01575
01576 void
01577 IMAP4Protocol::specialCustomCommand( TQDataStream& stream )
01578 {
01579 kdDebug(7116) << "IMAP4Protocol::specialCustomCommand" << endl;
01580
01581 TQString command, arguments;
01582 int type;
01583 stream >> type;
01584 stream >> command >> arguments;
01585
01590 if ( type == 'N' ) {
01591 kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: normal mode" << endl;
01592 imapCommand *cmd = doCommand (imapCommand::clientCustom( command, arguments ));
01593 if (cmd->result () != "OK")
01594 {
01595 error(ERR_SLAVE_DEFINED, i18n("Custom command %1:%2 "
01596 "failed. The server returned: %3")
01597 .arg(command)
01598 .arg(arguments)
01599 .arg(cmd->resultInfo()));
01600 return;
01601 }
01602 completeQueue.removeRef(cmd);
01603 TQStringList lst = getResults();
01604 kdDebug(7116) << "IMAP4Protocol::specialCustomCommand '" << command <<
01605 ":" << arguments <<
01606 "' returns " << lst << endl;
01607 infoMessage( lst.join( " " ) );
01608
01609 finished();
01610 } else
01615 if ( type == 'E' ) {
01616 kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: extended mode" << endl;
01617 imapCommand *cmd = sendCommand (imapCommand::clientCustom( command, TQString() ));
01618 while ( !parseLoop () ) ;
01619
01620
01621 if (!cmd->isComplete () && !getContinuation ().isEmpty ())
01622 {
01623 const TQByteArray buffer = arguments.utf8();
01624
01625
01626 bool sendOk = (write (buffer.data (), buffer.size ()) == (ssize_t)buffer.size ());
01627 processedSize( buffer.size() );
01628
01629 if ( !sendOk ) {
01630 error ( ERR_CONNECTION_BROKEN, myHost );
01631 completeQueue.removeRef ( cmd );
01632 setState(ISTATE_CONNECT);
01633 closeConnection();
01634 return;
01635 }
01636 }
01637 parseWriteLine ("");
01638
01639 do
01640 {
01641 while (!parseLoop ()) ;
01642 }
01643 while (!cmd->isComplete ());
01644
01645 completeQueue.removeRef (cmd);
01646
01647 TQStringList lst = getResults();
01648 kdDebug(7116) << "IMAP4Protocol::specialCustomCommand: returns " << lst << endl;
01649 infoMessage( lst.join( " " ) );
01650
01651 finished ();
01652 }
01653 }
01654
01655 void
01656 IMAP4Protocol::specialAnnotateMoreCommand( int command, TQDataStream& stream )
01657 {
01658
01659 KURL _url;
01660 stream >> _url;
01661 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01662 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01663
01664 switch( command ) {
01665 case 'S':
01666 {
01667
01668
01669
01670
01671 TQString entry;
01672 TQMap<TQString, TQString> attributes;
01673 stream >> entry >> attributes;
01674 kdDebug(7116) << "SETANNOTATION " << aBox << " " << entry << " " << attributes.count() << " attributes" << endl;
01675 imapCommand *cmd = doCommand(imapCommand::clientSetAnnotation(aBox, entry, attributes));
01676 if (cmd->result () != "OK")
01677 {
01678 error(ERR_SLAVE_DEFINED, i18n("Setting the annotation %1 on folder %2 "
01679 " failed. The server returned: %3")
01680 .arg(entry)
01681 .arg(_url.prettyURL())
01682 .arg(cmd->resultInfo()));
01683 return;
01684 }
01685 completeQueue.removeRef (cmd);
01686 finished();
01687 break;
01688 }
01689 case 'G':
01690 {
01691
01692
01693
01694
01695 TQString entry;
01696 TQStringList attributeNames;
01697 stream >> entry >> attributeNames;
01698 kdDebug(7116) << "GETANNOTATION " << aBox << " " << entry << " " << attributeNames << endl;
01699 imapCommand *cmd = doCommand(imapCommand::clientGetAnnotation(aBox, entry, attributeNames));
01700 if (cmd->result () != "OK")
01701 {
01702 error(ERR_SLAVE_DEFINED, i18n("Retrieving the annotation %1 on folder %2 "
01703 "failed. The server returned: %3")
01704 .arg(entry)
01705 .arg(_url.prettyURL())
01706 .arg(cmd->resultInfo()));
01707 return;
01708 }
01709
01710
01711
01712 kdDebug(7116) << getResults() << endl;
01713 infoMessage(getResults().join( "\r" ));
01714 finished();
01715 break;
01716 }
01717 default:
01718 kdWarning(7116) << "Unknown special annotate command:" << command << endl;
01719 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
01720 }
01721 }
01722
01723 void
01724 IMAP4Protocol::specialQuotaCommand( int command, TQDataStream& stream )
01725 {
01726
01727 KURL _url;
01728 stream >> _url;
01729 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01730 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter, aInfo);
01731
01732 switch( command ) {
01733 case 'R':
01734 {
01735 kdDebug(7116) << "QUOTAROOT " << aBox << endl;
01736 imapCommand *cmd = doCommand(imapCommand::clientGetQuotaroot( aBox ) );
01737 if (cmd->result () != "OK")
01738 {
01739 error(ERR_SLAVE_DEFINED, i18n("Retrieving the quota root information on folder %1 "
01740 "failed. The server returned: %2")
01741 .arg(_url.prettyURL())
01742 .arg(cmd->resultInfo()));
01743 return;
01744 }
01745 infoMessage(getResults().join( "\r" ));
01746 finished();
01747 break;
01748 }
01749 case 'G':
01750 {
01751 kdDebug(7116) << "GETQUOTA command" << endl;
01752 kdWarning(7116) << "UNIMPLEMENTED" << endl;
01753 break;
01754 }
01755 case 'S':
01756 {
01757 kdDebug(7116) << "SETQUOTA command" << endl;
01758 kdWarning(7116) << "UNIMPLEMENTED" << endl;
01759 break;
01760 }
01761 default:
01762 kdWarning(7116) << "Unknown special quota command:" << command << endl;
01763 error( ERR_UNSUPPORTED_ACTION, TQString(TQChar(command)) );
01764 }
01765 }
01766
01767 void
01768 IMAP4Protocol::rename (const KURL & src, const KURL & dest, bool overwrite)
01769 {
01770 kdDebug(7116) << "IMAP4::rename - [" << (overwrite ? "Overwrite" : "NoOverwrite") << "] " << src.prettyURL() << " -> " << dest.prettyURL() << endl;
01771 TQString sBox, sSequence, sLType, sSection, sValidity, sDelimiter, sInfo;
01772 TQString dBox, dSequence, dLType, dSection, dValidity, dDelimiter, dInfo;
01773 enum IMAP_TYPE sType =
01774 parseURL (src, sBox, sSection, sLType, sSequence, sValidity, sDelimiter, sInfo, false);
01775 enum IMAP_TYPE dType =
01776 parseURL (dest, dBox, dSection, dLType, dSequence, dValidity, dDelimiter, dInfo, false);
01777
01778 if (dType == ITYPE_UNKNOWN)
01779 {
01780 switch (sType)
01781 {
01782 case ITYPE_BOX:
01783 case ITYPE_DIR:
01784 case ITYPE_DIR_AND_BOX:
01785 {
01786 if (getState() == ISTATE_SELECT && sBox == getCurrentBox())
01787 {
01788 kdDebug(7116) << "IMAP4::rename - close " << getCurrentBox() << endl;
01789
01790 imapCommand *cmd = doCommand (imapCommand::clientClose());
01791 bool ok = cmd->result() == "OK";
01792 completeQueue.removeRef(cmd);
01793 if (!ok)
01794 {
01795 kdWarning(7116) << "Unable to close mailbox!" << endl;
01796 error(ERR_CANNOT_RENAME, src.path());
01797 return;
01798 }
01799 setState(ISTATE_LOGIN);
01800 }
01801 imapCommand *cmd = doCommand (imapCommand::clientRename (sBox, dBox));
01802 if (cmd->result () != "OK") {
01803 error (ERR_CANNOT_RENAME, src.path());
01804 completeQueue.removeRef (cmd);
01805 return;
01806 }
01807 completeQueue.removeRef (cmd);
01808 }
01809 break;
01810
01811 case ITYPE_MSG:
01812 case ITYPE_ATTACH:
01813 case ITYPE_UNKNOWN:
01814 error (ERR_CANNOT_RENAME, src.path());
01815 break;
01816 }
01817 }
01818 else
01819 {
01820 error (ERR_CANNOT_RENAME, src.path());
01821 return;
01822 }
01823 finished ();
01824 }
01825
01826 void
01827 IMAP4Protocol::slave_status ()
01828 {
01829 bool connected = (getState() != ISTATE_NO) && isConnectionValid();
01830 kdDebug(7116) << "IMAP4::slave_status " << connected << endl;
01831 slaveStatus ( connected ? myHost : TQString(), connected );
01832 }
01833
01834 void
01835 IMAP4Protocol::dispatch (int command, const TQByteArray & data)
01836 {
01837 kdDebug(7116) << "IMAP4::dispatch - command=" << command << endl;
01838 TDEIO::TCPSlaveBase::dispatch (command, data);
01839 }
01840
01841 void
01842 IMAP4Protocol::stat (const KURL & _url)
01843 {
01844 kdDebug(7116) << "IMAP4::stat - " << _url.prettyURL() << endl;
01845 TQString aBox, aSequence, aLType, aSection, aValidity, aDelimiter, aInfo;
01846
01847 enum IMAP_TYPE aType =
01848 parseURL (_url, aBox, aSection, aLType, aSequence, aValidity, aDelimiter,
01849 aInfo, true);
01850
01851 UDSEntry entry;
01852 UDSAtom atom;
01853
01854 atom.m_uds = UDS_NAME;
01855 atom.m_str = aBox;
01856 entry.append (atom);
01857
01858 if (!aSection.isEmpty())
01859 {
01860 if (getState() == ISTATE_SELECT && aBox == getCurrentBox())
01861 {
01862 imapCommand *cmd = doCommand (imapCommand::clientClose());
01863 bool ok = cmd->result() == "OK";
01864 completeQueue.removeRef(cmd);
01865 if (!ok)
01866 {
01867 error(ERR_COULD_NOT_STAT, aBox);
01868 return;
01869 }
01870 setState(ISTATE_LOGIN);
01871 }
01872 bool ok = false;
01873 TQString cmdInfo;
01874 if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
01875 ok = true;
01876 else
01877 {
01878 imapCommand *cmd = doCommand(imapCommand::clienStatus(aBox, aSection));
01879 ok = cmd->result() == "OK";
01880 cmdInfo = cmd->resultInfo();
01881 completeQueue.removeRef(cmd);
01882 }
01883 if (!ok)
01884 {
01885 bool found = false;
01886 imapCommand *cmd = doCommand (imapCommand::clientList ("", aBox));
01887 if (cmd->result () == "OK")
01888 {
01889 for (TQValueListIterator < imapList > it = listResponses.begin ();
01890 it != listResponses.end (); ++it)
01891 {
01892 if (aBox == (*it).name ()) found = true;
01893 }
01894 }
01895 completeQueue.removeRef (cmd);
01896 if (found)
01897 error(ERR_COULD_NOT_STAT, aBox);
01898 else
01899 error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
01900 return;
01901 }
01902 if ((aSection == "UIDNEXT" && geStatus().uidNextAvailable())
01903 || (aSection == "UNSEEN" && geStatus().unseenAvailable()))
01904 {
01905 atom.m_uds = UDS_SIZE;
01906 atom.m_str = TQString();
01907 atom.m_long = (aSection == "UIDNEXT") ? geStatus().uidNext()
01908 : geStatus().unseen();
01909 entry.append(atom);
01910 }
01911 } else
01912 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX || aType == ITYPE_MSG ||
01913 aType == ITYPE_ATTACH)
01914 {
01915 ulong validity = 0;
01916
01917 if (aBox == getCurrentBox ())
01918 validity = selectInfo.uidValidity ();
01919 else
01920 {
01921
01922
01923
01924 imapCommand *cmd =
01925 doCommand (imapCommand::clienStatus (aBox, "UIDVALIDITY"));
01926 completeQueue.removeRef (cmd);
01927 validity = geStatus ().uidValidity ();
01928 }
01929 validity = 0;
01930
01931 if (aType == ITYPE_BOX || aType == ITYPE_DIR_AND_BOX)
01932 {
01933
01934 if (validity > 0 && validity != aValidity.toULong ())
01935 {
01936
01937 KURL newUrl = _url;
01938
01939 newUrl.setPath ("/" + aBox + ";UIDVALIDITY=" +
01940 TQString::number(validity));
01941 kdDebug(7116) << "IMAP4::stat - redirecting to " << newUrl.prettyURL() << endl;
01942 redirection (newUrl);
01943 }
01944 }
01945 else if (aType == ITYPE_MSG || aType == ITYPE_ATTACH)
01946 {
01947
01948
01949
01950
01951
01952 if (validity > 0 && validity != aValidity.toULong ())
01953 {
01954 aType = ITYPE_UNKNOWN;
01955 kdDebug(7116) << "IMAP4::stat - url has invalid validity [" << validity << "d] " << _url.prettyURL() << endl;
01956 }
01957 }
01958 }
01959
01960 atom.m_uds = UDS_MIME_TYPE;
01961 atom.m_str = getMimeType (aType);
01962 entry.append (atom);
01963
01964 kdDebug(7116) << "IMAP4: stat: " << atom.m_str << endl;
01965 switch (aType)
01966 {
01967 case ITYPE_DIR:
01968 atom.m_uds = UDS_FILE_TYPE;
01969 atom.m_str = TQString();
01970 atom.m_long = S_IFDIR;
01971 entry.append (atom);
01972 break;
01973
01974 case ITYPE_BOX:
01975 case ITYPE_DIR_AND_BOX:
01976 atom.m_uds = UDS_FILE_TYPE;
01977 atom.m_str = TQString();
01978 atom.m_long = S_IFDIR;
01979 entry.append (atom);
01980 break;
01981
01982 case ITYPE_MSG:
01983 case ITYPE_ATTACH:
01984 atom.m_uds = UDS_FILE_TYPE;
01985 atom.m_str = TQString();
01986 atom.m_long = S_IFREG;
01987 entry.append (atom);
01988 break;
01989
01990 case ITYPE_UNKNOWN:
01991 error (ERR_DOES_NOT_EXIST, _url.prettyURL());
01992 break;
01993 }
01994
01995 statEntry (entry);
01996 kdDebug(7116) << "IMAP4::stat - Finishing stat" << endl;
01997 finished ();
01998 }
01999
02000 void IMAP4Protocol::openConnection()
02001 {
02002 if (makeLogin()) connected();
02003 }
02004
02005 void IMAP4Protocol::closeConnection()
02006 {
02007 if (getState() == ISTATE_NO) return;
02008 if (getState() == ISTATE_SELECT && metaData("expunge") == "auto")
02009 {
02010 imapCommand *cmd = doCommand (imapCommand::clientExpunge());
02011 completeQueue.removeRef (cmd);
02012 }
02013 if (getState() != ISTATE_CONNECT)
02014 {
02015 imapCommand *cmd = doCommand (imapCommand::clientLogout());
02016 completeQueue.removeRef (cmd);
02017 }
02018 closeDescriptor();
02019 setState(ISTATE_NO);
02020 completeQueue.clear();
02021 sentQueue.clear();
02022 lastHandled = 0;
02023 currentBox = TQString();
02024 readBufferLen = 0;
02025 }
02026
02027 bool IMAP4Protocol::makeLogin ()
02028 {
02029 if (getState () == ISTATE_LOGIN || getState () == ISTATE_SELECT)
02030 return true;
02031
02032 kdDebug(7116) << "IMAP4::makeLogin - checking login" << endl;
02033 bool alreadyConnected = getState() == ISTATE_CONNECT;
02034 kdDebug(7116) << "IMAP4::makeLogin - alreadyConnected " << alreadyConnected << endl;
02035 if (alreadyConnected || connectToHost (myHost.latin1(), myPort))
02036 {
02037
02038
02039 setState(ISTATE_CONNECT);
02040
02041 myAuth = metaData("auth");
02042 myTLS = metaData("tls");
02043 kdDebug(7116) << "myAuth: " << myAuth << endl;
02044
02045 imapCommand *cmd;
02046
02047 unhandled.clear ();
02048 if (!alreadyConnected) while (!parseLoop ()) ;
02049 TQString greeting;
02050 if (!unhandled.isEmpty()) greeting = unhandled.first().stripWhiteSpace();
02051 unhandled.clear ();
02052 cmd = doCommand (new imapCommand ("CAPABILITY", ""));
02053
02054 kdDebug(7116) << "IMAP4: setHost: capability" << endl;
02055 for (TQStringList::Iterator it = imapCapabilities.begin ();
02056 it != imapCapabilities.end (); ++it)
02057 {
02058 kdDebug(7116) << "'" << (*it) << "'" << endl;
02059 }
02060 completeQueue.removeRef (cmd);
02061
02062 if (!hasCapability("IMAP4") && !hasCapability("IMAP4rev1"))
02063 {
02064 error(ERR_COULD_NOT_LOGIN, i18n("The server %1 supports neither "
02065 "IMAP4 nor IMAP4rev1.\nIt identified itself with: %2")
02066 .arg(myHost).arg(greeting));
02067 closeConnection();
02068 return false;
02069 }
02070
02071 if (metaData("nologin") == "on") return TRUE;
02072
02073 if (myTLS == "on" && !hasCapability(TQString("STARTTLS")))
02074 {
02075 error(ERR_COULD_NOT_LOGIN, i18n("The server does not support TLS.\n"
02076 "Disable this security feature to connect unencrypted."));
02077 closeConnection();
02078 return false;
02079 }
02080 if ((myTLS == "on" || (canUseTLS() && myTLS != "off")) &&
02081 hasCapability(TQString("STARTTLS")))
02082 {
02083 imapCommand *cmd = doCommand (imapCommand::clientStartTLS());
02084 if (cmd->result () == "OK")
02085 {
02086 completeQueue.removeRef(cmd);
02087 int tlsrc = startTLS();
02088 if (tlsrc == 1)
02089 {
02090 kdDebug(7116) << "TLS mode has been enabled." << endl;
02091 imapCommand *cmd2 = doCommand (new imapCommand ("CAPABILITY", ""));
02092 for (TQStringList::Iterator it = imapCapabilities.begin ();
02093 it != imapCapabilities.end (); ++it)
02094 {
02095 kdDebug(7116) << "'" << (*it) << "'" << endl;
02096 }
02097 completeQueue.removeRef (cmd2);
02098 } else {
02099 kdWarning(7116) << "TLS mode setup has failed. Aborting." << endl;
02100 error (ERR_COULD_NOT_LOGIN, i18n("Starting TLS failed."));
02101 closeConnection();
02102 return false;
02103 }
02104 } else completeQueue.removeRef(cmd);
02105 }
02106
02107 if (myAuth.isEmpty () || myAuth == "*") {
02108 if (hasCapability (TQString ("LOGINDISABLED"))) {
02109 error (ERR_COULD_NOT_LOGIN, i18n("LOGIN is disabled by the server."));
02110 closeConnection();
02111 return false;
02112 }
02113 }
02114 else {
02115 if (!hasCapability (TQString ("AUTH=") + myAuth)) {
02116 error (ERR_COULD_NOT_LOGIN, i18n("The authentication method %1 is not "
02117 "supported by the server.").arg(myAuth));
02118 closeConnection();
02119 return false;
02120 }
02121 }
02122
02123 if ( greeting.contains( TQRegExp( "Cyrus IMAP4 v2.1" ) ) ) {
02124 removeCapability( "ANNOTATEMORE" );
02125 }
02126
02127
02128 TQRegExp regExp( "Cyrus\\sIMAP[4]{0,1}\\sv(\\d+)\\.(\\d+)\\.(\\d+)", false );
02129 if ( regExp.search( greeting ) >= 0 ) {
02130 const int major = regExp.cap( 1 ).toInt();
02131 const int minor = regExp.cap( 2 ).toInt();
02132 const int patch = regExp.cap( 3 ).toInt();
02133 if ( major > 2 || (major == 2 && (minor > 3 || (minor == 3 && patch > 9))) ) {
02134 kdDebug(7116) << k_funcinfo << "Cyrus IMAP >= 2.3.9 detected, enabling shared seen flag support" << endl;
02135 imapCapabilities.append( "x-kmail-sharedseen" );
02136 }
02137 }
02138
02139 kdDebug(7116) << "IMAP4::makeLogin - attempting login" << endl;
02140
02141 TDEIO::AuthInfo authInfo;
02142 authInfo.username = myUser;
02143 authInfo.password = myPass;
02144 authInfo.prompt = i18n ("Username and password for your IMAP account:");
02145
02146 kdDebug(7116) << "IMAP4::makeLogin - open_PassDlg said user=" << myUser << " pass=xx" << endl;
02147
02148 TQString resultInfo;
02149 if (myAuth.isEmpty () || myAuth == "*")
02150 {
02151 if (myUser.isEmpty () || myPass.isEmpty ()) {
02152 if(openPassDlg (authInfo)) {
02153 myUser = authInfo.username;
02154 myPass = authInfo.password;
02155 }
02156 }
02157 if (!clientLogin (myUser, myPass, resultInfo))
02158 error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to login. Probably the "
02159 "password is wrong.\nThe server %1 replied:\n%2").arg(myHost).arg(resultInfo));
02160 }
02161 else
02162 {
02163 #ifdef HAVE_LIBSASL2
02164 if (!clientAuthenticate (this, authInfo, myHost, myAuth, mySSL, resultInfo))
02165 error(TDEIO::ERR_COULD_NOT_AUTHENTICATE, i18n("Unable to authenticate via %1.\n"
02166 "The server %2 replied:\n%3").arg(myAuth).arg(myHost).arg(resultInfo));
02167 else {
02168 myUser = authInfo.username;
02169 myPass = authInfo.password;
02170 }
02171 #else
02172 error(TDEIO::ERR_COULD_NOT_LOGIN, i18n("SASL authentication is not compiled into tdeio_imap4."));
02173 #endif
02174 }
02175 if ( hasCapability("NAMESPACE") )
02176 {
02177
02178 cmd = doCommand( imapCommand::clientNamespace() );
02179 if (cmd->result () == "OK")
02180 {
02181 kdDebug(7116) << "makeLogin - registered namespaces" << endl;
02182 }
02183 completeQueue.removeRef (cmd);
02184 }
02185
02186 cmd = doCommand( imapCommand::clientList("", "") );
02187 if (cmd->result () == "OK")
02188 {
02189 TQValueListIterator < imapList > it = listResponses.begin();
02190 if ( it == listResponses.end() )
02191 {
02192
02193
02194 completeQueue.removeRef (cmd);
02195 cmd = doCommand( imapCommand::clientList("", "%") );
02196 if (cmd->result () == "OK")
02197 {
02198 it = listResponses.begin();
02199 }
02200 }
02201 if ( it != listResponses.end() )
02202 {
02203 namespaceToDelimiter[TQString()] = (*it).hierarchyDelimiter();
02204 kdDebug(7116) << "makeLogin - delimiter for empty ns='" <<
02205 (*it).hierarchyDelimiter() << "'" << endl;
02206 if ( !hasCapability("NAMESPACE") )
02207 {
02208
02209 TQString nsentry = TQString::number( 0 ) + "=="
02210 + (*it).hierarchyDelimiter();
02211 imapNamespaces.append( nsentry );
02212 }
02213 }
02214 }
02215 completeQueue.removeRef (cmd);
02216 } else {
02217 kdDebug(7116) << "makeLogin - NO login" << endl;
02218 }
02219
02220 return getState() == ISTATE_LOGIN;
02221 }
02222
02223 void
02224 IMAP4Protocol::parseWriteLine (const TQString & aStr)
02225 {
02226
02227 TQCString writer = aStr.utf8();
02228 int len = writer.length();
02229
02230
02231 if (len == 0 || (writer[len - 1] != '\n')) {
02232 len += 2;
02233 writer += "\r\n";
02234 }
02235
02236
02237 write(writer.data(), len);
02238 }
02239
02240 TQString
02241 IMAP4Protocol::getMimeType (enum IMAP_TYPE aType)
02242 {
02243 switch (aType)
02244 {
02245 case ITYPE_DIR:
02246 return "inode/directory";
02247 break;
02248
02249 case ITYPE_BOX:
02250 return "message/digest";
02251 break;
02252
02253 case ITYPE_DIR_AND_BOX:
02254 return "message/directory";
02255 break;
02256
02257 case ITYPE_MSG:
02258 return "message/rfc822";
02259 break;
02260
02261
02262 case ITYPE_ATTACH:
02263 return "application/octet-stream";
02264 break;
02265
02266 case ITYPE_UNKNOWN:
02267 default:
02268 return "unknown/unknown";
02269 }
02270 }
02271
02272
02273
02274 void
02275 IMAP4Protocol::doListEntry (const KURL & _url, int stretch, imapCache * cache,
02276 bool withFlags, bool withSubject)
02277 {
02278 KURL aURL = _url;
02279 aURL.setQuery (TQString());
02280 const TQString encodedUrl = aURL.url(0, 106);
02281 doListEntry(encodedUrl, stretch, cache, withFlags, withSubject);
02282 }
02283
02284
02285
02286 void
02287 IMAP4Protocol::doListEntry (const TQString & encodedUrl, int stretch, imapCache * cache,
02288 bool withFlags, bool withSubject)
02289 {
02290 if (cache)
02291 {
02292 UDSEntry entry;
02293 UDSAtom atom;
02294
02295 entry.clear ();
02296
02297 const TQString uid = TQString::number(cache->getUid());
02298
02299 atom.m_uds = UDS_NAME;
02300 atom.m_str = uid;
02301 atom.m_long = 0;
02302 if (stretch > 0)
02303 {
02304 atom.m_str = "0000000000000000" + atom.m_str;
02305 atom.m_str = atom.m_str.right (stretch);
02306 }
02307 if (withSubject)
02308 {
02309 mailHeader *header = cache->getHeader();
02310 if (header)
02311 atom.m_str += " " + header->getSubject();
02312 }
02313 entry.append (atom);
02314
02315 atom.m_uds = UDS_URL;
02316 atom.m_str = encodedUrl;
02317 if (atom.m_str[atom.m_str.length () - 1] != '/')
02318 atom.m_str += '/';
02319 atom.m_str += ";UID=" + uid;
02320 atom.m_long = 0;
02321 entry.append (atom);
02322
02323 atom.m_uds = UDS_FILE_TYPE;
02324 atom.m_str = TQString();
02325 atom.m_long = S_IFREG;
02326 entry.append (atom);
02327
02328 atom.m_uds = UDS_SIZE;
02329 atom.m_long = cache->getSize();
02330 entry.append (atom);
02331
02332 atom.m_uds = UDS_MIME_TYPE;
02333 atom.m_str = "message/rfc822";
02334 atom.m_long = 0;
02335 entry.append (atom);
02336
02337 atom.m_uds = UDS_USER;
02338 atom.m_str = myUser;
02339 entry.append (atom);
02340
02341 atom.m_uds = TDEIO::UDS_ACCESS;
02342 atom.m_long = (withFlags) ? cache->getFlags() : S_IRUSR | S_IXUSR | S_IWUSR;
02343 entry.append (atom);
02344
02345 listEntry (entry, false);
02346 }
02347 }
02348
02349 void
02350 IMAP4Protocol::doListEntry (const KURL & _url, const TQString & myBox,
02351 const imapList & item, bool appendPath)
02352 {
02353 KURL aURL = _url;
02354 aURL.setQuery (TQString());
02355 UDSEntry entry;
02356 UDSAtom atom;
02357 int hdLen = item.hierarchyDelimiter().length();
02358
02359 {
02360
02361 TQString mailboxName = item.name ();
02362
02363
02364 if (mailboxName.find (myBox) == 0 && mailboxName.length() > myBox.length())
02365 {
02366 mailboxName =
02367 mailboxName.right (mailboxName.length () - myBox.length ());
02368 }
02369 if (mailboxName[0] == '/')
02370 mailboxName = mailboxName.right (mailboxName.length () - 1);
02371 if (mailboxName.left(hdLen) == item.hierarchyDelimiter())
02372 mailboxName = mailboxName.right(mailboxName.length () - hdLen);
02373 if (mailboxName.right(hdLen) == item.hierarchyDelimiter())
02374 mailboxName.truncate(mailboxName.length () - hdLen);
02375
02376 atom.m_uds = UDS_NAME;
02377 if (!item.hierarchyDelimiter().isEmpty() &&
02378 mailboxName.find(item.hierarchyDelimiter()) != -1)
02379 atom.m_str = mailboxName.section(item.hierarchyDelimiter(), -1);
02380 else
02381 atom.m_str = mailboxName;
02382
02383
02384 if (atom.m_str.isEmpty ())
02385 atom.m_str = "..";
02386
02387 if (!atom.m_str.isEmpty ())
02388 {
02389 atom.m_long = 0;
02390 entry.append (atom);
02391
02392 if (!item.noSelect ())
02393 {
02394 atom.m_uds = UDS_MIME_TYPE;
02395 if (!item.noInferiors ())
02396 {
02397 atom.m_str = "message/directory";
02398 } else {
02399 atom.m_str = "message/digest";
02400 }
02401 atom.m_long = 0;
02402 entry.append (atom);
02403 mailboxName += '/';
02404
02405
02406 atom.m_uds = UDS_FILE_TYPE;
02407 atom.m_str = TQString();
02408 atom.m_long = S_IFDIR;
02409 entry.append (atom);
02410 }
02411 else if (!item.noInferiors ())
02412 {
02413 atom.m_uds = UDS_MIME_TYPE;
02414 atom.m_str = "inode/directory";
02415 atom.m_long = 0;
02416 entry.append (atom);
02417 mailboxName += '/';
02418
02419
02420 atom.m_uds = UDS_FILE_TYPE;
02421 atom.m_str = TQString();
02422 atom.m_long = S_IFDIR;
02423 entry.append (atom);
02424 }
02425 else
02426 {
02427 atom.m_uds = UDS_MIME_TYPE;
02428 atom.m_str = "unknown/unknown";
02429 atom.m_long = 0;
02430 entry.append (atom);
02431 }
02432
02433 atom.m_uds = UDS_URL;
02434 TQString path = aURL.path();
02435 atom.m_str = aURL.url (0, 106);
02436 if (appendPath)
02437 {
02438 if (path[path.length() - 1] == '/' && !path.isEmpty() && path != "/")
02439 path.truncate(path.length() - 1);
02440 if (!path.isEmpty() && path != "/"
02441 && path.right(hdLen) != item.hierarchyDelimiter()) {
02442 path += item.hierarchyDelimiter();
02443 }
02444 path += mailboxName;
02445 if (path.upper() == "/INBOX/") {
02446
02447 path = path.upper();
02448 }
02449 }
02450 aURL.setPath(path);
02451 atom.m_str = aURL.url(0, 106);
02452 atom.m_long = 0;
02453 entry.append (atom);
02454
02455 atom.m_uds = UDS_USER;
02456 atom.m_str = myUser;
02457 entry.append (atom);
02458
02459 atom.m_uds = UDS_ACCESS;
02460 atom.m_long = S_IRUSR | S_IXUSR | S_IWUSR;
02461 entry.append (atom);
02462
02463 atom.m_uds = UDS_EXTRA;
02464 atom.m_str = item.attributesAsString();
02465 atom.m_long = 0;
02466 entry.append (atom);
02467
02468 listEntry (entry, false);
02469 }
02470 }
02471 }
02472
02473 enum IMAP_TYPE
02474 IMAP4Protocol::parseURL (const KURL & _url, TQString & _box,
02475 TQString & _section, TQString & _type, TQString & _uid,
02476 TQString & _validity, TQString & _hierarchyDelimiter,
02477 TQString & _info, bool cache)
02478 {
02479 enum IMAP_TYPE retVal;
02480 retVal = ITYPE_UNKNOWN;
02481
02482 imapParser::parseURL (_url, _box, _section, _type, _uid, _validity, _info);
02483
02484
02485
02486 TQString myNamespace = namespaceForBox( _box );
02487 kdDebug(7116) << "IMAP4::parseURL - namespace=" << myNamespace << endl;
02488 if ( namespaceToDelimiter.contains(myNamespace) )
02489 {
02490 _hierarchyDelimiter = namespaceToDelimiter[myNamespace];
02491 kdDebug(7116) << "IMAP4::parseURL - delimiter=" << _hierarchyDelimiter << endl;
02492 }
02493
02494 if (!_box.isEmpty ())
02495 {
02496 kdDebug(7116) << "IMAP4::parseURL - box=" << _box << endl;
02497
02498 if (makeLogin ())
02499 {
02500 if (getCurrentBox () != _box ||
02501 _type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK")
02502 {
02503 if ( cache )
02504 {
02505
02506 retVal = ITYPE_DIR_AND_BOX;
02507 } else
02508 {
02509
02510 imapCommand *cmd;
02511
02512 cmd = doCommand (imapCommand::clientList ("", _box));
02513 if (cmd->result () == "OK")
02514 {
02515 for (TQValueListIterator < imapList > it = listResponses.begin ();
02516 it != listResponses.end (); ++it)
02517 {
02518
02519 if (_box == (*it).name ())
02520 {
02521 if ( !(*it).hierarchyDelimiter().isEmpty() )
02522 _hierarchyDelimiter = (*it).hierarchyDelimiter();
02523 if ((*it).noSelect ())
02524 {
02525 retVal = ITYPE_DIR;
02526 }
02527 else if ((*it).noInferiors ())
02528 {
02529 retVal = ITYPE_BOX;
02530 }
02531 else
02532 {
02533 retVal = ITYPE_DIR_AND_BOX;
02534 }
02535 }
02536 }
02537
02538 if ( retVal == ITYPE_UNKNOWN &&
02539 namespaceToDelimiter.contains(_box) ) {
02540 retVal = ITYPE_DIR;
02541 }
02542 } else {
02543 kdDebug(7116) << "IMAP4::parseURL - got error for " << _box << endl;
02544 }
02545 completeQueue.removeRef (cmd);
02546 }
02547 }
02548 else
02549 {
02550 retVal = ITYPE_BOX;
02551 }
02552 }
02553 else
02554 kdDebug(7116) << "IMAP4::parseURL: no login!" << endl;
02555
02556 }
02557 else
02558 {
02559
02560 kdDebug(7116) << "IMAP4: parseURL: box [root]" << endl;
02561 retVal = ITYPE_DIR;
02562 }
02563
02564
02565 if (retVal == ITYPE_BOX || retVal == ITYPE_DIR_AND_BOX)
02566 {
02567 if (!_uid.isEmpty ())
02568 {
02569 if (_uid.find (':') == -1 && _uid.find (',') == -1
02570 && _uid.find ('*') == -1)
02571 retVal = ITYPE_MSG;
02572 }
02573 }
02574 if (retVal == ITYPE_MSG)
02575 {
02576 if ( (_section.find ("BODY.PEEK[", 0, false) != -1 ||
02577 _section.find ("BODY[", 0, false) != -1) &&
02578 _section.find(".MIME") == -1 &&
02579 _section.find(".HEADER") == -1 )
02580 retVal = ITYPE_ATTACH;
02581 }
02582 if ( _hierarchyDelimiter.isEmpty() &&
02583 (_type == "LIST" || _type == "LSUB" || _type == "LSUBNOCHECK") )
02584 {
02585
02586
02587 if (!_box.isEmpty())
02588 {
02589 int start = _url.path().findRev(_box);
02590 if (start != -1)
02591 _hierarchyDelimiter = _url.path().mid(start-1, start);
02592 kdDebug(7116) << "IMAP4::parseURL - reconstructed delimiter:" << _hierarchyDelimiter
02593 << " from URL " << _url.path() << endl;
02594 }
02595 if (_hierarchyDelimiter.isEmpty())
02596 _hierarchyDelimiter = "/";
02597 }
02598 kdDebug(7116) << "IMAP4::parseURL - return " << retVal << endl;
02599
02600 return retVal;
02601 }
02602
02603 int
02604 IMAP4Protocol::outputLine (const TQCString & _str, int len)
02605 {
02606 if (len == -1) {
02607 len = _str.length();
02608 }
02609
02610 if (cacheOutput)
02611 {
02612 if ( !outputBuffer.isOpen() ) {
02613 outputBuffer.open(IO_WriteOnly);
02614 }
02615 outputBuffer.at(outputBufferIndex);
02616 outputBuffer.writeBlock(_str.data(), len);
02617 outputBufferIndex += len;
02618 return 0;
02619 }
02620
02621 TQByteArray temp;
02622 bool relay = relayEnabled;
02623
02624 relayEnabled = true;
02625 temp.setRawData (_str.data (), len);
02626 parseRelay (temp);
02627 temp.resetRawData (_str.data (), len);
02628
02629 relayEnabled = relay;
02630 return 0;
02631 }
02632
02633 void IMAP4Protocol::flushOutput(TQString contentEncoding)
02634 {
02635
02636 if (outputBufferIndex == 0)
02637 return;
02638 outputBuffer.close();
02639 outputCache.resize(outputBufferIndex);
02640 if (decodeContent)
02641 {
02642
02643 TQByteArray decoded;
02644 if (contentEncoding.find("quoted-printable", 0, false) == 0)
02645 decoded = KCodecs::quotedPrintableDecode(outputCache);
02646 else if (contentEncoding.find("base64", 0, false) == 0)
02647 KCodecs::base64Decode(outputCache, decoded);
02648 else
02649 decoded = outputCache;
02650
02651 TQString mimetype = KMimeType::findByContent( decoded )->name();
02652 kdDebug(7116) << "IMAP4::flushOutput - mimeType " << mimetype << endl;
02653 mimeType(mimetype);
02654 decodeContent = false;
02655 data( decoded );
02656 } else {
02657 data( outputCache );
02658 }
02659 mProcessedSize += outputBufferIndex;
02660 processedSize( mProcessedSize );
02661 outputBufferIndex = 0;
02662 outputCache[0] = '\0';
02663 outputBuffer.setBuffer(outputCache);
02664 }
02665
02666 ssize_t IMAP4Protocol::myRead(void *data, ssize_t len)
02667 {
02668 if (readBufferLen)
02669 {
02670 ssize_t copyLen = (len < readBufferLen) ? len : readBufferLen;
02671 memcpy(data, readBuffer, copyLen);
02672 readBufferLen -= copyLen;
02673 if (readBufferLen) memmove(readBuffer, &readBuffer[copyLen], readBufferLen);
02674 return copyLen;
02675 }
02676 if (!isConnectionValid()) return 0;
02677 waitForResponse( responseTimeout() );
02678 return read(data, len);
02679 }
02680
02681 bool
02682 IMAP4Protocol::assureBox (const TQString & aBox, bool readonly)
02683 {
02684 if (aBox.isEmpty()) return false;
02685
02686 imapCommand *cmd = 0;
02687
02688 if (aBox != getCurrentBox () || (!getSelected().readWrite() && !readonly))
02689 {
02690
02691 kdDebug(7116) << "IMAP4Protocol::assureBox - opening box" << endl;
02692 selectInfo = imapInfo();
02693 cmd = doCommand (imapCommand::clientSelect (aBox, readonly));
02694 bool ok = cmd->result() == "OK";
02695 TQString cmdInfo = cmd->resultInfo();
02696 completeQueue.removeRef (cmd);
02697
02698 if (!ok)
02699 {
02700 bool found = false;
02701 cmd = doCommand (imapCommand::clientList ("", aBox));
02702 if (cmd->result () == "OK")
02703 {
02704 for (TQValueListIterator < imapList > it = listResponses.begin ();
02705 it != listResponses.end (); ++it)
02706 {
02707 if (aBox == (*it).name ()) found = true;
02708 }
02709 }
02710 completeQueue.removeRef (cmd);
02711 if (found) {
02712 if (cmdInfo.find("permission", 0, false) != -1) {
02713
02714 error(ERR_ACCESS_DENIED, cmdInfo);
02715 } else {
02716 error(ERR_SLAVE_DEFINED, i18n("Unable to open folder %1. The server replied: %2").arg(aBox).arg(cmdInfo));
02717 }
02718 } else {
02719 error(TDEIO::ERR_DOES_NOT_EXIST, aBox);
02720 }
02721 return false;
02722 }
02723 }
02724 else
02725 {
02726
02727
02728
02729 kdDebug(7116) << "IMAP4Protocol::assureBox - reusing box" << endl;
02730 if ( mTimeOfLastNoop.secsTo( TQDateTime::currentDateTime() ) > 10 ) {
02731 cmd = doCommand (imapCommand::clientNoop ());
02732 completeQueue.removeRef (cmd);
02733 mTimeOfLastNoop = TQDateTime::currentDateTime();
02734 kdDebug(7116) << "IMAP4Protocol::assureBox - noop timer fired" << endl;
02735 }
02736 }
02737
02738
02739 if (!getSelected().readWrite() && !readonly)
02740 {
02741 error(TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, aBox);
02742 return false;
02743 }
02744
02745 return true;
02746 }