00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #include "rfcdecoder.h"
00030
00031 #include "imapparser.h"
00032
00033 #include "imapinfo.h"
00034
00035 #include "mailheader.h"
00036 #include "mimeheader.h"
00037 #include "mailaddress.h"
00038
00039 #include <sys/types.h>
00040
00041 #include <stdlib.h>
00042 #include <unistd.h>
00043
00044 #ifdef HAVE_LIBSASL2
00045 extern "C" {
00046 #include <sasl/sasl.h>
00047 }
00048 #endif
00049
00050 #include <qregexp.h>
00051 #include <qbuffer.h>
00052 #include <qstring.h>
00053 #include <qstringlist.h>
00054
00055 #include <kdebug.h>
00056 #include <kmdcodec.h>
00057 #include <kurl.h>
00058
00059 #include <kasciistricmp.h>
00060 #include <kasciistringtools.h>
00061
00062 imapParser::imapParser ()
00063 {
00064 sentQueue.setAutoDelete (false);
00065 completeQueue.setAutoDelete (true);
00066 currentState = ISTATE_NO;
00067 commandCounter = 0;
00068 lastHandled = 0;
00069 }
00070
00071 imapParser::~imapParser ()
00072 {
00073 delete lastHandled;
00074 lastHandled = 0;
00075 }
00076
00077 imapCommand *
00078 imapParser::doCommand (imapCommand * aCmd)
00079 {
00080 int pl = 0;
00081 sendCommand (aCmd);
00082 while (pl != -1 && !aCmd->isComplete ()) {
00083 while ((pl = parseLoop ()) == 0)
00084 ;
00085 }
00086
00087 return aCmd;
00088 }
00089
00090 imapCommand *
00091 imapParser::sendCommand (imapCommand * aCmd)
00092 {
00093 aCmd->setId (QString::number(commandCounter++));
00094 sentQueue.append (aCmd);
00095
00096 continuation.resize(0);
00097 const QString& command = aCmd->command();
00098
00099 if (command == "SELECT" || command == "EXAMINE")
00100 {
00101
00102 parseString p;
00103 p.fromString(aCmd->parameter());
00104 currentBox = parseOneWordC(p);
00105 kdDebug(7116) << "imapParser::sendCommand - setting current box to " << currentBox << endl;
00106 }
00107 else if (command == "CLOSE")
00108 {
00109
00110 currentBox = QString::null;
00111 }
00112 else if (command.find ("SEARCH") != -1
00113 || command == "GETACL"
00114 || command == "LISTRIGHTS"
00115 || command == "MYRIGHTS"
00116 || command == "GETANNOTATION"
00117 || command == "NAMESPACE")
00118 {
00119 lastResults.clear ();
00120 }
00121 else if (command == "LIST"
00122 || command == "LSUB")
00123 {
00124 listResponses.clear ();
00125 }
00126 parseWriteLine (aCmd->getStr ());
00127 return aCmd;
00128 }
00129
00130 bool
00131 imapParser::clientLogin (const QString & aUser, const QString & aPass,
00132 QString & resultInfo)
00133 {
00134 imapCommand *cmd;
00135 bool retVal = false;
00136
00137 cmd =
00138 doCommand (new
00139 imapCommand ("LOGIN", "\"" + rfcDecoder::quoteIMAP(aUser)
00140 + "\" \"" + rfcDecoder::quoteIMAP(aPass) + "\""));
00141
00142 if (cmd->result () == "OK")
00143 {
00144 currentState = ISTATE_LOGIN;
00145 retVal = true;
00146 }
00147 resultInfo = cmd->resultInfo();
00148 completeQueue.removeRef (cmd);
00149
00150 return retVal;
00151 }
00152
00153 #ifdef HAVE_LIBSASL2
00154 static bool sasl_interact( KIO::SlaveBase *slave, KIO::AuthInfo &ai, void *in )
00155 {
00156 kdDebug(7116) << "sasl_interact" << endl;
00157 sasl_interact_t *interact = ( sasl_interact_t * ) in;
00158
00159
00160
00161 for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
00162 if ( interact->id == SASL_CB_AUTHNAME ||
00163 interact->id == SASL_CB_PASS ) {
00164
00165 if ( ai.username.isEmpty() || ai.password.isEmpty() ) {
00166 if (!slave->openPassDlg(ai))
00167 return false;
00168 }
00169 break;
00170 }
00171 }
00172
00173 interact = ( sasl_interact_t * ) in;
00174 while( interact->id != SASL_CB_LIST_END ) {
00175 kdDebug(7116) << "SASL_INTERACT id: " << interact->id << endl;
00176 switch( interact->id ) {
00177 case SASL_CB_USER:
00178 case SASL_CB_AUTHNAME:
00179 kdDebug(7116) << "SASL_CB_[USER|AUTHNAME]: '" << ai.username << "'" << endl;
00180 interact->result = strdup( ai.username.utf8() );
00181 interact->len = strlen( (const char *) interact->result );
00182 break;
00183 case SASL_CB_PASS:
00184 kdDebug(7116) << "SASL_CB_PASS: [hidden] " << endl;
00185 interact->result = strdup( ai.password.utf8() );
00186 interact->len = strlen( (const char *) interact->result );
00187 break;
00188 default:
00189 interact->result = 0;
00190 interact->len = 0;
00191 break;
00192 }
00193 interact++;
00194 }
00195 return true;
00196 }
00197 #endif
00198
00199 bool
00200 imapParser::clientAuthenticate ( KIO::SlaveBase *slave, KIO::AuthInfo &ai,
00201 const QString & aFQDN, const QString & aAuth, bool isSSL, QString & resultInfo)
00202 {
00203 bool retVal = false;
00204 #ifdef HAVE_LIBSASL2
00205 int result;
00206 sasl_conn_t *conn = 0;
00207 sasl_interact_t *client_interact = 0;
00208 const char *out = 0;
00209 uint outlen = 0;
00210 const char *mechusing = 0;
00211 QByteArray tmp, challenge;
00212
00213 kdDebug(7116) << "aAuth: " << aAuth << " FQDN: " << aFQDN << " isSSL: " << isSSL << endl;
00214
00215
00216 if (!hasCapability ("AUTH=" + aAuth))
00217 return false;
00218
00219
00220 result = sasl_client_new( "imap",
00221
00222 aFQDN.latin1(),
00223 0, 0, 0, 0, &conn );
00224
00225 if ( result != SASL_OK ) {
00226 kdDebug(7116) << "sasl_client_new failed with: " << result << endl;
00227 resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
00228 return false;
00229 }
00230
00231 do {
00232 result = sasl_client_start(conn, aAuth.latin1(), &client_interact,
00233 hasCapability("SASL-IR") ? &out : 0, &outlen, &mechusing);
00234
00235 if ( result == SASL_INTERACT ) {
00236 if ( !sasl_interact( slave, ai, client_interact ) ) {
00237 sasl_dispose( &conn );
00238 return false;
00239 }
00240 }
00241 } while ( result == SASL_INTERACT );
00242
00243 if ( result != SASL_CONTINUE && result != SASL_OK ) {
00244 kdDebug(7116) << "sasl_client_start failed with: " << result << endl;
00245 resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
00246 sasl_dispose( &conn );
00247 return false;
00248 }
00249 imapCommand *cmd;
00250
00251 tmp.setRawData( out, outlen );
00252 KCodecs::base64Encode( tmp, challenge );
00253 tmp.resetRawData( out, outlen );
00254
00255 QString firstCommand = aAuth;
00256 if ( !challenge.isEmpty() ) {
00257 firstCommand += " ";
00258 firstCommand += QString::fromLatin1( challenge.data(), challenge.size() );
00259 }
00260 cmd = sendCommand (new imapCommand ("AUTHENTICATE", firstCommand.latin1()));
00261
00262 while ( true )
00263 {
00264
00265 while (parseLoop() == 0);
00266 if ( cmd->isComplete() ) break;
00267
00268 if (!continuation.isEmpty())
00269 {
00270
00271 if ( continuation.size() > 4 ) {
00272 tmp.setRawData( continuation.data() + 2, continuation.size() - 4 );
00273 KCodecs::base64Decode( tmp, challenge );
00274
00275 tmp.resetRawData( continuation.data() + 2, continuation.size() - 4 );
00276 }
00277
00278 do {
00279 result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(),
00280 challenge.size(),
00281 &client_interact,
00282 &out, &outlen);
00283
00284 if (result == SASL_INTERACT) {
00285 if ( !sasl_interact( slave, ai, client_interact ) ) {
00286 sasl_dispose( &conn );
00287 return false;
00288 }
00289 }
00290 } while ( result == SASL_INTERACT );
00291
00292 if ( result != SASL_CONTINUE && result != SASL_OK ) {
00293 kdDebug(7116) << "sasl_client_step failed with: " << result << endl;
00294 resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
00295 sasl_dispose( &conn );
00296 return false;
00297 }
00298
00299 tmp.setRawData( out, outlen );
00300
00301 KCodecs::base64Encode( tmp, challenge );
00302 tmp.resetRawData( out, outlen );
00303
00304 parseWriteLine (challenge);
00305 continuation.resize(0);
00306 }
00307 }
00308
00309 if (cmd->result () == "OK")
00310 {
00311 currentState = ISTATE_LOGIN;
00312 retVal = true;
00313 }
00314 resultInfo = cmd->resultInfo();
00315 completeQueue.removeRef (cmd);
00316
00317 sasl_dispose( &conn );
00318 #endif //HAVE_LIBSASL2
00319 return retVal;
00320 }
00321
00322 void
00323 imapParser::parseUntagged (parseString & result)
00324 {
00325
00326
00327 parseOneWordC(result);
00328 QByteArray what = parseLiteral (result);
00329
00330 switch (what[0])
00331 {
00332
00333 case 'B':
00334 if (qstrncmp(what, "BAD", what.size()) == 0)
00335 {
00336 parseResult (what, result);
00337 }
00338 else if (qstrncmp(what, "BYE", what.size()) == 0)
00339 {
00340 parseResult (what, result);
00341 if ( sentQueue.count() ) {
00342
00343 imapCommand *current = sentQueue.at (0);
00344 current->setResultInfo(result.cstr());
00345 }
00346 currentState = ISTATE_NO;
00347 }
00348 break;
00349
00350 case 'N':
00351 if (what[1] == 'O' && what.size() == 2)
00352 {
00353 parseResult (what, result);
00354 }
00355 else if (qstrncmp(what, "NAMESPACE", what.size()) == 0)
00356 {
00357 parseNamespace (result);
00358 }
00359 break;
00360
00361 case 'O':
00362 if (what[1] == 'K' && what.size() == 2)
00363 {
00364 parseResult (what, result);
00365 }
00366 break;
00367
00368 case 'P':
00369 if (qstrncmp(what, "PREAUTH", what.size()) == 0)
00370 {
00371 parseResult (what, result);
00372 currentState = ISTATE_LOGIN;
00373 }
00374 break;
00375
00376
00377 case 'C':
00378 if (qstrncmp(what, "CAPABILITY", what.size()) == 0)
00379 {
00380 parseCapability (result);
00381 }
00382 break;
00383
00384 case 'F':
00385 if (qstrncmp(what, "FLAGS", what.size()) == 0)
00386 {
00387 parseFlags (result);
00388 }
00389 break;
00390
00391 case 'L':
00392 if (qstrncmp(what, "LIST", what.size()) == 0)
00393 {
00394 parseList (result);
00395 }
00396 else if (qstrncmp(what, "LSUB", what.size()) == 0)
00397 {
00398 parseLsub (result);
00399 }
00400 else if (qstrncmp(what, "LISTRIGHTS", what.size()) == 0)
00401 {
00402 parseListRights (result);
00403 }
00404 break;
00405
00406 case 'M':
00407 if (qstrncmp(what, "MYRIGHTS", what.size()) == 0)
00408 {
00409 parseMyRights (result);
00410 }
00411 break;
00412 case 'S':
00413 if (qstrncmp(what, "SEARCH", what.size()) == 0)
00414 {
00415 parseSearch (result);
00416 }
00417 else if (qstrncmp(what, "STATUS", what.size()) == 0)
00418 {
00419 parseStatus (result);
00420 }
00421 break;
00422
00423 case 'A':
00424 if (qstrncmp(what, "ACL", what.size()) == 0)
00425 {
00426 parseAcl (result);
00427 }
00428 else if (qstrncmp(what, "ANNOTATION", what.size()) == 0)
00429 {
00430 parseAnnotation (result);
00431 }
00432 break;
00433 default:
00434
00435 {
00436 ulong number;
00437 bool valid;
00438
00439 number = QCString(what, what.size() + 1).toUInt(&valid);
00440 if (valid)
00441 {
00442 what = parseLiteral (result);
00443 switch (what[0])
00444 {
00445 case 'E':
00446 if (qstrncmp(what, "EXISTS", what.size()) == 0)
00447 {
00448 parseExists (number, result);
00449 }
00450 else if (qstrncmp(what, "EXPUNGE", what.size()) == 0)
00451 {
00452 parseExpunge (number, result);
00453 }
00454 break;
00455
00456 case 'F':
00457 if (qstrncmp(what, "FETCH", what.size()) == 0)
00458 {
00459 seenUid = QString::null;
00460 parseFetch (number, result);
00461 }
00462 break;
00463
00464 case 'S':
00465 if (qstrncmp(what, "STORE", what.size()) == 0)
00466 {
00467 seenUid = QString::null;
00468 parseFetch (number, result);
00469 }
00470 break;
00471
00472 case 'R':
00473 if (qstrncmp(what, "RECENT", what.size()) == 0)
00474 {
00475 parseRecent (number, result);
00476 }
00477 break;
00478 default:
00479 break;
00480 }
00481 }
00482 }
00483 break;
00484 }
00485 }
00486
00487
00488 void
00489 imapParser::parseResult (QByteArray & result, parseString & rest,
00490 const QString & command)
00491 {
00492 if (command == "SELECT")
00493 selectInfo.setReadWrite(true);
00494
00495 if (rest[0] == '[')
00496 {
00497 rest.pos++;
00498 QCString option = parseOneWordC(rest, TRUE);
00499
00500 switch (option[0])
00501 {
00502 case 'A':
00503 if (option == "ALERT")
00504 {
00505 rest.pos = rest.data.find(']', rest.pos) + 1;
00506
00507
00508 selectInfo.setAlert( rest.cstr() );
00509 }
00510 break;
00511
00512 case 'N':
00513 if (option == "NEWNAME")
00514 {
00515 }
00516 break;
00517
00518 case 'P':
00519 if (option == "PARSE")
00520 {
00521 }
00522 else if (option == "PERMANENTFLAGS")
00523 {
00524 uint end = rest.data.find(']', rest.pos);
00525 QCString flags(rest.data.data() + rest.pos, end - rest.pos);
00526 selectInfo.setPermanentFlags (flags);
00527 rest.pos = end;
00528 }
00529 break;
00530
00531 case 'R':
00532 if (option == "READ-ONLY")
00533 {
00534 selectInfo.setReadWrite (false);
00535 }
00536 else if (option == "READ-WRITE")
00537 {
00538 selectInfo.setReadWrite (true);
00539 }
00540 break;
00541
00542 case 'T':
00543 if (option == "TRYCREATE")
00544 {
00545 }
00546 break;
00547
00548 case 'U':
00549 if (option == "UIDVALIDITY")
00550 {
00551 ulong value;
00552 if (parseOneNumber (rest, value))
00553 selectInfo.setUidValidity (value);
00554 }
00555 else if (option == "UNSEEN")
00556 {
00557 ulong value;
00558 if (parseOneNumber (rest, value))
00559 selectInfo.setUnseen (value);
00560 }
00561 else if (option == "UIDNEXT")
00562 {
00563 ulong value;
00564 if (parseOneNumber (rest, value))
00565 selectInfo.setUidNext (value);
00566 }
00567 else
00568 break;
00569
00570 }
00571 if (rest[0] == ']')
00572 rest.pos++;
00573 skipWS (rest);
00574 }
00575
00576 if (command.isEmpty())
00577 {
00578
00579
00580 return;
00581 }
00582
00583 switch (command[0].latin1 ())
00584 {
00585 case 'A':
00586 if (command == "AUTHENTICATE")
00587 if (qstrncmp(result, "OK", result.size()) == 0)
00588 currentState = ISTATE_LOGIN;
00589 break;
00590
00591 case 'L':
00592 if (command == "LOGIN")
00593 if (qstrncmp(result, "OK", result.size()) == 0)
00594 currentState = ISTATE_LOGIN;
00595 break;
00596
00597 case 'E':
00598 if (command == "EXAMINE")
00599 {
00600 if (qstrncmp(result, "OK", result.size()) == 0)
00601 currentState = ISTATE_SELECT;
00602 else
00603 {
00604 if (currentState == ISTATE_SELECT)
00605 currentState = ISTATE_LOGIN;
00606 currentBox = QString::null;
00607 }
00608 kdDebug(7116) << "imapParser::parseResult - current box is now " << currentBox << endl;
00609 }
00610 break;
00611
00612 case 'S':
00613 if (command == "SELECT")
00614 {
00615 if (qstrncmp(result, "OK", result.size()) == 0)
00616 currentState = ISTATE_SELECT;
00617 else
00618 {
00619 if (currentState == ISTATE_SELECT)
00620 currentState = ISTATE_LOGIN;
00621 currentBox = QString::null;
00622 }
00623 kdDebug(7116) << "imapParser::parseResult - current box is now " << currentBox << endl;
00624 }
00625 break;
00626
00627 default:
00628 break;
00629 }
00630
00631 }
00632
00633 void imapParser::parseCapability (parseString & result)
00634 {
00635 QCString temp( result.cstr() );
00636 imapCapabilities = QStringList::split ( ' ', KPIM::kAsciiToLower( temp.data() ) );
00637 }
00638
00639 void imapParser::parseFlags (parseString & result)
00640 {
00641 selectInfo.setFlags(result.cstr());
00642 }
00643
00644 void imapParser::parseList (parseString & result)
00645 {
00646 imapList this_one;
00647
00648 if (result[0] != '(')
00649 return;
00650
00651 result.pos++;
00652
00653 this_one.parseAttributes( result );
00654
00655 result.pos++;
00656 skipWS (result);
00657
00658 this_one.setHierarchyDelimiter(parseLiteralC(result));
00659 this_one.setName (rfcDecoder::fromIMAP(parseLiteralC(result)));
00660
00661 listResponses.append (this_one);
00662 }
00663
00664 void imapParser::parseLsub (parseString & result)
00665 {
00666 imapList this_one (result.cstr());
00667 listResponses.append (this_one);
00668 }
00669
00670 void imapParser::parseListRights (parseString & result)
00671 {
00672 parseOneWordC (result);
00673 parseOneWordC (result);
00674 int outlen = 1;
00675 while ( outlen ) {
00676 QCString word = parseOneWordC (result, false, &outlen);
00677 lastResults.append (word);
00678 }
00679 }
00680
00681 void imapParser::parseAcl (parseString & result)
00682 {
00683 parseOneWordC (result);
00684 int outlen = 1;
00685
00686 while ( outlen && !result.isEmpty() ) {
00687 QCString word = parseLiteralC (result, false, false, &outlen);
00688 lastResults.append (word);
00689 }
00690 }
00691
00692 void imapParser::parseAnnotation (parseString & result)
00693 {
00694 parseOneWordC (result);
00695 skipWS (result);
00696 parseOneWordC (result);
00697 skipWS (result);
00698 if (result.isEmpty() || result[0] != '(')
00699 return;
00700 result.pos++;
00701 skipWS (result);
00702 int outlen = 1;
00703
00704 while ( outlen && !result.isEmpty() && result[0] != ')' ) {
00705 QCString word = parseLiteralC (result, false, false, &outlen);
00706 lastResults.append (word);
00707 }
00708 }
00709
00710 void imapParser::parseMyRights (parseString & result)
00711 {
00712 parseOneWordC (result);
00713 Q_ASSERT( lastResults.isEmpty() );
00714 lastResults.append (parseOneWordC (result) );
00715 }
00716
00717 void imapParser::parseSearch (parseString & result)
00718 {
00719 ulong value;
00720
00721 while (parseOneNumber (result, value))
00722 {
00723 lastResults.append (QString::number(value));
00724 }
00725 }
00726
00727 void imapParser::parseStatus (parseString & inWords)
00728 {
00729 lastStatus = imapInfo ();
00730
00731 parseLiteralC(inWords);
00732 if (inWords[0] != '(')
00733 return;
00734
00735 inWords.pos++;
00736 skipWS (inWords);
00737
00738 while (!inWords.isEmpty() && inWords[0] != ')')
00739 {
00740 ulong value;
00741
00742 QCString label = parseOneWordC(inWords);
00743 if (parseOneNumber (inWords, value))
00744 {
00745 if (label == "MESSAGES")
00746 lastStatus.setCount (value);
00747 else if (label == "RECENT")
00748 lastStatus.setRecent (value);
00749 else if (label == "UIDVALIDITY")
00750 lastStatus.setUidValidity (value);
00751 else if (label == "UNSEEN")
00752 lastStatus.setUnseen (value);
00753 else if (label == "UIDNEXT")
00754 lastStatus.setUidNext (value);
00755 }
00756 }
00757
00758 if (inWords[0] == ')')
00759 inWords.pos++;
00760 skipWS (inWords);
00761 }
00762
00763 void imapParser::parseExists (ulong value, parseString & result)
00764 {
00765 selectInfo.setCount (value);
00766 result.pos = result.data.size();
00767 }
00768
00769 void imapParser::parseExpunge (ulong value, parseString & result)
00770 {
00771 Q_UNUSED(value);
00772 Q_UNUSED(result);
00773 }
00774
00775 void imapParser::parseAddressList (parseString & inWords, QPtrList<mailAddress>& list)
00776 {
00777 if (inWords[0] != '(')
00778 {
00779 parseOneWord (inWords);
00780 }
00781 else
00782 {
00783 inWords.pos++;
00784 skipWS (inWords);
00785
00786 while (!inWords.isEmpty () && inWords[0] != ')')
00787 {
00788 if (inWords[0] == '(') {
00789 mailAddress *addr = new mailAddress;
00790 parseAddress(inWords, *addr);
00791 list.append(addr);
00792 } else {
00793 break;
00794 }
00795 }
00796
00797 if (inWords[0] == ')')
00798 inWords.pos++;
00799 skipWS (inWords);
00800 }
00801 }
00802
00803 const mailAddress& imapParser::parseAddress (parseString & inWords, mailAddress& retVal)
00804 {
00805 inWords.pos++;
00806 skipWS (inWords);
00807
00808 retVal.setFullName(rfcDecoder::quoteIMAP(parseLiteralC(inWords)));
00809 retVal.setCommentRaw(parseLiteralC(inWords));
00810 retVal.setUser(parseLiteralC(inWords));
00811 retVal.setHost(parseLiteralC(inWords));
00812
00813 if (inWords[0] == ')')
00814 inWords.pos++;
00815 skipWS (inWords);
00816
00817 return retVal;
00818 }
00819
00820 mailHeader * imapParser::parseEnvelope (parseString & inWords)
00821 {
00822 mailHeader *envelope = 0;
00823
00824 if (inWords[0] != '(')
00825 return envelope;
00826 inWords.pos++;
00827 skipWS (inWords);
00828
00829 envelope = new mailHeader;
00830
00831
00832 envelope->setDate(parseLiteralC(inWords));
00833
00834
00835 envelope->setSubject(parseLiteralC(inWords));
00836
00837 QPtrList<mailAddress> list;
00838 list.setAutoDelete(true);
00839
00840
00841 parseAddressList(inWords, list);
00842 if (!list.isEmpty()) {
00843 envelope->setFrom(*list.last());
00844 list.clear();
00845 }
00846
00847
00848 parseAddressList(inWords, list);
00849 if (!list.isEmpty()) {
00850 envelope->setSender(*list.last());
00851 list.clear();
00852 }
00853
00854
00855 parseAddressList(inWords, list);
00856 if (!list.isEmpty()) {
00857 envelope->setReplyTo(*list.last());
00858 list.clear();
00859 }
00860
00861
00862 parseAddressList (inWords, envelope->to());
00863
00864
00865 parseAddressList (inWords, envelope->cc());
00866
00867
00868 parseAddressList (inWords, envelope->bcc());
00869
00870
00871 envelope->setInReplyTo(parseLiteralC(inWords));
00872
00873
00874 envelope->setMessageId(parseLiteralC(inWords));
00875
00876
00877 while (!inWords.isEmpty () && inWords[0] != ')')
00878 {
00879
00880 if (inWords[0] == '(')
00881 parseSentence (inWords);
00882 else
00883 parseLiteralC (inWords);
00884 }
00885
00886 if (inWords[0] == ')')
00887 inWords.pos++;
00888 skipWS (inWords);
00889
00890 return envelope;
00891 }
00892
00893
00894
00895 QAsciiDict < QString > imapParser::parseDisposition (parseString & inWords)
00896 {
00897 QByteArray disposition;
00898 QAsciiDict < QString > retVal (17, false);
00899
00900
00901 retVal.setAutoDelete (false);
00902
00903 if (inWords[0] != '(')
00904 {
00905
00906 disposition = parseOneWord (inWords);
00907 }
00908 else
00909 {
00910 inWords.pos++;
00911 skipWS (inWords);
00912
00913
00914 disposition = parseOneWord (inWords);
00915
00916 retVal = parseParameters (inWords);
00917 if (inWords[0] != ')')
00918 return retVal;
00919 inWords.pos++;
00920 skipWS (inWords);
00921 }
00922
00923 if (!disposition.isEmpty ())
00924 {
00925 retVal.insert ("content-disposition", new QString(b2c(disposition)));
00926 }
00927
00928 return retVal;
00929 }
00930
00931
00932
00933 QAsciiDict < QString > imapParser::parseParameters (parseString & inWords)
00934 {
00935 QAsciiDict < QString > retVal (17, false);
00936
00937
00938 retVal.setAutoDelete (false);
00939
00940 if (inWords[0] != '(')
00941 {
00942
00943 parseOneWord (inWords);
00944 }
00945 else
00946 {
00947 inWords.pos++;
00948 skipWS (inWords);
00949
00950 while (!inWords.isEmpty () && inWords[0] != ')')
00951 {
00952 retVal.insert (parseLiteralC(inWords), new QString(parseLiteralC(inWords)));
00953 }
00954
00955 if (inWords[0] != ')')
00956 return retVal;
00957 inWords.pos++;
00958 skipWS (inWords);
00959 }
00960
00961 return retVal;
00962 }
00963
00964 mimeHeader * imapParser::parseSimplePart (parseString & inWords,
00965 QString & inSection, mimeHeader * localPart)
00966 {
00967 QCString subtype;
00968 QCString typeStr;
00969 QAsciiDict < QString > parameters (17, false);
00970 ulong size;
00971
00972 parameters.setAutoDelete (true);
00973
00974 if (inWords[0] != '(')
00975 return 0;
00976
00977 if (!localPart)
00978 localPart = new mimeHeader;
00979
00980 localPart->setPartSpecifier (inSection);
00981
00982 inWords.pos++;
00983 skipWS (inWords);
00984
00985
00986 typeStr = parseLiteralC(inWords);
00987
00988
00989 subtype = parseLiteralC(inWords);
00990
00991 localPart->setType (typeStr + "/" + subtype);
00992
00993
00994 parameters = parseParameters (inWords);
00995 {
00996 QAsciiDictIterator < QString > it (parameters);
00997
00998 while (it.current ())
00999 {
01000 localPart->setTypeParm (it.currentKey (), *(it.current ()));
01001 ++it;
01002 }
01003 parameters.clear ();
01004 }
01005
01006
01007 localPart->setID (parseLiteralC(inWords));
01008
01009
01010 localPart->setDescription (parseLiteralC(inWords));
01011
01012
01013 localPart->setEncoding (parseLiteralC(inWords));
01014
01015
01016 if (parseOneNumber (inWords, size))
01017 localPart->setLength (size);
01018
01019
01020 if (localPart->getType().upper() == "MESSAGE/RFC822")
01021 {
01022
01023 mailHeader *envelope = parseEnvelope (inWords);
01024
01025
01026 parseBodyStructure (inWords, inSection, envelope);
01027
01028 localPart->setNestedMessage (envelope);
01029
01030
01031 ulong lines;
01032 parseOneNumber (inWords, lines);
01033 }
01034 else
01035 {
01036 if (typeStr == "TEXT")
01037 {
01038
01039 ulong lines;
01040 parseOneNumber (inWords, lines);
01041 }
01042
01043
01044 parseLiteralC(inWords);
01045
01046
01047 parameters = parseDisposition (inWords);
01048 {
01049 QString *disposition = parameters["content-disposition"];
01050
01051 if (disposition)
01052 localPart->setDisposition (disposition->ascii ());
01053 parameters.remove ("content-disposition");
01054 QAsciiDictIterator < QString > it (parameters);
01055 while (it.current ())
01056 {
01057 localPart->setDispositionParm (it.currentKey (),
01058 *(it.current ()));
01059 ++it;
01060 }
01061 parameters.clear ();
01062 }
01063
01064
01065 parseSentence (inWords);
01066 }
01067
01068
01069 while (!inWords.isEmpty () && inWords[0] != ')')
01070 {
01071
01072 if (inWords[0] == '(')
01073 parseSentence (inWords);
01074 else
01075 parseLiteralC(inWords);
01076 }
01077
01078 if (inWords[0] == ')')
01079 inWords.pos++;
01080 skipWS (inWords);
01081
01082 return localPart;
01083 }
01084
01085 mimeHeader * imapParser::parseBodyStructure (parseString & inWords,
01086 QString & inSection, mimeHeader * localPart)
01087 {
01088 bool init = false;
01089 if (inSection.isEmpty())
01090 {
01091
01092 init = true;
01093
01094 inSection = "1";
01095 }
01096 int section = 0;
01097
01098 if (inWords[0] != '(')
01099 {
01100
01101 parseOneWord (inWords);
01102 return 0;
01103 }
01104 inWords.pos++;
01105 skipWS (inWords);
01106
01107 if (inWords[0] == '(')
01108 {
01109 QByteArray subtype;
01110 QAsciiDict < QString > parameters (17, false);
01111 QString outSection;
01112 parameters.setAutoDelete (true);
01113 if (!localPart)
01114 localPart = new mimeHeader;
01115 else
01116 {
01117
01118 localPart->clearNestedParts ();
01119 localPart->clearTypeParameters ();
01120 localPart->clearDispositionParameters ();
01121
01122 outSection = inSection + ".HEADER";
01123 }
01124 if (inWords[0] == '(' && init)
01125 inSection = "0";
01126
01127
01128 if ( !outSection.isEmpty() ) {
01129 localPart->setPartSpecifier(outSection);
01130 } else {
01131 localPart->setPartSpecifier(inSection);
01132 }
01133
01134
01135 while (inWords[0] == '(')
01136 {
01137 outSection = QString::number(++section);
01138 if (!init)
01139 outSection = inSection + "." + outSection;
01140 mimeHeader *subpart = parseBodyStructure (inWords, outSection, 0);
01141 localPart->addNestedPart (subpart);
01142 }
01143
01144
01145 subtype = parseOneWord (inWords);
01146
01147 localPart->setType ("MULTIPART/" + b2c(subtype));
01148
01149
01150 parameters = parseParameters (inWords);
01151 {
01152 QAsciiDictIterator < QString > it (parameters);
01153
01154 while (it.current ())
01155 {
01156 localPart->setTypeParm (it.currentKey (), *(it.current ()));
01157 ++it;
01158 }
01159 parameters.clear ();
01160 }
01161
01162
01163 parameters = parseDisposition (inWords);
01164 {
01165 QString *disposition = parameters["content-disposition"];
01166
01167 if (disposition)
01168 localPart->setDisposition (disposition->ascii ());
01169 parameters.remove ("content-disposition");
01170 QAsciiDictIterator < QString > it (parameters);
01171 while (it.current ())
01172 {
01173 localPart->setDispositionParm (it.currentKey (),
01174 *(it.current ()));
01175 ++it;
01176 }
01177 parameters.clear ();
01178 }
01179
01180
01181 parseSentence (inWords);
01182
01183 }
01184 else
01185 {
01186
01187 inWords.pos--;
01188 inWords.data[inWords.pos] = '(';
01189 if ( localPart )
01190 inSection = inSection + ".1";
01191 localPart = parseSimplePart (inWords, inSection, localPart);
01192 inWords.pos--;
01193 inWords.data[inWords.pos] = ')';
01194 }
01195
01196
01197 while (!inWords.isEmpty () && inWords[0] != ')')
01198 {
01199
01200 if (inWords[0] == '(')
01201 parseSentence (inWords);
01202 else
01203 parseLiteralC(inWords);
01204 }
01205
01206 if (inWords[0] == ')')
01207 inWords.pos++;
01208 skipWS (inWords);
01209
01210 return localPart;
01211 }
01212
01213 void imapParser::parseBody (parseString & inWords)
01214 {
01215
01216 if (inWords[0] == '[')
01217 {
01218 QByteArray specifier;
01219 QByteArray label;
01220 inWords.pos++;
01221
01222 specifier = parseOneWord (inWords, TRUE);
01223
01224 if (inWords[0] == '(')
01225 {
01226 inWords.pos++;
01227
01228 while (!inWords.isEmpty () && inWords[0] != ')')
01229 {
01230 label = parseOneWord (inWords);
01231 }
01232
01233 if (inWords[0] == ')')
01234 inWords.pos++;
01235 }
01236 if (inWords[0] == ']')
01237 inWords.pos++;
01238 skipWS (inWords);
01239
01240
01241 if (qstrncmp(specifier, "0", specifier.size()) == 0)
01242 {
01243 mailHeader *envelope = 0;
01244 if (lastHandled)
01245 envelope = lastHandled->getHeader ();
01246
01247 if (!envelope || seenUid.isEmpty ())
01248 {
01249 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01250
01251 parseLiteralC(inWords, true);
01252 }
01253 else
01254 {
01255 kdDebug(7116) << "imapParser::parseBody - reading " << envelope << " " << seenUid.ascii () << endl;
01256
01257 QString theHeader = parseLiteralC(inWords, true);
01258 mimeIOQString myIO;
01259
01260 myIO.setString (theHeader);
01261 envelope->parseHeader (myIO);
01262
01263 }
01264 }
01265 else if (qstrncmp(specifier, "HEADER.FIELDS", specifier.size()) == 0)
01266 {
01267
01268
01269
01270 if (qstrncmp(label, "REFERENCES", label.size()) == 0)
01271 {
01272 mailHeader *envelope = 0;
01273 if (lastHandled)
01274 envelope = lastHandled->getHeader ();
01275
01276 if (!envelope || seenUid.isEmpty ())
01277 {
01278 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01279
01280 parseLiteralC (inWords, true);
01281 }
01282 else
01283 {
01284 QCString references = parseLiteralC(inWords, true);
01285 int start = references.find ('<');
01286 int end = references.findRev ('>');
01287 if (start < end)
01288 references = references.mid (start, end - start + 1);
01289 envelope->setReferences(references.simplifyWhiteSpace());
01290 }
01291 }
01292 else
01293 {
01294 parseLiteralC(inWords, true);
01295 }
01296 }
01297 else
01298 {
01299 QCString spec(specifier.data(), specifier.size()+1);
01300 if (spec.find(".MIME") != -1)
01301 {
01302 mailHeader *envelope = new mailHeader;
01303 QString theHeader = parseLiteralC(inWords, false);
01304 mimeIOQString myIO;
01305 myIO.setString (theHeader);
01306 envelope->parseHeader (myIO);
01307 if (lastHandled)
01308 lastHandled->setHeader (envelope);
01309 return;
01310 }
01311
01312 kdDebug(7116) << "imapParser::parseBody - discarding " << seenUid.ascii () << endl;
01313 parseLiteralC(inWords, true);
01314 }
01315
01316 }
01317 else
01318 {
01319 mailHeader *envelope = 0;
01320 if (lastHandled)
01321 envelope = lastHandled->getHeader ();
01322
01323 if (!envelope || seenUid.isEmpty ())
01324 {
01325 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01326
01327 parseSentence (inWords);
01328 }
01329 else
01330 {
01331 kdDebug(7116) << "imapParser::parseBody - reading " << envelope << " " << seenUid.ascii () << endl;
01332
01333 QString section;
01334 mimeHeader *body = parseBodyStructure (inWords, section, envelope);
01335 if (body != envelope)
01336 delete body;
01337 }
01338 }
01339 }
01340
01341 void imapParser::parseFetch (ulong , parseString & inWords)
01342 {
01343 if (inWords[0] != '(')
01344 return;
01345 inWords.pos++;
01346 skipWS (inWords);
01347
01348 delete lastHandled;
01349 lastHandled = 0;
01350
01351 while (!inWords.isEmpty () && inWords[0] != ')')
01352 {
01353 if (inWords[0] == '(')
01354 parseSentence (inWords);
01355 else
01356 {
01357 QCString word = parseLiteralC(inWords, false, true);
01358
01359 switch (word[0])
01360 {
01361 case 'E':
01362 if (word == "ENVELOPE")
01363 {
01364 mailHeader *envelope = 0;
01365
01366 if (lastHandled)
01367 envelope = lastHandled->getHeader ();
01368 else
01369 lastHandled = new imapCache();
01370
01371 if (envelope && !envelope->getMessageId ().isEmpty ())
01372 {
01373
01374
01375 parseSentence (inWords);
01376 }
01377 else
01378 {
01379 envelope = parseEnvelope (inWords);
01380 if (envelope)
01381 {
01382 envelope->setPartSpecifier (seenUid + ".0");
01383 lastHandled->setHeader (envelope);
01384 lastHandled->setUid (seenUid.toULong ());
01385 }
01386 }
01387 }
01388 break;
01389
01390 case 'B':
01391 if (word == "BODY")
01392 {
01393 parseBody (inWords);
01394 }
01395 else if (word == "BODY[]" )
01396 {
01397
01398 parseLiteralC(inWords, true);
01399 }
01400 else if (word == "BODYSTRUCTURE")
01401 {
01402 mailHeader *envelope = 0;
01403
01404 if (lastHandled)
01405 envelope = lastHandled->getHeader ();
01406
01407
01408 QString section;
01409 mimeHeader *body =
01410 parseBodyStructure (inWords, section, envelope);
01411 QByteArray data;
01412 QDataStream stream( data, IO_WriteOnly );
01413 body->serialize(stream);
01414 parseRelay(data);
01415
01416 delete body;
01417 }
01418 break;
01419
01420 case 'U':
01421 if (word == "UID")
01422 {
01423 seenUid = parseOneWordC(inWords);
01424 mailHeader *envelope = 0;
01425 if (lastHandled)
01426 envelope = lastHandled->getHeader ();
01427 else
01428 lastHandled = new imapCache();
01429
01430 if (seenUid.isEmpty ())
01431 {
01432
01433 kdDebug(7116) << "imapParser::parseFetch - UID empty" << endl;
01434 }
01435 else
01436 {
01437 lastHandled->setUid (seenUid.toULong ());
01438 }
01439 if (envelope)
01440 envelope->setPartSpecifier (seenUid);
01441 }
01442 break;
01443
01444 case 'R':
01445 if (word == "RFC822.SIZE")
01446 {
01447 ulong size;
01448 parseOneNumber (inWords, size);
01449
01450 if (!lastHandled) lastHandled = new imapCache();
01451 lastHandled->setSize (size);
01452 }
01453 else if (word.find ("RFC822") == 0)
01454 {
01455
01456 parseLiteralC(inWords, true);
01457 }
01458 break;
01459
01460 case 'I':
01461 if (word == "INTERNALDATE")
01462 {
01463 QCString date = parseOneWordC(inWords);
01464 if (!lastHandled) lastHandled = new imapCache();
01465 lastHandled->setDate(date);
01466 }
01467 break;
01468
01469 case 'F':
01470 if (word == "FLAGS")
01471 {
01472
01473 if (!lastHandled) lastHandled = new imapCache();
01474 lastHandled->setFlags (imapInfo::_flags (inWords.cstr()));
01475 }
01476 break;
01477
01478 default:
01479 parseLiteralC(inWords);
01480 break;
01481 }
01482 }
01483 }
01484
01485
01486 while (!inWords.isEmpty () && inWords[0] != ')')
01487 {
01488
01489 if (inWords[0] == '(')
01490 parseSentence (inWords);
01491 else
01492 parseLiteralC(inWords);
01493 }
01494
01495 if (inWords[0] != ')')
01496 return;
01497 inWords.pos++;
01498 skipWS (inWords);
01499 }
01500
01501
01502
01503 void imapParser::parseSentence (parseString & inWords)
01504 {
01505 bool first = true;
01506 int stack = 0;
01507
01508
01509
01510 while (!inWords.isEmpty () && (stack != 0 || first))
01511 {
01512 first = false;
01513 skipWS (inWords);
01514
01515 unsigned char ch = inWords[0];
01516 switch (ch)
01517 {
01518 case '(':
01519 inWords.pos++;
01520 ++stack;
01521 break;
01522 case ')':
01523 inWords.pos++;
01524 --stack;
01525 break;
01526 case '[':
01527 inWords.pos++;
01528 ++stack;
01529 break;
01530 case ']':
01531 inWords.pos++;
01532 --stack;
01533 break;
01534 default:
01535 parseLiteralC(inWords);
01536 skipWS (inWords);
01537 break;
01538 }
01539 }
01540 skipWS (inWords);
01541 }
01542
01543 void imapParser::parseRecent (ulong value, parseString & result)
01544 {
01545 selectInfo.setRecent (value);
01546 result.pos = result.data.size();
01547 }
01548
01549 void imapParser::parseNamespace (parseString & result)
01550 {
01551 if ( result[0] != '(' )
01552 return;
01553
01554 QString delimEmpty;
01555 if ( namespaceToDelimiter.contains( QString::null ) )
01556 delimEmpty = namespaceToDelimiter[QString::null];
01557
01558 namespaceToDelimiter.clear();
01559 imapNamespaces.clear();
01560
01561
01562 int ns = -1;
01563 bool personalAvailable = false;
01564 while ( !result.isEmpty() )
01565 {
01566 if ( result[0] == '(' )
01567 {
01568 result.pos++;
01569 if ( result[0] == '(' )
01570 {
01571
01572 result.pos++;
01573 ++ns;
01574 }
01575
01576 QCString prefix = parseOneWordC( result );
01577
01578 QCString delim = parseOneWordC( result );
01579 kdDebug(7116) << "imapParser::parseNamespace ns='" << prefix <<
01580 "',delim='" << delim << "'" << endl;
01581 if ( ns == 0 )
01582 {
01583
01584 personalAvailable = true;
01585 }
01586 QString nsentry = QString::number( ns ) + "=" + QString(prefix) +
01587 "=" + QString(delim);
01588 imapNamespaces.append( nsentry );
01589 if ( prefix.right( 1 ) == delim ) {
01590
01591 prefix.resize( prefix.length() );
01592 }
01593 namespaceToDelimiter[prefix] = delim;
01594
01595 result.pos++;
01596 skipWS( result );
01597 } else if ( result[0] == ')' )
01598 {
01599 result.pos++;
01600 skipWS( result );
01601 } else if ( result[0] == 'N' )
01602 {
01603
01604 ++ns;
01605 parseOneWord( result );
01606 } else {
01607
01608 parseOneWord( result );
01609 }
01610 }
01611 if ( !delimEmpty.isEmpty() ) {
01612
01613 namespaceToDelimiter[QString::null] = delimEmpty;
01614 if ( !personalAvailable )
01615 {
01616
01617 kdDebug(7116) << "imapParser::parseNamespace - registering own personal ns" << endl;
01618 QString nsentry = "0==" + delimEmpty;
01619 imapNamespaces.append( nsentry );
01620 }
01621 }
01622 }
01623
01624 int imapParser::parseLoop ()
01625 {
01626 parseString result;
01627
01628 if (!parseReadLine(result.data)) return -1;
01629
01630
01631
01632 if (result.data.isEmpty())
01633 return 0;
01634 if (!sentQueue.count ())
01635 {
01636
01637 kdDebug(7116) << "imapParser::parseLoop - unhandledResponse: \n" << result.cstr() << endl;
01638 unhandled << result.cstr();
01639 }
01640 else
01641 {
01642 imapCommand *current = sentQueue.at (0);
01643 switch (result[0])
01644 {
01645 case '*':
01646 result.data.resize(result.data.size() - 2);
01647 parseUntagged (result);
01648 break;
01649 case '+':
01650 continuation.duplicate(result.data);
01651 break;
01652 default:
01653 {
01654 QCString tag = parseLiteralC(result);
01655 if (current->id() == tag.data())
01656 {
01657 result.data.resize(result.data.size() - 2);
01658 QByteArray resultCode = parseLiteral (result);
01659 current->setResult (resultCode);
01660 current->setResultInfo(result.cstr());
01661 current->setComplete ();
01662
01663 sentQueue.removeRef (current);
01664 completeQueue.append (current);
01665 if (result.length())
01666 parseResult (resultCode, result, current->command());
01667 }
01668 else
01669 {
01670 kdDebug(7116) << "imapParser::parseLoop - unknown tag '" << tag << "'" << endl;
01671 QCString cstr = tag + " " + result.cstr();
01672 result.data = cstr;
01673 result.pos = 0;
01674 result.data.resize(cstr.length());
01675 }
01676 }
01677 break;
01678 }
01679 }
01680
01681 return 1;
01682 }
01683
01684 void
01685 imapParser::parseRelay (const QByteArray & buffer)
01686 {
01687 Q_UNUSED(buffer);
01688 qWarning
01689 ("imapParser::parseRelay - virtual function not reimplemented - data lost");
01690 }
01691
01692 void
01693 imapParser::parseRelay (ulong len)
01694 {
01695 Q_UNUSED(len);
01696 qWarning
01697 ("imapParser::parseRelay - virtual function not reimplemented - announcement lost");
01698 }
01699
01700 bool imapParser::parseRead (QByteArray & buffer, ulong len, ulong relay)
01701 {
01702 Q_UNUSED(buffer);
01703 Q_UNUSED(len);
01704 Q_UNUSED(relay);
01705 qWarning
01706 ("imapParser::parseRead - virtual function not reimplemented - no data read");
01707 return FALSE;
01708 }
01709
01710 bool imapParser::parseReadLine (QByteArray & buffer, ulong relay)
01711 {
01712 Q_UNUSED(buffer);
01713 Q_UNUSED(relay);
01714 qWarning
01715 ("imapParser::parseReadLine - virtual function not reimplemented - no data read");
01716 return FALSE;
01717 }
01718
01719 void
01720 imapParser::parseWriteLine (const QString & str)
01721 {
01722 Q_UNUSED(str);
01723 qWarning
01724 ("imapParser::parseWriteLine - virtual function not reimplemented - no data written");
01725 }
01726
01727 void
01728 imapParser::parseURL (const KURL & _url, QString & _box, QString & _section,
01729 QString & _type, QString & _uid, QString & _validity, QString & _info)
01730 {
01731 QStringList parameters;
01732
01733 _box = _url.path ();
01734 kdDebug(7116) << "imapParser::parseURL " << _box << endl;
01735 int paramStart = _box.find("/;");
01736 if ( paramStart > -1 )
01737 {
01738 QString paramString = _box.right( _box.length() - paramStart-2 );
01739 parameters = QStringList::split (';', paramString);
01740 _box.truncate( paramStart );
01741 }
01742
01743 for (QStringList::ConstIterator it (parameters.begin ());
01744 it != parameters.end (); ++it)
01745 {
01746 QString temp = (*it);
01747
01748
01749 int pt = temp.find ('/');
01750 if (pt > 0)
01751 temp.truncate(pt);
01752 if (temp.find ("section=", 0, false) == 0)
01753 _section = temp.right (temp.length () - 8);
01754 else if (temp.find ("type=", 0, false) == 0)
01755 _type = temp.right (temp.length () - 5);
01756 else if (temp.find ("uid=", 0, false) == 0)
01757 _uid = temp.right (temp.length () - 4);
01758 else if (temp.find ("uidvalidity=", 0, false) == 0)
01759 _validity = temp.right (temp.length () - 12);
01760 else if (temp.find ("info=", 0, false) == 0)
01761 _info = temp.right (temp.length () - 5);
01762 }
01763
01764
01765
01766
01767
01768 if (!_box.isEmpty ())
01769 {
01770
01771 if (_box[0] == '/')
01772 _box = _box.right (_box.length () - 1);
01773 if (!_box.isEmpty () && _box[_box.length () - 1] == '/')
01774 _box.truncate(_box.length() - 1);
01775 }
01776 kdDebug(7116) << "URL: box= " << _box << ", section= " << _section << ", type= "
01777 << _type << ", uid= " << _uid << ", validity= " << _validity << ", info= " << _info << endl;
01778 }
01779
01780
01781 QCString imapParser::parseLiteralC(parseString & inWords, bool relay, bool stopAtBracket, int *outlen) {
01782
01783 if (inWords[0] == '{')
01784 {
01785 QCString retVal;
01786 ulong runLen = inWords.find ('}', 1);
01787 if (runLen > 0)
01788 {
01789 bool proper;
01790 ulong runLenSave = runLen + 1;
01791 QCString tmpstr(runLen);
01792 inWords.takeMidNoResize(tmpstr, 1, runLen - 1);
01793 runLen = tmpstr.toULong (&proper);
01794 inWords.pos += runLenSave;
01795 if (proper)
01796 {
01797
01798 if (relay)
01799 parseRelay (runLen);
01800 QByteArray rv;
01801 parseRead (rv, runLen, relay ? runLen : 0);
01802 rv.resize(QMAX(runLen, rv.size()));
01803 retVal = b2c(rv);
01804 inWords.clear();
01805 parseReadLine (inWords.data);
01806
01807
01808 relay = false;
01809 }
01810 else
01811 {
01812 kdDebug(7116) << "imapParser::parseLiteral - error parsing {} - " << endl;
01813 }
01814 }
01815 else
01816 {
01817 inWords.clear();
01818 kdDebug(7116) << "imapParser::parseLiteral - error parsing unmatched {" << endl;
01819 }
01820 if (outlen) {
01821 *outlen = retVal.length();
01822 }
01823 skipWS (inWords);
01824 return retVal;
01825 }
01826
01827 return parseOneWordC(inWords, stopAtBracket, outlen);
01828 }
01829
01830
01831 QCString imapParser::parseOneWordC (parseString & inWords, bool stopAtBracket, int *outLen)
01832 {
01833 uint retValSize = 0;
01834 uint len = inWords.length();
01835 if (len == 0) {
01836 return QCString();
01837 }
01838
01839 if (len > 0 && inWords[0] == '"')
01840 {
01841 unsigned int i = 1;
01842 bool quote = FALSE;
01843 while (i < len && (inWords[i] != '"' || quote))
01844 {
01845 if (inWords[i] == '\\') quote = !quote;
01846 else quote = FALSE;
01847 i++;
01848 }
01849 if (i < len)
01850 {
01851 QCString retVal(i);
01852 inWords.pos++;
01853 inWords.takeLeftNoResize(retVal, i - 1);
01854 len = i - 1;
01855 int offset = 0;
01856 for (unsigned int j = 0; j <= len; j++) {
01857 if (retVal[j] == '\\') {
01858 offset++;
01859 j++;
01860 }
01861 retVal[j - offset] = retVal[j];
01862 }
01863 retVal[len - offset] = 0;
01864 retValSize = len - offset;
01865 inWords.pos += i;
01866 skipWS (inWords);
01867 if (outLen) {
01868 *outLen = retValSize;
01869 }
01870 return retVal;
01871 }
01872 else
01873 {
01874 kdDebug(7116) << "imapParser::parseOneWord - error parsing unmatched \"" << endl;
01875 QCString retVal = inWords.cstr();
01876 retValSize = len;
01877 inWords.clear();
01878 if (outLen) {
01879 *outLen = retValSize;
01880 }
01881 return retVal;
01882 }
01883 }
01884 else
01885 {
01886
01887 unsigned int i;
01888
01889 for (i = 0; i < len; ++i) {
01890 char ch = inWords[i];
01891 if (ch <= ' ' || ch == '(' || ch == ')' ||
01892 (stopAtBracket && (ch == '[' || ch == ']')))
01893 break;
01894 }
01895
01896 QCString retVal(i+1);
01897 inWords.takeLeftNoResize(retVal, i);
01898 retValSize = i;
01899 inWords.pos += i;
01900
01901 if (retVal == "NIL") {
01902 retVal.truncate(0);
01903 retValSize = 0;
01904 }
01905 skipWS (inWords);
01906 if (outLen) {
01907 *outLen = retValSize;
01908 }
01909 return retVal;
01910 }
01911 }
01912
01913 bool imapParser::parseOneNumber (parseString & inWords, ulong & num)
01914 {
01915 bool valid;
01916 num = parseOneWordC(inWords, TRUE).toULong(&valid);
01917 return valid;
01918 }
01919
01920 bool imapParser::hasCapability (const QString & cap)
01921 {
01922 QString c = cap.lower();
01923
01924 for (QStringList::ConstIterator it = imapCapabilities.begin ();
01925 it != imapCapabilities.end (); ++it)
01926 {
01927
01928 if ( !(kasciistricmp(c.ascii(), (*it).ascii())) )
01929 {
01930 return true;
01931 }
01932 }
01933 return false;
01934 }
01935
01936 void imapParser::removeCapability (const QString & cap)
01937 {
01938 imapCapabilities.remove(cap.lower());
01939 }
01940
01941 QString imapParser::namespaceForBox( const QString & box )
01942 {
01943 kdDebug(7116) << "imapParse::namespaceForBox " << box << endl;
01944 QString myNamespace;
01945 if ( !box.isEmpty() )
01946 {
01947 QValueList<QString> list = namespaceToDelimiter.keys();
01948 QString cleanPrefix;
01949 for ( QValueList<QString>::Iterator it = list.begin(); it != list.end(); ++it )
01950 {
01951 if ( !(*it).isEmpty() && box.find( *it ) != -1 )
01952 return (*it);
01953 }
01954 }
01955 return myNamespace;
01956 }
01957