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