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