25 #include "imapparser.h"
27 #include "mailheader.h"
28 #include "mimeheader.h"
29 #include "mailaddress.h"
31 #include <sys/types.h>
38 #include <sasl/sasl.h>
44 #include <QStringList>
52 #include <kimap/rfccodecs.h>
53 using namespace KIMAP;
55 static sasl_callback_t callbacks[] = {
56 { SASL_CB_ECHOPROMPT, NULL, NULL },
57 { SASL_CB_NOECHOPROMPT, NULL, NULL },
58 { SASL_CB_GETREALM, NULL, NULL },
59 { SASL_CB_USER, NULL, NULL },
60 { SASL_CB_AUTHNAME, NULL, NULL },
61 { SASL_CB_PASS, NULL, NULL },
62 { SASL_CB_CANON_USER, NULL, NULL },
63 { SASL_CB_LIST_END, NULL, NULL }
66 imapParser::imapParser ()
68 currentState = ISTATE_NO;
73 imapParser::~imapParser ()
80 imapParser::doCommand (CommandPtr aCmd)
84 while ( pl != -1 && !aCmd->isComplete() ) {
85 while ( ( pl = parseLoop() ) == 0 ) {
93 imapParser::sendCommand (CommandPtr aCmd)
96 sentQueue.append( aCmd );
98 continuation.resize( 0 );
99 const QString& command = aCmd->command();
101 if ( command ==
"SELECT" || command ==
"EXAMINE" ) {
104 p.fromString( aCmd->parameter() );
105 currentBox = parseOneWord( p );
106 kDebug( 7116 ) <<
"imapParser::sendCommand - setting current box to" << currentBox;
107 }
else if ( command ==
"CLOSE" ) {
110 }
else if ( command.
contains(
"SEARCH" ) ||
111 command ==
"GETACL" ||
112 command ==
"LISTRIGHTS" ||
113 command ==
"MYRIGHTS" ||
114 command ==
"GETANNOTATION" ||
115 command ==
"NAMESPACE" ||
116 command ==
"GETQUOTAROOT" ||
117 command ==
"GETQUOTA" ||
118 command ==
"X-GET-OTHER-USERS" ||
119 command ==
"X-GET-DELEGATES" ||
120 command ==
"X-GET-OUT-OF-OFFICE" ) {
122 }
else if ( command ==
"LIST" ||
123 command ==
"LSUB" ) {
124 listResponses.clear();
126 parseWriteLine( aCmd->getStr() );
131 imapParser::clientLogin (
const QString & aUser,
const QString & aPass,
137 cmd = doCommand( CommandPtr(
new imapCommand(
"LOGIN",
"\"" + KIMAP::quoteIMAP( aUser ) +
138 "\" \"" + KIMAP::quoteIMAP( aPass ) +
"\"" ) ) );
140 if ( cmd->result() ==
"OK" ) {
141 currentState = ISTATE_LOGIN;
144 resultInfo = cmd->resultInfo();
145 completeQueue.removeAll( cmd );
149 static bool sasl_interact( KIO::SlaveBase *slave, KIO::AuthInfo &ai,
void *in )
151 kDebug( 7116 ) <<
"sasl_interact";
152 sasl_interact_t *interact = ( sasl_interact_t * ) in;
156 for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
157 if ( interact->id == SASL_CB_AUTHNAME ||
158 interact->id == SASL_CB_PASS ) {
160 if ( ai.username.isEmpty() || ai.password.isEmpty() ) {
161 if ( !slave->openPasswordDialog( ai ) ) {
169 interact = ( sasl_interact_t * ) in;
170 while ( interact->id != SASL_CB_LIST_END ) {
171 kDebug( 7116 ) <<
"SASL_INTERACT id:" << interact->id;
172 switch ( interact->id ) {
174 case SASL_CB_AUTHNAME:
175 kDebug( 7116 ) <<
"SASL_CB_[USER|AUTHNAME]: '" << ai.username <<
"'";
176 interact->result = strdup( ai.username.toUtf8() );
177 interact->len = strlen( (
const char *) interact->result );
180 kDebug( 7116 ) <<
"SASL_CB_PASS: [hidden]";
181 interact->result = strdup( ai.password.toUtf8() );
182 interact->len = strlen( (
const char *) interact->result );
185 interact->result = 0;
195 imapParser::clientAuthenticate ( KIO::SlaveBase *slave, KIO::AuthInfo &ai,
200 sasl_conn_t *conn = 0;
201 sasl_interact_t *client_interact = 0;
204 const char *mechusing = 0;
207 kDebug( 7116 ) <<
"aAuth:" << aAuth <<
" FQDN:" << aFQDN <<
" isSSL:" << isSSL;
210 if ( !hasCapability(
"AUTH=" + aAuth ) ) {
215 result = sasl_client_new(
"imap",
218 0, 0, callbacks, 0, &conn );
220 if ( result != SASL_OK ) {
221 kDebug( 7116 ) <<
"sasl_client_new failed with:" << result;
227 result = sasl_client_start( conn, aAuth.
toLatin1(), &client_interact,
228 hasCapability(
"SASL-IR" ) ? &out : 0, &outlen, &mechusing );
230 if ( result == SASL_INTERACT ) {
231 if ( !sasl_interact( slave, ai, client_interact ) ) {
232 sasl_dispose( &conn );
236 }
while ( result == SASL_INTERACT );
238 if ( result != SASL_CONTINUE && result != SASL_OK ) {
239 kDebug( 7116 ) <<
"sasl_client_start failed with:" << result;
241 sasl_dispose( &conn );
255 cmd = sendCommand( CommandPtr(
new imapCommand(
"AUTHENTICATE", firstCommand.
toLatin1() ) ) );
258 while ( pl != -1 && !cmd->isComplete() ) {
260 while ( ( pl = parseLoop() ) == 0 ) {
264 if ( !continuation.isEmpty() ) {
266 if ( continuation.size() > 4 ) {
274 result = sasl_client_step( conn, challenge.isEmpty() ? 0 : challenge.data(),
279 if ( result == SASL_INTERACT ) {
280 if ( !sasl_interact( slave, ai, client_interact ) ) {
281 sasl_dispose( &conn );
285 }
while ( result == SASL_INTERACT );
287 if ( result != SASL_CONTINUE && result != SASL_OK ) {
288 kDebug( 7116 ) <<
"sasl_client_step failed with:" << result;
290 sasl_dispose( &conn );
299 parseWriteLine( challenge );
300 continuation.resize( 0 );
304 if ( cmd->result() ==
"OK" ) {
305 currentState = ISTATE_LOGIN;
308 resultInfo = cmd->resultInfo();
309 completeQueue.removeAll( cmd );
311 sasl_dispose( &conn );
320 parseOneWord( result );
326 if ( qstrncmp( what,
"BAD", what.
size() ) == 0 ) {
327 parseResult( what, result );
328 }
else if ( qstrncmp( what,
"BYE", what.
size() ) == 0 ) {
329 parseResult( what, result );
330 if ( sentQueue.count() ) {
332 CommandPtr current = sentQueue.at( 0 );
333 current->setResultInfo( result.cstr() );
335 currentState = ISTATE_NO;
340 if ( what[1] ==
'O' && what.
size() == 2 ) {
341 parseResult( what, result );
342 }
else if ( qstrncmp( what,
"NAMESPACE", what.
size() ) == 0 ) {
343 parseNamespace( result );
348 if ( what[1] ==
'K' && what.
size() == 2 ) {
349 parseResult( what, result );
350 }
else if ( qstrncmp( what,
"OTHER-USER", 10 ) == 0 ) {
351 parseOtherUser( result );
352 }
else if ( qstrncmp( what,
"OUT-OF-OFFICE", 13 ) == 0 ) {
353 parseOutOfOffice( result );
357 if ( qstrncmp( what,
"DELEGATE", 8 ) == 0 ) {
358 parseDelegate( result );
363 if ( qstrncmp( what,
"PREAUTH", what.
size() ) == 0 ) {
364 parseResult( what, result );
365 currentState = ISTATE_LOGIN;
371 if ( qstrncmp( what,
"CAPABILITY", what.
size() ) == 0 ) {
372 parseCapability( result );
377 if ( qstrncmp( what,
"FLAGS", what.
size() ) == 0 ) {
378 parseFlags( result );
383 if ( qstrncmp( what,
"LIST", what.
size() ) == 0 ) {
385 }
else if ( qstrncmp( what,
"LSUB", what.
size() ) == 0 ) {
387 }
else if ( qstrncmp( what,
"LISTRIGHTS", what.
size() ) == 0 ) {
388 parseListRights( result );
393 if ( qstrncmp( what,
"MYRIGHTS", what.
size() ) == 0 ) {
394 parseMyRights( result );
398 if ( qstrncmp( what,
"SEARCH", what.
size() ) == 0 ) {
399 parseSearch( result );
400 }
else if ( qstrncmp( what,
"STATUS", what.
size() ) == 0 ) {
401 parseStatus( result );
406 if ( qstrncmp( what,
"ACL", what.
size() ) == 0 ) {
408 }
else if ( qstrncmp( what,
"ANNOTATION", what.
size() ) == 0 ) {
409 parseAnnotation( result );
413 if ( what.
size() > 5 && qstrncmp( what,
"QUOTAROOT", what.
size() ) == 0 ) {
414 parseQuotaRoot( result );
415 }
else if ( qstrncmp( what,
"QUOTA", what.
size() ) == 0 ) {
416 parseQuota( result );
421 parseCustom( result );
430 number = what.
toUInt( &valid );
432 what = parseLiteral( result );
435 if ( qstrncmp( what,
"EXISTS", what.
size() ) == 0 ) {
436 parseExists( number, result );
437 }
else if ( qstrncmp( what,
"EXPUNGE", what.
size() ) == 0 ) {
438 parseExpunge( number, result );
443 if ( qstrncmp( what,
"FETCH", what.
size() ) == 0 ) {
445 parseFetch( number, result );
450 if ( qstrncmp( what,
"STORE", what.
size() ) == 0 ) {
452 parseFetch( number, result );
457 if ( qstrncmp( what,
"RECENT", what.
size() ) == 0 ) {
458 parseRecent( number, result );
474 if ( command ==
"SELECT" ) {
475 selectInfo.setReadWrite(
true );
478 if ( rest[0] ==
'[' ) {
480 QByteArray option = parseOneWord( rest,
true );
482 switch ( option[0] ) {
484 if ( option ==
"ALERT" ) {
485 rest.pos = rest.data.
indexOf(
']', rest.pos ) + 1;
488 selectInfo.setAlert( rest.cstr() );
493 if ( option ==
"NEWNAME" ) {
498 if ( option ==
"PARSE" ) {
499 }
else if ( option ==
"PERMANENTFLAGS" ) {
500 uint end = rest.data.
indexOf(
']', rest.pos );
502 selectInfo.setPermanentFlags( flags );
508 if ( option ==
"READ-ONLY" ) {
509 selectInfo.setReadWrite(
false );
510 }
else if ( option ==
"READ-WRITE" ) {
511 selectInfo.setReadWrite(
true );
516 if ( option ==
"TRYCREATE" ) {
521 if ( option ==
"UIDVALIDITY" ) {
523 if ( parseOneNumber( rest, value ) ) {
524 selectInfo.setUidValidity( value );
526 }
else if ( option ==
"UNSEEN" ) {
528 if ( parseOneNumber( rest, value ) ) {
529 selectInfo.setUnseen( value );
531 }
else if ( option ==
"UIDNEXT" ) {
533 if ( parseOneNumber( rest, value ) ) {
534 selectInfo.setUidNext( value );
540 if ( rest[0] ==
']' ) {
552 switch ( command[0].toLatin1() ) {
554 if ( command ==
"AUTHENTICATE" ) {
555 if ( qstrncmp( result,
"OK", result.
size() ) == 0 ) {
556 currentState = ISTATE_LOGIN;
562 if ( command ==
"LOGIN" ) {
563 if ( qstrncmp( result,
"OK", result.
size() ) == 0 ) {
564 currentState = ISTATE_LOGIN;
570 if ( command ==
"EXAMINE" ) {
571 if ( qstrncmp( result,
"OK", result.
size() ) == 0 ) {
572 currentState = ISTATE_SELECT;
574 if ( currentState == ISTATE_SELECT ) {
575 currentState = ISTATE_LOGIN;
579 kDebug( 7116 ) <<
"imapParser::parseResult - current box is now" << currentBox;
584 if ( command ==
"SELECT" ) {
585 if ( qstrncmp( result,
"OK", result.
size() ) == 0 ) {
586 currentState = ISTATE_SELECT;
588 if ( currentState == ISTATE_SELECT ) {
589 currentState = ISTATE_LOGIN;
593 kDebug( 7116 ) <<
"imapParser::parseResult - current box is now" << currentBox;
602 void imapParser::parseCapability (
parseString & result)
605 kAsciiToLower( data.
data() );
611 selectInfo.setFlags( result.cstr() );
618 if ( result[0] !=
'(' ) {
624 this_one.parseAttributes( result );
629 this_one.setHierarchyDelimiter( parseLiteral( result ) );
630 this_one.setName(
QString::fromUtf8( KIMAP::decodeImapFolderName( parseLiteral( result ) ) ) );
632 listResponses.append( this_one );
637 imapList this_one( result.cstr(), *this );
638 listResponses.append( this_one );
641 void imapParser::parseListRights (
parseString & result)
643 parseOneWord( result );
644 parseOneWord( result );
646 const QByteArray word = parseOneWord( result );
650 lastResults.append( word );
656 parseOneWord( result );
658 while ( !result.isEmpty() ) {
659 const QByteArray word = parseLiteral( result );
663 lastResults.append( word );
667 void imapParser::parseAnnotation (
parseString & result)
669 parseOneWord( result );
671 parseOneWord( result );
673 if ( result.isEmpty() || result[0] !=
'(' ) {
679 while ( !result.isEmpty() && result[0] !=
')' ) {
680 const QByteArray word = parseLiteral( result );
684 lastResults.append( word );
695 lastResults.append(
"" );
697 lastResults.append( root );
699 if ( result.isEmpty() || result[0] !=
'(' ) {
705 while ( !result.isEmpty() && result[0] !=
')' ) {
706 const QByteArray word = parseLiteral( result );
712 lastResults.append( triplet.
join(
" " ) );
715 void imapParser::parseQuotaRoot (
parseString & result)
719 parseOneWord( result );
721 if ( result.isEmpty() ) {
725 while ( !result.isEmpty() ) {
726 const QByteArray word = parseLiteral( result );
732 lastResults.append( roots.
isEmpty() ?
"" : roots.
join(
" " ) );
735 void imapParser::parseCustom (
parseString & result)
737 QByteArray word = parseLiteral( result,
false,
false );
738 lastResults.append( word );
741 void imapParser::parseOtherUser (
parseString & result)
743 lastResults.append( parseOneWord( result ) );
746 void imapParser::parseDelegate (
parseString & result)
748 const QString email = parseOneWord( result );
751 while ( !result.isEmpty() ) {
752 QByteArray word = parseLiteral( result,
false,
false );
756 lastResults.append( email +
':' + rights.
join(
"," ) );
759 void imapParser::parseOutOfOffice (
parseString & result)
761 const QString state = parseOneWord( result );
762 parseOneWord( result );
764 QByteArray msg = parseLiteral( result,
false,
false );
769 void imapParser::parseMyRights (
parseString & result)
771 parseOneWord( result );
772 Q_ASSERT( lastResults.isEmpty() );
773 lastResults.append( parseOneWord( result ) );
776 void imapParser::parseSearch (
parseString & result)
780 while ( parseOneNumber( result, value ) ) {
785 void imapParser::parseStatus (
parseString & inWords)
787 lastStatus = imapInfo();
789 parseLiteral( inWords );
790 if ( inWords[0] !=
'(' ) {
797 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
801 if ( parseOneNumber( inWords, value ) ) {
802 if ( label ==
"MESSAGES" ) {
803 lastStatus.setCount( value );
804 }
else if ( label ==
"RECENT" ) {
805 lastStatus.setRecent( value );
806 }
else if ( label ==
"UIDVALIDITY" ) {
807 lastStatus.setUidValidity( value );
808 }
else if ( label ==
"UNSEEN" ) {
809 lastStatus.setUnseen( value );
810 }
else if ( label ==
"UIDNEXT" ) {
811 lastStatus.setUidNext( value );
816 if ( inWords[0] ==
')' ) {
822 void imapParser::parseExists (ulong value,
parseString & result)
824 selectInfo.setCount( value );
825 result.pos = result.data.
size();
828 void imapParser::parseExpunge (ulong value,
parseString & result)
836 if ( inWords.isEmpty() ) {
839 if ( inWords[0] !=
'(' ) {
840 parseOneWord( inWords );
845 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
846 if ( inWords[0] ==
'(' ) {
847 mailAddress *addr =
new mailAddress;
848 parseAddress( inWords, *addr );
855 if ( !inWords.isEmpty() && inWords[0] ==
')' ) {
862 const mailAddress& imapParser::parseAddress (
parseString & inWords, mailAddress& retVal)
867 retVal.setFullName( parseLiteral( inWords ) );
868 retVal.setCommentRaw( parseLiteral( inWords ) );
869 retVal.setUser( parseLiteral( inWords ) );
870 retVal.setHost( parseLiteral( inWords ) );
872 if ( !inWords.isEmpty() && inWords[0] ==
')' ) {
883 if ( inWords[0] !=
'(' ) {
892 envelope->
setDate( parseLiteral( inWords ) );
895 envelope->
setSubject( parseLiteral( inWords ) );
900 parseAddressList( inWords, list );
902 envelope->setFrom( *list.
last() );
907 parseAddressList(inWords, list);
909 envelope->setSender( *list.
last() );
914 parseAddressList( inWords, list );
916 envelope->setReplyTo( *list.
last() );
921 parseAddressList( inWords, envelope->to() );
924 parseAddressList( inWords, envelope->cc() );
927 parseAddressList( inWords, envelope->bcc() );
930 envelope->setInReplyTo( parseLiteral( inWords ) );
933 envelope->setMessageId( parseLiteral( inWords ) );
936 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
938 if ( inWords[0] ==
'(' ) {
939 parseSentence( inWords );
941 parseLiteral( inWords );
945 if ( !inWords.isEmpty() && inWords[0] ==
')' ) {
959 if ( inWords[0] !=
'(' ) {
961 disposition = parseOneWord( inWords );
967 disposition = parseOneWord( inWords );
969 retVal = parseParameters( inWords );
970 if ( inWords[0] !=
')' ) {
977 if ( !disposition.
isEmpty() ) {
978 retVal.
insert(
"content-disposition",
QString( disposition ) );
989 if ( inWords[0] !=
'(' ) {
991 parseOneWord( inWords );
996 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
997 const QByteArray l1 = parseLiteral( inWords );
998 const QByteArray l2 = parseLiteral( inWords );
1002 if ( inWords[0] !=
')' ) {
1019 if ( inWords[0] !=
'(' ) {
1027 localPart->setPartSpecifier( inSection );
1033 typeStr = parseLiteral( inWords );
1036 subtype = parseLiteral( inWords );
1038 localPart->setType( typeStr +
'/' + subtype );
1041 parameters = parseParameters( inWords );
1045 while ( it.hasNext() ) {
1047 localPart->setTypeParm( it.key(), it.value() );
1053 localPart->setID( parseLiteral( inWords ) );
1056 localPart->setDescription( parseLiteral( inWords ) );
1059 localPart->setEncoding( parseLiteral( inWords ) );
1062 if ( parseOneNumber( inWords, size ) ) {
1063 localPart->setLength( size );
1067 if ( localPart->getType().
toUpper() ==
"MESSAGE/RFC822" ) {
1069 mailHeader *envelope = parseEnvelope( inWords );
1072 parseBodyStructure( inWords, inSection, envelope );
1074 localPart->setNestedMessage( envelope );
1078 parseOneNumber( inWords, lines );
1080 if ( typeStr ==
"TEXT" ) {
1083 parseOneNumber( inWords, lines );
1087 parseLiteral( inWords );
1090 parameters = parseDisposition( inWords );
1092 QString disposition = parameters[
"content-disposition"];
1094 localPart->setDisposition( disposition.
toLatin1() );
1096 while ( it.hasNext() ) {
1098 localPart->setDispositionParm( it.key(), it.value() );
1104 parseSentence( inWords );
1108 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
1110 if ( inWords[0] ==
'(' ) {
1111 parseSentence( inWords );
1113 parseLiteral( inWords );
1117 if ( inWords[0] ==
')' ) {
1136 if ( inWords[0] !=
'(' ) {
1138 parseOneWord( inWords );
1144 if ( inWords[0] ==
'(' ) {
1153 localPart->clearNestedParts();
1154 localPart->clearTypeParameters();
1155 localPart->clearDispositionParameters();
1157 outSection = inSection +
".HEADER";
1159 if ( inWords[0] ==
'(' && init ) {
1164 if ( !outSection.
isEmpty() ) {
1165 localPart->setPartSpecifier( outSection );
1167 localPart->setPartSpecifier( inSection );
1171 while ( inWords[0] ==
'(' ) {
1174 outSection = inSection +
'.' + outSection;
1176 mimeHeader *subpart = parseBodyStructure( inWords, outSection, 0 );
1177 localPart->addNestedPart( subpart );
1181 subtype = parseOneWord( inWords );
1183 localPart->setType(
"MULTIPART/" + subtype );
1186 parameters = parseParameters( inWords );
1190 while ( it.hasNext() ) {
1192 localPart->setTypeParm( it.key(), it.value() );
1198 parameters = parseDisposition( inWords );
1200 QString disposition = parameters[
"content-disposition"];
1202 localPart->setDisposition( disposition.
toLatin1() );
1204 while ( it.hasNext() ) {
1206 localPart->setDispositionParm( it.key(), it.value() );
1212 parseSentence( inWords );
1217 inWords.data[inWords.pos] =
'(';
1219 inSection = inSection +
".1";
1221 localPart = parseSimplePart( inWords, inSection, localPart );
1223 inWords.data[inWords.pos] =
')';
1227 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
1229 if ( inWords[0] ==
'(' ) {
1230 parseSentence( inWords );
1232 parseLiteral( inWords );
1236 if ( inWords[0] ==
')' ) {
1243 void imapParser::parseBody (
parseString & inWords)
1246 if ( inWords[0] ==
'[' ) {
1251 specifier = parseOneWord( inWords,
true );
1253 if ( inWords[0] ==
'(' ) {
1256 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
1257 label = parseOneWord( inWords );
1260 if ( inWords[0] ==
')' ) {
1264 if ( inWords[0] ==
']' ) {
1270 if ( qstrncmp( specifier,
"0", specifier.
size() ) == 0 ) {
1272 if ( lastHandled ) {
1273 envelope = lastHandled->getHeader();
1276 if ( !envelope || seenUid.isEmpty() ) {
1277 kDebug( 7116 ) <<
"imapParser::parseBody - discarding" << envelope << seenUid.toLatin1();
1279 parseLiteral( inWords,
true );
1281 kDebug( 7116 ) <<
"imapParser::parseBody - reading" << envelope << seenUid.toLatin1();
1283 QString theHeader = parseLiteral( inWords,
true );
1286 myIO.setString( theHeader );
1287 envelope->parseHeader( myIO );
1289 }
else if ( qstrncmp( specifier,
"HEADER.FIELDS", specifier.
size() ) == 0 ) {
1293 if ( qstrncmp( label,
"REFERENCES", label.
size() ) == 0 ) {
1295 if ( lastHandled ) {
1296 envelope = lastHandled->getHeader();
1299 if ( !envelope || seenUid.isEmpty() ) {
1300 kDebug( 7116 ) <<
"imapParser::parseBody - discarding" << envelope << seenUid.toLatin1();
1302 parseLiteral( inWords,
true );
1304 QByteArray references = parseLiteral( inWords,
true );
1305 int start = references.
indexOf(
'<' );
1307 if ( start < end ) {
1308 references = references.
mid( start, end - start + 1 );
1310 envelope->setReferences( references.
simplified() );
1313 parseLiteral( inWords,
true );
1316 if ( specifier.
contains(
".MIME" ) ) {
1318 QString theHeader = parseLiteral( inWords,
false );
1320 myIO.setString( theHeader );
1321 envelope->parseHeader( myIO );
1322 if ( lastHandled ) {
1323 lastHandled->setHeader( envelope );
1328 kDebug( 7116 ) <<
"imapParser::parseBody - discarding" << seenUid.toLatin1();
1329 parseLiteral( inWords,
true );
1333 if ( lastHandled ) {
1334 envelope = lastHandled->getHeader();
1337 if ( !envelope || seenUid.isEmpty() ) {
1338 kDebug( 7116 ) <<
"imapParser::parseBody - discarding" << envelope << seenUid.toLatin1();
1340 parseSentence( inWords );
1342 kDebug( 7116 ) <<
"imapParser::parseBody - reading" << envelope << seenUid.toLatin1();
1345 mimeHeader *body = parseBodyStructure( inWords, section, envelope );
1346 if ( body != envelope ) {
1353 void imapParser::parseFetch (ulong ,
parseString & inWords)
1355 if ( inWords[0] !=
'(' ) {
1364 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
1365 if ( inWords[0] ==
'(' ) {
1366 parseSentence( inWords );
1368 const QByteArray word = parseLiteral( inWords,
false,
true );
1370 switch ( word[0] ) {
1372 if ( word ==
"ENVELOPE" ) {
1375 if ( lastHandled ) {
1376 envelope = lastHandled->getHeader();
1378 lastHandled =
new imapCache();
1381 if ( envelope && !envelope->getMessageId().
isEmpty() ) {
1384 parseSentence( inWords );
1386 envelope = parseEnvelope( inWords );
1388 envelope->setPartSpecifier( seenUid +
".0" );
1389 lastHandled->setHeader( envelope );
1390 lastHandled->setUid( seenUid.toULong() );
1397 if ( word ==
"BODY" ) {
1398 parseBody( inWords );
1399 }
else if ( word ==
"BODY[]" ) {
1401 parseLiteral( inWords,
true );
1402 }
else if ( word ==
"BODYSTRUCTURE" ) {
1405 if ( lastHandled ) {
1406 envelope = lastHandled->getHeader();
1411 mimeHeader *body = parseBodyStructure( inWords, section, envelope );
1413 QDataStream stream( &data, QIODevice::WriteOnly );
1415 body->serialize( stream );
1423 if ( word ==
"UID" ) {
1424 seenUid = parseOneWord( inWords );
1426 if ( lastHandled ) {
1427 envelope = lastHandled->getHeader();
1429 lastHandled =
new imapCache();
1432 if ( seenUid.isEmpty() ) {
1434 kDebug( 7116 ) <<
"imapParser::parseFetch - UID empty";
1436 lastHandled->setUid( seenUid.toULong() );
1439 envelope->setPartSpecifier( seenUid );
1445 if ( word ==
"RFC822.SIZE" ) {
1447 parseOneNumber( inWords, size );
1449 if ( !lastHandled ) {
1450 lastHandled =
new imapCache();
1452 lastHandled->setSize( size );
1455 parseLiteral( inWords,
true );
1460 if ( word ==
"INTERNALDATE" ) {
1461 const QByteArray date = parseOneWord( inWords );
1462 if ( !lastHandled ) {
1463 lastHandled =
new imapCache();
1465 lastHandled->setDate( date );
1470 if ( word ==
"FLAGS" ) {
1472 if ( !lastHandled ) {
1473 lastHandled =
new imapCache();
1475 lastHandled->setFlags( imapInfo::_flags( inWords.cstr() ) );
1480 parseLiteral( inWords );
1487 while ( !inWords.isEmpty() && inWords[0] !=
')' ) {
1489 if ( inWords[0] ==
'(' ) {
1490 parseSentence( inWords );
1492 parseLiteral( inWords );
1496 if ( inWords.isEmpty() || inWords[0] !=
')' ) {
1504 void imapParser::parseSentence (
parseString & inWords)
1511 while ( !inWords.isEmpty() && ( stack != 0 || first ) ) {
1515 unsigned char ch = inWords[0];
1534 parseLiteral( inWords );
1542 void imapParser::parseRecent (ulong value,
parseString & result)
1544 selectInfo.setRecent( value );
1545 result.pos = result.data.
size();
1548 void imapParser::parseNamespace (
parseString & result)
1550 if ( result[0] !=
'(' ) {
1555 if ( namespaceToDelimiter.contains(
QString() ) ) {
1556 delimEmpty = namespaceToDelimiter[
QString()];
1559 namespaceToDelimiter.
clear();
1560 imapNamespaces.clear();
1564 bool personalAvailable =
false;
1565 while ( !result.isEmpty() ) {
1566 if ( result[0] ==
'(' ) {
1568 if ( result[0] ==
'(' ) {
1577 kDebug( 7116 ) <<
"imapParser::parseNamespace ns='" << prefix <<
"',delim='" << delim <<
"'";
1580 personalAvailable =
true;
1583 imapNamespaces.
append( nsentry );
1584 if ( prefix.
right( 1 ) == delim ) {
1588 namespaceToDelimiter[prefix] = delim;
1592 }
else if ( result[0] ==
')' ) {
1595 }
else if ( result[0] ==
'N' ) {
1598 parseOneWord( result );
1601 parseOneWord( result );
1604 if ( !delimEmpty.
isEmpty() ) {
1606 namespaceToDelimiter[
QString()] = delimEmpty;
1607 if ( !personalAvailable ) {
1609 kDebug( 7116 ) <<
"imapParser::parseNamespace - registering own personal ns";
1610 QString nsentry =
"0==" + delimEmpty;
1611 imapNamespaces.
append( nsentry );
1616 int imapParser::parseLoop ()
1620 if ( !parseReadLine( result.data ) ) {
1626 if ( result.data.
isEmpty() ) {
1629 if ( !sentQueue.count() ) {
1631 kDebug( 7116 ) <<
"imapParser::parseLoop - unhandledResponse:" << result.cstr();
1632 unhandled << result.cstr();
1634 CommandPtr current = sentQueue.
at( 0 );
1635 switch ( result[0] ) {
1637 result.data.
resize( result.data.
size() - 2 );
1638 parseUntagged( result );
1641 continuation = result.data;
1646 if ( current->id() == tag.
data() ) {
1647 result.data.
resize( result.data.
size() - 2 );
1648 QByteArray resultCode = parseLiteral( result );
1649 current->setResult( resultCode );
1650 current->setResultInfo( result.cstr() );
1651 current->setComplete();
1653 sentQueue.removeAll( current );
1654 completeQueue.append( current );
1655 if ( result.length() ) {
1656 parseResult( resultCode, result, current->command() );
1659 kDebug( 7116 ) <<
"imapParser::parseLoop - unknown tag '" << tag <<
"'";
1673 imapParser::parseRelay (
const QByteArray & buffer)
1676 qWarning(
"imapParser::parseRelay - virtual function not reimplemented - data lost" );
1680 imapParser::parseRelay (ulong len)
1683 qWarning(
"imapParser::parseRelay - virtual function not reimplemented - announcement lost" );
1686 bool imapParser::parseRead (
QByteArray & buffer,
long len,
long relay)
1691 qWarning(
"imapParser::parseRead - virtual function not reimplemented - no data read" );
1695 bool imapParser::parseReadLine (
QByteArray & buffer,
long relay)
1699 qWarning(
"imapParser::parseReadLine - virtual function not reimplemented - no data read" );
1704 imapParser::parseWriteLine (
const QString & str)
1707 qWarning(
"imapParser::parseWriteLine - virtual function not reimplemented - no data written" );
1711 imapParser::parseURL (
const KUrl & _url,
QString & _box,
QString & _section,
1717 kDebug( 7116 ) <<
"imapParser::parseURL" << _box;
1718 int paramStart = _box.
indexOf(
"/;" );
1719 if ( paramStart > -1 ) {
1721 parameters = paramString.
split(
';', QString::SkipEmptyParts );
1726 it != parameters.
constEnd(); ++it ) {
1753 if ( _box[0] ==
'/' ) {
1760 kDebug( 7116 ) <<
"URL: box=" << _box <<
", section=" << _section <<
", type="
1761 << _type <<
", uid=" << _uid <<
", validity=" << _validity
1762 <<
", info=" << _info;
1768 if ( !inWords.isEmpty() && inWords[0] ==
'{' ) {
1770 int runLen = inWords.find(
'}', 1);
1773 long runLenSave = runLen + 1;
1775 inWords.takeMidNoResize( tmpstr, 1, runLen - 1 );
1776 runLen = tmpstr.toULong( &proper );
1777 inWords.pos += runLenSave;
1781 parseRelay( runLen );
1784 parseRead( rv, runLen, relay ? runLen : 0 );
1788 parseReadLine( inWords.data );
1793 kDebug( 7116 ) <<
"imapParser::parseLiteral - error parsing {} -" ;
1797 kDebug( 7116 ) <<
"imapParser::parseLiteral - error parsing unmatched {";
1802 return parseOneWord( inWords, stopAtBracket );
1808 uint len = inWords.length();
1813 if ( len > 0 && inWords[0] ==
'"' ) {
1816 while ( i < len && ( inWords[i] !=
'"' || quote ) ) {
1817 if ( inWords[i] ==
'\\' ) {
1828 inWords.takeLeftNoResize( retVal, i - 1 );
1831 for (
unsigned int j = 0; j < len; j++ ) {
1832 if ( retVal[j] ==
'\\' ) {
1836 retVal[j - offset] = retVal[j];
1838 retVal.
resize( len - offset );
1843 kDebug( 7116 ) <<
"imapParser::parseOneWord - error parsing unmatched \"";
1852 for ( i = 0; i < len; ++i ) {
1853 char ch = inWords[i];
1854 if ( ch <=
' ' || ch ==
'(' || ch ==
')' ||
1855 ( stopAtBracket && ( ch ==
'[' || ch ==
']' ) ) ) {
1862 inWords.takeLeftNoResize( retVal, i );
1865 if ( retVal ==
"NIL" ) {
1873 bool imapParser::parseOneNumber (
parseString & inWords, ulong & num)
1876 num = parseOneWord( inWords,
true ).
toULong( &valid );
1880 bool imapParser::hasCapability (
const QString & cap)
1885 it != imapCapabilities.constEnd(); ++it ) {
1887 if ( !( kasciistricmp( c.
toLatin1(), ( *it ).toAscii() ) ) ) {
1894 void imapParser::removeCapability (
const QString & cap)
1896 imapCapabilities.removeAll( cap.
toLower() );
1901 kDebug( 7116 ) <<
"imapParse::namespaceForBox" << box;
1907 if ( !( *it ).isEmpty() && box.
contains( *it ) ) {
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString & append(QChar ch)
uint toUInt(bool *ok, int base) const
iterator insert(const Key &key, const T &value)
void truncate(int position)
QByteArray toLower() const
int lastIndexOf(char ch, int from) const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QByteArray toUpper() const
bool startsWith(const QByteArray &ba) const
QByteArray fromRawData(const char *data, int size)
QString join(const QString &separator) const
a string used during parsing the string allows you to move the effective start of the string using st...
int indexOf(char ch, int from) const
QString number(int n, int base)
void append(const T &value)
QString fromUtf8(const char *str, int size)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QByteArray mid(int pos, int len) const
QString right(int n) const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QByteArray simplified() const
QByteArray toLatin1() const
QByteArray fromBase64(const QByteArray &base64)
bool contains(char ch) const
QString fromLatin1(const char *str, int size)
ulong toULong(bool *ok, int base) const
encapulate a IMAP command
QByteArray toBase64() const
const_iterator constEnd() const
const_iterator constBegin() const