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(), *this);
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 QCString l1 = parseLiteralC(inWords);
00953 QCString l2 = parseLiteralC(inWords);
00954 retVal.insert (l1, new QString(l2));
00955 }
00956
00957 if (inWords[0] != ')')
00958 return retVal;
00959 inWords.pos++;
00960 skipWS (inWords);
00961 }
00962
00963 return retVal;
00964 }
00965
00966 mimeHeader * imapParser::parseSimplePart (parseString & inWords,
00967 QString & inSection, mimeHeader * localPart)
00968 {
00969 QCString subtype;
00970 QCString typeStr;
00971 QAsciiDict < QString > parameters (17, false);
00972 ulong size;
00973
00974 parameters.setAutoDelete (true);
00975
00976 if (inWords[0] != '(')
00977 return 0;
00978
00979 if (!localPart)
00980 localPart = new mimeHeader;
00981
00982 localPart->setPartSpecifier (inSection);
00983
00984 inWords.pos++;
00985 skipWS (inWords);
00986
00987
00988 typeStr = parseLiteralC(inWords);
00989
00990
00991 subtype = parseLiteralC(inWords);
00992
00993 localPart->setType (typeStr + "/" + subtype);
00994
00995
00996 parameters = parseParameters (inWords);
00997 {
00998 QAsciiDictIterator < QString > it (parameters);
00999
01000 while (it.current ())
01001 {
01002 localPart->setTypeParm (it.currentKey (), *(it.current ()));
01003 ++it;
01004 }
01005 parameters.clear ();
01006 }
01007
01008
01009 localPart->setID (parseLiteralC(inWords));
01010
01011
01012 localPart->setDescription (parseLiteralC(inWords));
01013
01014
01015 localPart->setEncoding (parseLiteralC(inWords));
01016
01017
01018 if (parseOneNumber (inWords, size))
01019 localPart->setLength (size);
01020
01021
01022 if (localPart->getType().upper() == "MESSAGE/RFC822")
01023 {
01024
01025 mailHeader *envelope = parseEnvelope (inWords);
01026
01027
01028 parseBodyStructure (inWords, inSection, envelope);
01029
01030 localPart->setNestedMessage (envelope);
01031
01032
01033 ulong lines;
01034 parseOneNumber (inWords, lines);
01035 }
01036 else
01037 {
01038 if (typeStr == "TEXT")
01039 {
01040
01041 ulong lines;
01042 parseOneNumber (inWords, lines);
01043 }
01044
01045
01046 parseLiteralC(inWords);
01047
01048
01049 parameters = parseDisposition (inWords);
01050 {
01051 QString *disposition = parameters["content-disposition"];
01052
01053 if (disposition)
01054 localPart->setDisposition (disposition->ascii ());
01055 parameters.remove ("content-disposition");
01056 QAsciiDictIterator < QString > it (parameters);
01057 while (it.current ())
01058 {
01059 localPart->setDispositionParm (it.currentKey (),
01060 *(it.current ()));
01061 ++it;
01062 }
01063 parameters.clear ();
01064 }
01065
01066
01067 parseSentence (inWords);
01068 }
01069
01070
01071 while (!inWords.isEmpty () && inWords[0] != ')')
01072 {
01073
01074 if (inWords[0] == '(')
01075 parseSentence (inWords);
01076 else
01077 parseLiteralC(inWords);
01078 }
01079
01080 if (inWords[0] == ')')
01081 inWords.pos++;
01082 skipWS (inWords);
01083
01084 return localPart;
01085 }
01086
01087 mimeHeader * imapParser::parseBodyStructure (parseString & inWords,
01088 QString & inSection, mimeHeader * localPart)
01089 {
01090 bool init = false;
01091 if (inSection.isEmpty())
01092 {
01093
01094 init = true;
01095
01096 inSection = "1";
01097 }
01098 int section = 0;
01099
01100 if (inWords[0] != '(')
01101 {
01102
01103 parseOneWord (inWords);
01104 return 0;
01105 }
01106 inWords.pos++;
01107 skipWS (inWords);
01108
01109 if (inWords[0] == '(')
01110 {
01111 QByteArray subtype;
01112 QAsciiDict < QString > parameters (17, false);
01113 QString outSection;
01114 parameters.setAutoDelete (true);
01115 if (!localPart)
01116 localPart = new mimeHeader;
01117 else
01118 {
01119
01120 localPart->clearNestedParts ();
01121 localPart->clearTypeParameters ();
01122 localPart->clearDispositionParameters ();
01123
01124 outSection = inSection + ".HEADER";
01125 }
01126 if (inWords[0] == '(' && init)
01127 inSection = "0";
01128
01129
01130 if ( !outSection.isEmpty() ) {
01131 localPart->setPartSpecifier(outSection);
01132 } else {
01133 localPart->setPartSpecifier(inSection);
01134 }
01135
01136
01137 while (inWords[0] == '(')
01138 {
01139 outSection = QString::number(++section);
01140 if (!init)
01141 outSection = inSection + "." + outSection;
01142 mimeHeader *subpart = parseBodyStructure (inWords, outSection, 0);
01143 localPart->addNestedPart (subpart);
01144 }
01145
01146
01147 subtype = parseOneWord (inWords);
01148
01149 localPart->setType ("MULTIPART/" + b2c(subtype));
01150
01151
01152 parameters = parseParameters (inWords);
01153 {
01154 QAsciiDictIterator < QString > it (parameters);
01155
01156 while (it.current ())
01157 {
01158 localPart->setTypeParm (it.currentKey (), *(it.current ()));
01159 ++it;
01160 }
01161 parameters.clear ();
01162 }
01163
01164
01165 parameters = parseDisposition (inWords);
01166 {
01167 QString *disposition = parameters["content-disposition"];
01168
01169 if (disposition)
01170 localPart->setDisposition (disposition->ascii ());
01171 parameters.remove ("content-disposition");
01172 QAsciiDictIterator < QString > it (parameters);
01173 while (it.current ())
01174 {
01175 localPart->setDispositionParm (it.currentKey (),
01176 *(it.current ()));
01177 ++it;
01178 }
01179 parameters.clear ();
01180 }
01181
01182
01183 parseSentence (inWords);
01184
01185 }
01186 else
01187 {
01188
01189 inWords.pos--;
01190 inWords.data[inWords.pos] = '(';
01191 if ( localPart )
01192 inSection = inSection + ".1";
01193 localPart = parseSimplePart (inWords, inSection, localPart);
01194 inWords.pos--;
01195 inWords.data[inWords.pos] = ')';
01196 }
01197
01198
01199 while (!inWords.isEmpty () && inWords[0] != ')')
01200 {
01201
01202 if (inWords[0] == '(')
01203 parseSentence (inWords);
01204 else
01205 parseLiteralC(inWords);
01206 }
01207
01208 if (inWords[0] == ')')
01209 inWords.pos++;
01210 skipWS (inWords);
01211
01212 return localPart;
01213 }
01214
01215 void imapParser::parseBody (parseString & inWords)
01216 {
01217
01218 if (inWords[0] == '[')
01219 {
01220 QByteArray specifier;
01221 QByteArray label;
01222 inWords.pos++;
01223
01224 specifier = parseOneWord (inWords, TRUE);
01225
01226 if (inWords[0] == '(')
01227 {
01228 inWords.pos++;
01229
01230 while (!inWords.isEmpty () && inWords[0] != ')')
01231 {
01232 label = parseOneWord (inWords);
01233 }
01234
01235 if (inWords[0] == ')')
01236 inWords.pos++;
01237 }
01238 if (inWords[0] == ']')
01239 inWords.pos++;
01240 skipWS (inWords);
01241
01242
01243 if (qstrncmp(specifier, "0", specifier.size()) == 0)
01244 {
01245 mailHeader *envelope = 0;
01246 if (lastHandled)
01247 envelope = lastHandled->getHeader ();
01248
01249 if (!envelope || seenUid.isEmpty ())
01250 {
01251 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01252
01253 parseLiteralC(inWords, true);
01254 }
01255 else
01256 {
01257 kdDebug(7116) << "imapParser::parseBody - reading " << envelope << " " << seenUid.ascii () << endl;
01258
01259 QString theHeader = parseLiteralC(inWords, true);
01260 mimeIOQString myIO;
01261
01262 myIO.setString (theHeader);
01263 envelope->parseHeader (myIO);
01264
01265 }
01266 }
01267 else if (qstrncmp(specifier, "HEADER.FIELDS", specifier.size()) == 0)
01268 {
01269
01270
01271
01272 if (qstrncmp(label, "REFERENCES", label.size()) == 0)
01273 {
01274 mailHeader *envelope = 0;
01275 if (lastHandled)
01276 envelope = lastHandled->getHeader ();
01277
01278 if (!envelope || seenUid.isEmpty ())
01279 {
01280 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01281
01282 parseLiteralC (inWords, true);
01283 }
01284 else
01285 {
01286 QCString references = parseLiteralC(inWords, true);
01287 int start = references.find ('<');
01288 int end = references.findRev ('>');
01289 if (start < end)
01290 references = references.mid (start, end - start + 1);
01291 envelope->setReferences(references.simplifyWhiteSpace());
01292 }
01293 }
01294 else
01295 {
01296 parseLiteralC(inWords, true);
01297 }
01298 }
01299 else
01300 {
01301 QCString spec(specifier.data(), specifier.size()+1);
01302 if (spec.find(".MIME") != -1)
01303 {
01304 mailHeader *envelope = new mailHeader;
01305 QString theHeader = parseLiteralC(inWords, false);
01306 mimeIOQString myIO;
01307 myIO.setString (theHeader);
01308 envelope->parseHeader (myIO);
01309 if (lastHandled)
01310 lastHandled->setHeader (envelope);
01311 return;
01312 }
01313
01314 kdDebug(7116) << "imapParser::parseBody - discarding " << seenUid.ascii () << endl;
01315 parseLiteralC(inWords, true);
01316 }
01317
01318 }
01319 else
01320 {
01321 mailHeader *envelope = 0;
01322 if (lastHandled)
01323 envelope = lastHandled->getHeader ();
01324
01325 if (!envelope || seenUid.isEmpty ())
01326 {
01327 kdDebug(7116) << "imapParser::parseBody - discarding " << envelope << " " << seenUid.ascii () << endl;
01328
01329 parseSentence (inWords);
01330 }
01331 else
01332 {
01333 kdDebug(7116) << "imapParser::parseBody - reading " << envelope << " " << seenUid.ascii () << endl;
01334
01335 QString section;
01336 mimeHeader *body = parseBodyStructure (inWords, section, envelope);
01337 if (body != envelope)
01338 delete body;
01339 }
01340 }
01341 }
01342
01343 void imapParser::parseFetch (ulong , parseString & inWords)
01344 {
01345 if (inWords[0] != '(')
01346 return;
01347 inWords.pos++;
01348 skipWS (inWords);
01349
01350 delete lastHandled;
01351 lastHandled = 0;
01352
01353 while (!inWords.isEmpty () && inWords[0] != ')')
01354 {
01355 if (inWords[0] == '(')
01356 parseSentence (inWords);
01357 else
01358 {
01359 QCString word = parseLiteralC(inWords, false, true);
01360
01361 switch (word[0])
01362 {
01363 case 'E':
01364 if (word == "ENVELOPE")
01365 {
01366 mailHeader *envelope = 0;
01367
01368 if (lastHandled)
01369 envelope = lastHandled->getHeader ();
01370 else
01371 lastHandled = new imapCache();
01372
01373 if (envelope && !envelope->getMessageId ().isEmpty ())
01374 {
01375
01376
01377 parseSentence (inWords);
01378 }
01379 else
01380 {
01381 envelope = parseEnvelope (inWords);
01382 if (envelope)
01383 {
01384 envelope->setPartSpecifier (seenUid + ".0");
01385 lastHandled->setHeader (envelope);
01386 lastHandled->setUid (seenUid.toULong ());
01387 }
01388 }
01389 }
01390 break;
01391
01392 case 'B':
01393 if (word == "BODY")
01394 {
01395 parseBody (inWords);
01396 }
01397 else if (word == "BODY[]" )
01398 {
01399
01400 parseLiteralC(inWords, true);
01401 }
01402 else if (word == "BODYSTRUCTURE")
01403 {
01404 mailHeader *envelope = 0;
01405
01406 if (lastHandled)
01407 envelope = lastHandled->getHeader ();
01408
01409
01410 QString section;
01411 mimeHeader *body =
01412 parseBodyStructure (inWords, section, envelope);
01413 QByteArray data;
01414 QDataStream stream( data, IO_WriteOnly );
01415 body->serialize(stream);
01416 parseRelay(data);
01417
01418 delete body;
01419 }
01420 break;
01421
01422 case 'U':
01423 if (word == "UID")
01424 {
01425 seenUid = parseOneWordC(inWords);
01426 mailHeader *envelope = 0;
01427 if (lastHandled)
01428 envelope = lastHandled->getHeader ();
01429 else
01430 lastHandled = new imapCache();
01431
01432 if (seenUid.isEmpty ())
01433 {
01434
01435 kdDebug(7116) << "imapParser::parseFetch - UID empty" << endl;
01436 }
01437 else
01438 {
01439 lastHandled->setUid (seenUid.toULong ());
01440 }
01441 if (envelope)
01442 envelope->setPartSpecifier (seenUid);
01443 }
01444 break;
01445
01446 case 'R':
01447 if (word == "RFC822.SIZE")
01448 {
01449 ulong size;
01450 parseOneNumber (inWords, size);
01451
01452 if (!lastHandled) lastHandled = new imapCache();
01453 lastHandled->setSize (size);
01454 }
01455 else if (word.find ("RFC822") == 0)
01456 {
01457
01458 parseLiteralC(inWords, true);
01459 }
01460 break;
01461
01462 case 'I':
01463 if (word == "INTERNALDATE")
01464 {
01465 QCString date = parseOneWordC(inWords);
01466 if (!lastHandled) lastHandled = new imapCache();
01467 lastHandled->setDate(date);
01468 }
01469 break;
01470
01471 case 'F':
01472 if (word == "FLAGS")
01473 {
01474
01475 if (!lastHandled) lastHandled = new imapCache();
01476 lastHandled->setFlags (imapInfo::_flags (inWords.cstr()));
01477 }
01478 break;
01479
01480 default:
01481 parseLiteralC(inWords);
01482 break;
01483 }
01484 }
01485 }
01486
01487
01488 while (!inWords.isEmpty () && inWords[0] != ')')
01489 {
01490
01491 if (inWords[0] == '(')
01492 parseSentence (inWords);
01493 else
01494 parseLiteralC(inWords);
01495 }
01496
01497 if (inWords[0] != ')')
01498 return;
01499 inWords.pos++;
01500 skipWS (inWords);
01501 }
01502
01503
01504
01505 void imapParser::parseSentence (parseString & inWords)
01506 {
01507 bool first = true;
01508 int stack = 0;
01509
01510
01511
01512 while (!inWords.isEmpty () && (stack != 0 || first))
01513 {
01514 first = false;
01515 skipWS (inWords);
01516
01517 unsigned char ch = inWords[0];
01518 switch (ch)
01519 {
01520 case '(':
01521 inWords.pos++;
01522 ++stack;
01523 break;
01524 case ')':
01525 inWords.pos++;
01526 --stack;
01527 break;
01528 case '[':
01529 inWords.pos++;
01530 ++stack;
01531 break;
01532 case ']':
01533 inWords.pos++;
01534 --stack;
01535 break;
01536 default:
01537 parseLiteralC(inWords);
01538 skipWS (inWords);
01539 break;
01540 }
01541 }
01542 skipWS (inWords);
01543 }
01544
01545 void imapParser::parseRecent (ulong value, parseString & result)
01546 {
01547 selectInfo.setRecent (value);
01548 result.pos = result.data.size();
01549 }
01550
01551 void imapParser::parseNamespace (parseString & result)
01552 {
01553 if ( result[0] != '(' )
01554 return;
01555
01556 QString delimEmpty;
01557 if ( namespaceToDelimiter.contains( QString::null ) )
01558 delimEmpty = namespaceToDelimiter[QString::null];
01559
01560 namespaceToDelimiter.clear();
01561 imapNamespaces.clear();
01562
01563
01564 int ns = -1;
01565 bool personalAvailable = false;
01566 while ( !result.isEmpty() )
01567 {
01568 if ( result[0] == '(' )
01569 {
01570 result.pos++;
01571 if ( result[0] == '(' )
01572 {
01573
01574 result.pos++;
01575 ++ns;
01576 }
01577
01578 QCString prefix = parseOneWordC( result );
01579
01580 QCString delim = parseOneWordC( result );
01581 kdDebug(7116) << "imapParser::parseNamespace ns='" << prefix <<
01582 "',delim='" << delim << "'" << endl;
01583 if ( ns == 0 )
01584 {
01585
01586 personalAvailable = true;
01587 }
01588 QString nsentry = QString::number( ns ) + "=" + QString(prefix) +
01589 "=" + QString(delim);
01590 imapNamespaces.append( nsentry );
01591 if ( prefix.right( 1 ) == delim ) {
01592
01593 prefix.resize( prefix.length() );
01594 }
01595 namespaceToDelimiter[prefix] = delim;
01596
01597 result.pos++;
01598 skipWS( result );
01599 } else if ( result[0] == ')' )
01600 {
01601 result.pos++;
01602 skipWS( result );
01603 } else if ( result[0] == 'N' )
01604 {
01605
01606 ++ns;
01607 parseOneWord( result );
01608 } else {
01609
01610 parseOneWord( result );
01611 }
01612 }
01613 if ( !delimEmpty.isEmpty() ) {
01614
01615 namespaceToDelimiter[QString::null] = delimEmpty;
01616 if ( !personalAvailable )
01617 {
01618
01619 kdDebug(7116) << "imapParser::parseNamespace - registering own personal ns" << endl;
01620 QString nsentry = "0==" + delimEmpty;
01621 imapNamespaces.append( nsentry );
01622 }
01623 }
01624 }
01625
01626 int imapParser::parseLoop ()
01627 {
01628 parseString result;
01629
01630 if (!parseReadLine(result.data)) return -1;
01631
01632
01633
01634 if (result.data.isEmpty())
01635 return 0;
01636 if (!sentQueue.count ())
01637 {
01638
01639 kdDebug(7116) << "imapParser::parseLoop - unhandledResponse: \n" << result.cstr() << endl;
01640 unhandled << result.cstr();
01641 }
01642 else
01643 {
01644 imapCommand *current = sentQueue.at (0);
01645 switch (result[0])
01646 {
01647 case '*':
01648 result.data.resize(result.data.size() - 2);
01649 parseUntagged (result);
01650 break;
01651 case '+':
01652 continuation.duplicate(result.data);
01653 break;
01654 default:
01655 {
01656 QCString tag = parseLiteralC(result);
01657 if (current->id() == tag.data())
01658 {
01659 result.data.resize(result.data.size() - 2);
01660 QByteArray resultCode = parseLiteral (result);
01661 current->setResult (resultCode);
01662 current->setResultInfo(result.cstr());
01663 current->setComplete ();
01664
01665 sentQueue.removeRef (current);
01666 completeQueue.append (current);
01667 if (result.length())
01668 parseResult (resultCode, result, current->command());
01669 }
01670 else
01671 {
01672 kdDebug(7116) << "imapParser::parseLoop - unknown tag '" << tag << "'" << endl;
01673 QCString cstr = tag + " " + result.cstr();
01674 result.data = cstr;
01675 result.pos = 0;
01676 result.data.resize(cstr.length());
01677 }
01678 }
01679 break;
01680 }
01681 }
01682
01683 return 1;
01684 }
01685
01686 void
01687 imapParser::parseRelay (const QByteArray & buffer)
01688 {
01689 Q_UNUSED(buffer);
01690 qWarning
01691 ("imapParser::parseRelay - virtual function not reimplemented - data lost");
01692 }
01693
01694 void
01695 imapParser::parseRelay (ulong len)
01696 {
01697 Q_UNUSED(len);
01698 qWarning
01699 ("imapParser::parseRelay - virtual function not reimplemented - announcement lost");
01700 }
01701
01702 bool imapParser::parseRead (QByteArray & buffer, ulong len, ulong relay)
01703 {
01704 Q_UNUSED(buffer);
01705 Q_UNUSED(len);
01706 Q_UNUSED(relay);
01707 qWarning
01708 ("imapParser::parseRead - virtual function not reimplemented - no data read");
01709 return FALSE;
01710 }
01711
01712 bool imapParser::parseReadLine (QByteArray & buffer, ulong relay)
01713 {
01714 Q_UNUSED(buffer);
01715 Q_UNUSED(relay);
01716 qWarning
01717 ("imapParser::parseReadLine - virtual function not reimplemented - no data read");
01718 return FALSE;
01719 }
01720
01721 void
01722 imapParser::parseWriteLine (const QString & str)
01723 {
01724 Q_UNUSED(str);
01725 qWarning
01726 ("imapParser::parseWriteLine - virtual function not reimplemented - no data written");
01727 }
01728
01729 void
01730 imapParser::parseURL (const KURL & _url, QString & _box, QString & _section,
01731 QString & _type, QString & _uid, QString & _validity, QString & _info)
01732 {
01733 QStringList parameters;
01734
01735 _box = _url.path ();
01736 kdDebug(7116) << "imapParser::parseURL " << _box << endl;
01737 int paramStart = _box.find("/;");
01738 if ( paramStart > -1 )
01739 {
01740 QString paramString = _box.right( _box.length() - paramStart-2 );
01741 parameters = QStringList::split (';', paramString);
01742 _box.truncate( paramStart );
01743 }
01744
01745 for (QStringList::ConstIterator it (parameters.begin ());
01746 it != parameters.end (); ++it)
01747 {
01748 QString temp = (*it);
01749
01750
01751 int pt = temp.find ('/');
01752 if (pt > 0)
01753 temp.truncate(pt);
01754 if (temp.find ("section=", 0, false) == 0)
01755 _section = temp.right (temp.length () - 8);
01756 else if (temp.find ("type=", 0, false) == 0)
01757 _type = temp.right (temp.length () - 5);
01758 else if (temp.find ("uid=", 0, false) == 0)
01759 _uid = temp.right (temp.length () - 4);
01760 else if (temp.find ("uidvalidity=", 0, false) == 0)
01761 _validity = temp.right (temp.length () - 12);
01762 else if (temp.find ("info=", 0, false) == 0)
01763 _info = temp.right (temp.length () - 5);
01764 }
01765
01766
01767
01768
01769
01770 if (!_box.isEmpty ())
01771 {
01772
01773 if (_box[0] == '/')
01774 _box = _box.right (_box.length () - 1);
01775 if (!_box.isEmpty () && _box[_box.length () - 1] == '/')
01776 _box.truncate(_box.length() - 1);
01777 }
01778 kdDebug(7116) << "URL: box= " << _box << ", section= " << _section << ", type= "
01779 << _type << ", uid= " << _uid << ", validity= " << _validity << ", info= " << _info << endl;
01780 }
01781
01782
01783 QCString imapParser::parseLiteralC(parseString & inWords, bool relay, bool stopAtBracket, int *outlen) {
01784
01785 if (inWords[0] == '{')
01786 {
01787 QCString retVal;
01788 ulong runLen = inWords.find ('}', 1);
01789 if (runLen > 0)
01790 {
01791 bool proper;
01792 ulong runLenSave = runLen + 1;
01793 QCString tmpstr(runLen);
01794 inWords.takeMidNoResize(tmpstr, 1, runLen - 1);
01795 runLen = tmpstr.toULong (&proper);
01796 inWords.pos += runLenSave;
01797 if (proper)
01798 {
01799
01800 if (relay)
01801 parseRelay (runLen);
01802 QByteArray rv;
01803 parseRead (rv, runLen, relay ? runLen : 0);
01804 rv.resize(QMAX(runLen, rv.size()));
01805 retVal = b2c(rv);
01806 inWords.clear();
01807 parseReadLine (inWords.data);
01808
01809
01810 relay = false;
01811 }
01812 else
01813 {
01814 kdDebug(7116) << "imapParser::parseLiteral - error parsing {} - " << endl;
01815 }
01816 }
01817 else
01818 {
01819 inWords.clear();
01820 kdDebug(7116) << "imapParser::parseLiteral - error parsing unmatched {" << endl;
01821 }
01822 if (outlen) {
01823 *outlen = retVal.length();
01824 }
01825 skipWS (inWords);
01826 return retVal;
01827 }
01828
01829 return parseOneWordC(inWords, stopAtBracket, outlen);
01830 }
01831
01832
01833 QCString imapParser::parseOneWordC (parseString & inWords, bool stopAtBracket, int *outLen)
01834 {
01835 uint retValSize = 0;
01836 uint len = inWords.length();
01837 if (len == 0) {
01838 return QCString();
01839 }
01840
01841 if (len > 0 && inWords[0] == '"')
01842 {
01843 unsigned int i = 1;
01844 bool quote = FALSE;
01845 while (i < len && (inWords[i] != '"' || quote))
01846 {
01847 if (inWords[i] == '\\') quote = !quote;
01848 else quote = FALSE;
01849 i++;
01850 }
01851 if (i < len)
01852 {
01853 QCString retVal(i);
01854 inWords.pos++;
01855 inWords.takeLeftNoResize(retVal, i - 1);
01856 len = i - 1;
01857 int offset = 0;
01858 for (unsigned int j = 0; j <= len; j++) {
01859 if (retVal[j] == '\\') {
01860 offset++;
01861 j++;
01862 }
01863 retVal[j - offset] = retVal[j];
01864 }
01865 retVal[len - offset] = 0;
01866 retValSize = len - offset;
01867 inWords.pos += i;
01868 skipWS (inWords);
01869 if (outLen) {
01870 *outLen = retValSize;
01871 }
01872 return retVal;
01873 }
01874 else
01875 {
01876 kdDebug(7116) << "imapParser::parseOneWord - error parsing unmatched \"" << endl;
01877 QCString retVal = inWords.cstr();
01878 retValSize = len;
01879 inWords.clear();
01880 if (outLen) {
01881 *outLen = retValSize;
01882 }
01883 return retVal;
01884 }
01885 }
01886 else
01887 {
01888
01889 unsigned int i;
01890
01891 for (i = 0; i < len; ++i) {
01892 char ch = inWords[i];
01893 if (ch <= ' ' || ch == '(' || ch == ')' ||
01894 (stopAtBracket && (ch == '[' || ch == ']')))
01895 break;
01896 }
01897
01898 QCString retVal(i+1);
01899 inWords.takeLeftNoResize(retVal, i);
01900 retValSize = i;
01901 inWords.pos += i;
01902
01903 if (retVal == "NIL") {
01904 retVal.truncate(0);
01905 retValSize = 0;
01906 }
01907 skipWS (inWords);
01908 if (outLen) {
01909 *outLen = retValSize;
01910 }
01911 return retVal;
01912 }
01913 }
01914
01915 bool imapParser::parseOneNumber (parseString & inWords, ulong & num)
01916 {
01917 bool valid;
01918 num = parseOneWordC(inWords, TRUE).toULong(&valid);
01919 return valid;
01920 }
01921
01922 bool imapParser::hasCapability (const QString & cap)
01923 {
01924 QString c = cap.lower();
01925
01926 for (QStringList::ConstIterator it = imapCapabilities.begin ();
01927 it != imapCapabilities.end (); ++it)
01928 {
01929
01930 if ( !(kasciistricmp(c.ascii(), (*it).ascii())) )
01931 {
01932 return true;
01933 }
01934 }
01935 return false;
01936 }
01937
01938 void imapParser::removeCapability (const QString & cap)
01939 {
01940 imapCapabilities.remove(cap.lower());
01941 }
01942
01943 QString imapParser::namespaceForBox( const QString & box )
01944 {
01945 kdDebug(7116) << "imapParse::namespaceForBox " << box << endl;
01946 QString myNamespace;
01947 if ( !box.isEmpty() )
01948 {
01949 QValueList<QString> list = namespaceToDelimiter.keys();
01950 QString cleanPrefix;
01951 for ( QValueList<QString>::Iterator it = list.begin(); it != list.end(); ++it )
01952 {
01953 if ( !(*it).isEmpty() && box.find( *it ) != -1 )
01954 return (*it);
01955 }
01956 }
01957 return myNamespace;
01958 }
01959