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