29 #include "rfcdecoder.h"
31 #include "imapparser.h"
35 #include "mailheader.h"
36 #include "mimeheader.h"
37 #include "mailaddress.h"
39 #include <sys/types.h>
46 #include <sasl/sasl.h>
53 #include <tqstringlist.h>
59 #include <tdeglobal.h>
62 static sasl_callback_t callbacks[] = {
63 { SASL_CB_ECHOPROMPT, NULL, NULL },
64 { SASL_CB_NOECHOPROMPT, NULL, NULL },
65 { SASL_CB_GETREALM, NULL, NULL },
66 { SASL_CB_USER, NULL, NULL },
67 { SASL_CB_AUTHNAME, NULL, NULL },
68 { SASL_CB_PASS, NULL, NULL },
69 { SASL_CB_CANON_USER, NULL, NULL },
70 { SASL_CB_LIST_END, NULL, NULL }
74 imapParser::imapParser ()
76 sentQueue.setAutoDelete (
false);
77 completeQueue.setAutoDelete (
true);
78 currentState = ISTATE_NO;
83 imapParser::~imapParser ()
95 while ((pl = parseLoop ()) == 0)
105 aCmd->
setId (TQString::number(commandCounter++));
106 sentQueue.append (aCmd);
108 continuation.resize(0);
109 const TQString& command = aCmd->
command();
111 if (command ==
"SELECT" || command ==
"EXAMINE")
116 currentBox = parseOneWordC(p);
117 kdDebug(7116) <<
"imapParser::sendCommand - setting current box to " << currentBox << endl;
119 else if (command ==
"CLOSE")
122 currentBox = TQString();
124 else if (command.find (
"SEARCH") != -1
125 || command ==
"GETACL"
126 || command ==
"LISTRIGHTS"
127 || command ==
"MYRIGHTS"
128 || command ==
"GETANNOTATION"
129 || command ==
"NAMESPACE"
130 || command ==
"GETQUOTAROOT"
131 || command ==
"GETQUOTA"
132 || command ==
"X-GET-OTHER-USERS"
133 || command ==
"X-GET-DELEGATES"
134 || command ==
"X-GET-OUT-OF-OFFICE")
136 lastResults.clear ();
138 else if (command ==
"LIST"
139 || command ==
"LSUB")
141 listResponses.clear ();
143 parseWriteLine (aCmd->
getStr ());
148 imapParser::clientLogin (
const TQString & aUser,
const TQString & aPass,
149 TQString & resultInfo)
159 if (cmd->
result () ==
"OK")
161 currentState = ISTATE_LOGIN;
165 completeQueue.removeRef (cmd);
171 static bool sasl_interact( TDEIO::SlaveBase *slave, TDEIO::AuthInfo &ai,
void *in )
173 kdDebug(7116) <<
"sasl_interact" << endl;
174 sasl_interact_t *interact = ( sasl_interact_t * ) in;
178 for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
179 if ( interact->id == SASL_CB_AUTHNAME ||
180 interact->id == SASL_CB_PASS ) {
182 if ( ai.username.isEmpty() || ai.password.isEmpty() ) {
183 if (!slave->openPassDlg(ai))
190 interact = ( sasl_interact_t * ) in;
191 while( interact->id != SASL_CB_LIST_END ) {
192 kdDebug(7116) <<
"SASL_INTERACT id: " << interact->id << endl;
193 switch( interact->id ) {
195 case SASL_CB_AUTHNAME:
196 kdDebug(7116) <<
"SASL_CB_[USER|AUTHNAME]: '" << ai.username <<
"'" << endl;
197 interact->result = strdup( ai.username.utf8() );
198 interact->len = strlen( (
const char *) interact->result );
201 kdDebug(7116) <<
"SASL_CB_PASS: [hidden] " << endl;
202 interact->result = strdup( ai.password.utf8() );
203 interact->len = strlen( (
const char *) interact->result );
206 interact->result = 0;
217 imapParser::clientAuthenticate ( TDEIO::SlaveBase *slave, TDEIO::AuthInfo &ai,
218 const TQString & aFTQDN,
const TQString & aAuth,
bool isSSL, TQString & resultInfo)
223 sasl_conn_t *conn = 0;
224 sasl_interact_t *client_interact = 0;
227 const char *mechusing = 0;
228 TQByteArray tmp, challenge;
230 kdDebug(7116) <<
"aAuth: " << aAuth <<
" FTQDN: " << aFTQDN <<
" isSSL: " << isSSL << endl;
233 if (!hasCapability (
"AUTH=" + aAuth))
237 result = sasl_client_new(
"imap",
240 0, 0, callbacks, 0, &conn );
242 if ( result != SASL_OK ) {
243 kdDebug(7116) <<
"sasl_client_new failed with: " << result << endl;
244 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
249 result = sasl_client_start(conn, aAuth.latin1(), &client_interact,
250 hasCapability(
"SASL-IR") ? &out : 0, &outlen, &mechusing);
252 if ( result == SASL_INTERACT ) {
253 if ( !sasl_interact( slave, ai, client_interact ) ) {
254 sasl_dispose( &conn );
258 }
while ( result == SASL_INTERACT );
260 if ( result != SASL_CONTINUE && result != SASL_OK ) {
261 kdDebug(7116) <<
"sasl_client_start failed with: " << result << endl;
262 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
263 sasl_dispose( &conn );
268 tmp.setRawData( out, outlen );
269 KCodecs::base64Encode( tmp, challenge );
270 tmp.resetRawData( out, outlen );
272 TQString firstCommand = aAuth;
273 if ( !challenge.isEmpty() ) {
275 firstCommand += TQString::fromLatin1( challenge.data(), challenge.size() );
277 cmd = sendCommand (
new imapCommand (
"AUTHENTICATE", firstCommand.latin1()));
283 while ((pl = parseLoop()) == 0) ;
285 if (!continuation.isEmpty())
288 if ( continuation.size() > 4 ) {
289 tmp.setRawData( continuation.data() + 2, continuation.size() - 4 );
290 KCodecs::base64Decode( tmp, challenge );
292 tmp.resetRawData( continuation.data() + 2, continuation.size() - 4 );
296 result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(),
301 if (result == SASL_INTERACT) {
302 if ( !sasl_interact( slave, ai, client_interact ) ) {
303 sasl_dispose( &conn );
307 }
while ( result == SASL_INTERACT );
309 if ( result != SASL_CONTINUE && result != SASL_OK ) {
310 kdDebug(7116) <<
"sasl_client_step failed with: " << result << endl;
311 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
312 sasl_dispose( &conn );
316 tmp.setRawData( out, outlen );
318 KCodecs::base64Encode( tmp, challenge );
319 tmp.resetRawData( out, outlen );
321 parseWriteLine (challenge);
322 continuation.resize(0);
326 if (cmd->
result () ==
"OK")
328 currentState = ISTATE_LOGIN;
332 completeQueue.removeRef (cmd);
334 sasl_dispose( &conn );
344 parseOneWordC(result);
345 TQByteArray what = parseLiteral (result);
347 if(!what.isEmpty ()) {
352 if (tqstrncmp(what,
"BAD", what.size()) == 0)
354 parseResult (what, result);
356 else if (tqstrncmp(what,
"BYE", what.size()) == 0)
358 parseResult (what, result);
359 if ( sentQueue.count() ) {
364 currentState = ISTATE_NO;
369 if (what[1] ==
'O' && what.size() == 2)
371 parseResult (what, result);
373 else if (tqstrncmp(what,
"NAMESPACE", what.size()) == 0)
375 parseNamespace (result);
380 if (what[1] ==
'K' && what.size() == 2)
382 parseResult (what, result);
383 }
else if (tqstrncmp(what,
"OTHER-USER", 10) == 0) {
384 parseOtherUser (result);
385 }
else if (tqstrncmp(what,
"OUT-OF-OFFICE", 13) == 0) {
386 parseOutOfOffice (result);
390 if (tqstrncmp(what,
"DELEGATE", 8) == 0) {
391 parseDelegate (result);
396 if (tqstrncmp(what,
"PREAUTH", what.size()) == 0)
398 parseResult (what, result);
399 currentState = ISTATE_LOGIN;
405 if (tqstrncmp(what,
"CAPABILITY", what.size()) == 0)
407 parseCapability (result);
412 if (tqstrncmp(what,
"FLAGS", what.size()) == 0)
419 if (tqstrncmp(what,
"LIST", what.size()) == 0)
423 else if (tqstrncmp(what,
"LSUB", what.size()) == 0)
427 else if (tqstrncmp(what,
"LISTRIGHTS", what.size()) == 0)
429 parseListRights (result);
434 if (tqstrncmp(what,
"MYRIGHTS", what.size()) == 0)
436 parseMyRights (result);
440 if (tqstrncmp(what,
"SEARCH", what.size()) == 0)
442 parseSearch (result);
444 else if (tqstrncmp(what,
"STATUS", what.size()) == 0)
446 parsetStatus (result);
451 if (tqstrncmp(what,
"ACL", what.size()) == 0)
455 else if (tqstrncmp(what,
"ANNOTATION", what.size()) == 0)
457 parseAnnotation (result);
461 if ( what.size() > 5 && tqstrncmp(what,
"QUOTAROOT", what.size()) == 0)
463 parseQuotaRoot( result );
465 else if (tqstrncmp(what,
"QUOTA", what.size()) == 0)
467 parseQuota( result );
472 parseCustom( result );
481 number = TQCString(what, what.size() + 1).toUInt(&valid);
484 what = parseLiteral (result);
485 if(!what.isEmpty ()) {
489 if (tqstrncmp(what,
"EXISTS", what.size()) == 0)
491 parseExists (number, result);
493 else if (tqstrncmp(what,
"EXPUNGE", what.size()) == 0)
495 parseExpunge (number, result);
500 if (tqstrncmp(what,
"FETCH", what.size()) == 0)
502 seenUid = TQString();
503 parseFetch (number, result);
508 if (tqstrncmp(what,
"STORE", what.size()) == 0)
510 seenUid = TQString();
511 parseFetch (number, result);
516 if (tqstrncmp(what,
"RECENT", what.size()) == 0)
518 parseRecent (number, result);
534 imapParser::parseResult (TQByteArray & result,
parseString & rest,
535 const TQString & command)
537 if (command ==
"SELECT")
538 selectInfo.setReadWrite(
true);
543 TQCString option = parseOneWordC(rest, TRUE);
548 if (option ==
"ALERT")
550 rest.pos = rest.data.find(
']', rest.pos) + 1;
553 selectInfo.setAlert( rest.cstr() );
558 if (option ==
"NEWNAME")
564 if (option ==
"PARSE")
567 else if (option ==
"PERMANENTFLAGS")
569 uint end = rest.data.find(
']', rest.pos);
570 TQCString flags(rest.data.data() + rest.pos, end - rest.pos);
571 selectInfo.setPermanentFlags (flags);
577 if (option ==
"READ-ONLY")
579 selectInfo.setReadWrite (
false);
581 else if (option ==
"READ-WRITE")
583 selectInfo.setReadWrite (
true);
588 if (option ==
"TRYCREATE")
594 if (option ==
"UIDVALIDITY")
597 if (parseOneNumber (rest, value))
598 selectInfo.setUidValidity (value);
600 else if (option ==
"UNSEEN")
603 if (parseOneNumber (rest, value))
604 selectInfo.setUnseen (value);
606 else if (option ==
"UIDNEXT")
609 if (parseOneNumber (rest, value))
610 selectInfo.setUidNext (value);
621 if (command.isEmpty())
628 switch (command[0].latin1 ())
631 if (command ==
"AUTHENTICATE")
632 if (tqstrncmp(result,
"OK", result.size()) == 0)
633 currentState = ISTATE_LOGIN;
637 if (command ==
"LOGIN")
638 if (tqstrncmp(result,
"OK", result.size()) == 0)
639 currentState = ISTATE_LOGIN;
643 if (command ==
"EXAMINE")
645 if (tqstrncmp(result,
"OK", result.size()) == 0)
646 currentState = ISTATE_SELECT;
649 if (currentState == ISTATE_SELECT)
650 currentState = ISTATE_LOGIN;
651 currentBox = TQString();
653 kdDebug(7116) <<
"imapParser::parseResult - current box is now " << currentBox << endl;
658 if (command ==
"SELECT")
660 if (tqstrncmp(result,
"OK", result.size()) == 0)
661 currentState = ISTATE_SELECT;
664 if (currentState == ISTATE_SELECT)
665 currentState = ISTATE_LOGIN;
666 currentBox = TQString();
668 kdDebug(7116) <<
"imapParser::parseResult - current box is now " << currentBox << endl;
678 void imapParser::parseCapability (
parseString & result)
680 TQCString temp( result.cstr() );
681 imapCapabilities = TQStringList::split (
' ', kasciitolower( temp.data() ) );
686 selectInfo.setFlags(result.cstr());
693 if (result[0] !=
'(')
698 this_one.parseAttributes( result );
703 this_one.setHierarchyDelimiter(parseLiteralC(result));
706 listResponses.append (this_one);
711 imapList this_one (result.cstr(), *
this);
712 listResponses.append (this_one);
715 void imapParser::parseListRights (
parseString & result)
717 parseOneWordC (result);
718 parseOneWordC (result);
721 TQCString word = parseOneWordC (result,
false, &outlen);
722 lastResults.append (word);
728 parseOneWordC (result);
731 while ( outlen && !result.isEmpty() ) {
732 TQCString word = parseLiteralC (result,
false,
false, &outlen);
733 lastResults.append (word);
737 void imapParser::parseAnnotation (
parseString & result)
739 parseOneWordC (result);
741 parseOneWordC (result);
743 if (result.isEmpty() || result[0] !=
'(')
749 while ( outlen && !result.isEmpty() && result[0] !=
')' ) {
750 TQCString word = parseLiteralC (result,
false,
false, &outlen);
751 lastResults.append (word);
761 TQCString root = parseOneWordC( result );
762 if ( root.isEmpty() ) {
763 lastResults.append(
"" );
765 lastResults.append( root );
767 if (result.isEmpty() || result[0] !=
'(')
771 TQStringList triplet;
773 while ( outlen && !result.isEmpty() && result[0] !=
')' ) {
774 TQCString word = parseLiteralC (result,
false,
false, &outlen);
775 triplet.append(word);
777 lastResults.append( triplet.join(
" ") );
780 void imapParser::parseQuotaRoot (
parseString & result)
784 parseOneWordC (result);
786 if ( result.isEmpty() )
790 while ( outlen && !result.isEmpty() ) {
791 TQCString word = parseLiteralC (result,
false,
false, &outlen);
794 lastResults.append( roots.isEmpty()?
"" : roots.join(
" ") );
797 void imapParser::parseCustom (
parseString & result)
800 TQCString word = parseLiteralC (result,
false,
false, &outlen);
801 lastResults.append( word );
804 void imapParser::parseOtherUser (
parseString & result)
806 lastResults.append( parseOneWordC( result ) );
809 void imapParser::parseDelegate (
parseString & result)
811 const TQString email = parseOneWordC( result );
815 while ( outlen && !result.isEmpty() ) {
816 TQCString word = parseLiteralC( result,
false,
false, &outlen );
817 rights.append( word );
820 lastResults.append( email +
':' + rights.join(
"," ) );
823 void imapParser::parseOutOfOffice (
parseString & result)
825 const TQString state = parseOneWordC (result);
826 parseOneWordC (result);
829 TQCString msg = parseLiteralC (result,
false,
false, &outlen);
831 lastResults.append( state +
'^' + TQString::fromUtf8( msg ) );
834 void imapParser::parseMyRights (
parseString & result)
836 parseOneWordC (result);
837 Q_ASSERT( lastResults.isEmpty() );
838 lastResults.append (parseOneWordC (result) );
841 void imapParser::parseSearch (
parseString & result)
845 while (parseOneNumber (result, value))
847 lastResults.append (TQString::number(value));
851 void imapParser::parsetStatus (
parseString & inWords)
853 lasStatus = imapInfo ();
855 parseLiteralC(inWords);
856 if (inWords.isEmpty() || inWords[0] !=
'(')
862 while (!inWords.isEmpty() && inWords[0] !=
')')
866 TQCString label = parseOneWordC(inWords);
867 if (parseOneNumber (inWords, value))
869 if (label ==
"MESSAGES")
870 lasStatus.setCount (value);
871 else if (label ==
"RECENT")
872 lasStatus.setRecent (value);
873 else if (label ==
"UIDVALIDITY")
874 lasStatus.setUidValidity (value);
875 else if (label ==
"UNSEEN")
876 lasStatus.setUnseen (value);
877 else if (label ==
"UIDNEXT")
878 lasStatus.setUidNext (value);
882 if (inWords[0] ==
')')
887 void imapParser::parseExists (ulong value,
parseString & result)
889 selectInfo.setCount (value);
890 result.pos = result.data.size();
893 void imapParser::parseExpunge (ulong value,
parseString & result)
899 void imapParser::parseAddressList (
parseString & inWords, TQPtrList<mailAddress>& list)
901 if (inWords.isEmpty())
903 if (inWords[0] !=
'(')
905 parseOneWordC (inWords);
912 while (!inWords.isEmpty () && inWords[0] !=
')')
914 if (inWords[0] ==
'(') {
915 mailAddress *addr =
new mailAddress;
916 parseAddress(inWords, *addr);
923 if (!inWords.isEmpty() && inWords[0] ==
')')
929 const mailAddress& imapParser::parseAddress (
parseString & inWords, mailAddress& retVal)
934 retVal.setFullName(parseLiteralC(inWords));
935 retVal.setCommentRaw(parseLiteralC(inWords));
936 retVal.setUser(parseLiteralC(inWords));
937 retVal.setHost(parseLiteralC(inWords));
939 if (!inWords.isEmpty() && inWords[0] ==
')')
950 if (inWords[0] !=
'(')
958 envelope->
setDate(parseLiteralC(inWords));
963 TQPtrList<mailAddress> list;
964 list.setAutoDelete(
true);
967 parseAddressList(inWords, list);
968 if (!list.isEmpty()) {
969 envelope->setFrom(*list.last());
974 parseAddressList(inWords, list);
975 if (!list.isEmpty()) {
976 envelope->setSender(*list.last());
981 parseAddressList(inWords, list);
982 if (!list.isEmpty()) {
983 envelope->setReplyTo(*list.last());
988 parseAddressList (inWords, envelope->to());
991 parseAddressList (inWords, envelope->cc());
994 parseAddressList (inWords, envelope->bcc());
997 envelope->setInReplyTo(parseLiteralC(inWords));
1000 envelope->setMessageId(parseLiteralC(inWords));
1003 while (!inWords.isEmpty () && inWords[0] !=
')')
1006 if (inWords[0] ==
'(')
1007 parseSentence (inWords);
1009 parseLiteralC (inWords);
1012 if (!inWords.isEmpty() && inWords[0] ==
')')
1021 TQAsciiDict < TQString > imapParser::parseDisposition (
parseString & inWords)
1023 TQCString disposition;
1024 TQAsciiDict < TQString > retVal (17,
false);
1027 retVal.setAutoDelete (
false);
1029 if (inWords[0] !=
'(')
1032 disposition = parseOneWordC (inWords);
1040 disposition = parseOneWordC (inWords);
1041 retVal = parseParameters (inWords);
1042 if (inWords[0] !=
')')
1048 if (!disposition.isEmpty ())
1050 retVal.insert (
"content-disposition",
new TQString(disposition));
1058 TQAsciiDict < TQString > imapParser::parseParameters (
parseString & inWords)
1060 TQAsciiDict < TQString > retVal (17,
false);
1063 retVal.setAutoDelete (
false);
1065 if (inWords[0] !=
'(')
1068 parseOneWordC (inWords);
1075 while (!inWords.isEmpty () && inWords[0] !=
')')
1077 TQCString l1 = parseLiteralC(inWords);
1078 TQCString l2 = parseLiteralC(inWords);
1079 retVal.insert (l1,
new TQString(l2));
1082 if (inWords[0] !=
')')
1092 TQString & inSection,
mimeHeader * localPart)
1096 TQAsciiDict < TQString > parameters (17,
false);
1099 parameters.setAutoDelete (
true);
1101 if (inWords[0] !=
'(')
1107 localPart->setPartSpecifier (inSection);
1113 typeStr = parseLiteralC(inWords);
1116 subtype = parseLiteralC(inWords);
1118 localPart->setType (typeStr +
"/" + subtype);
1121 parameters = parseParameters (inWords);
1123 TQAsciiDictIterator < TQString > it (parameters);
1125 while (it.current ())
1127 localPart->setTypeParm (it.currentKey (), *(it.current ()));
1130 parameters.clear ();
1134 localPart->setID (parseLiteralC(inWords));
1137 localPart->setDescription (parseLiteralC(inWords));
1140 localPart->setEncoding (parseLiteralC(inWords));
1143 if (parseOneNumber (inWords, size))
1144 localPart->setLength (size);
1147 if (localPart->getType().upper() ==
"MESSAGE/RFC822")
1150 mailHeader *envelope = parseEnvelope (inWords);
1153 parseBodyStructure (inWords, inSection, envelope);
1155 localPart->setNestedMessage (envelope);
1159 parseOneNumber (inWords, lines);
1163 if (typeStr ==
"TEXT")
1167 parseOneNumber (inWords, lines);
1171 parseLiteralC(inWords);
1174 parameters = parseDisposition (inWords);
1176 TQString *disposition = parameters[
"content-disposition"];
1179 localPart->setDisposition (disposition->ascii ());
1180 parameters.remove (
"content-disposition");
1181 TQAsciiDictIterator < TQString > it (parameters);
1182 while (it.current ())
1184 localPart->setDispositionParm (it.currentKey (),
1189 parameters.clear ();
1193 parseSentence (inWords);
1197 while (!inWords.isEmpty () && inWords[0] !=
')')
1200 if (inWords[0] ==
'(')
1201 parseSentence (inWords);
1203 parseLiteralC(inWords);
1205 if (inWords[0] ==
')')
1213 TQString & inSection,
mimeHeader * localPart)
1216 if (inSection.isEmpty())
1225 if (inWords[0] !=
'(')
1228 parseOneWordC (inWords);
1234 if (inWords[0] ==
'(')
1236 TQByteArray subtype;
1237 TQAsciiDict < TQString > parameters (17,
false);
1238 TQString outSection;
1239 parameters.setAutoDelete (
true);
1245 localPart->clearNestedParts ();
1246 localPart->clearTypeParameters ();
1247 localPart->clearDispositionParameters ();
1249 outSection = inSection +
".HEADER";
1251 if (inWords[0] ==
'(' && init)
1255 if ( !outSection.isEmpty() ) {
1256 localPart->setPartSpecifier(outSection);
1258 localPart->setPartSpecifier(inSection);
1262 while (inWords[0] ==
'(')
1264 outSection = TQString::number(++section);
1266 outSection = inSection +
"." + outSection;
1267 mimeHeader *subpart = parseBodyStructure (inWords, outSection, 0);
1268 localPart->addNestedPart (subpart);
1272 subtype = parseOneWordC (inWords);
1274 localPart->setType (
"MULTIPART/" + b2c(subtype));
1277 parameters = parseParameters (inWords);
1279 TQAsciiDictIterator < TQString > it (parameters);
1281 while (it.current ())
1283 localPart->setTypeParm (it.currentKey (), *(it.current ()));
1286 parameters.clear ();
1290 parameters = parseDisposition (inWords);
1292 TQString *disposition = parameters[
"content-disposition"];
1295 localPart->setDisposition (disposition->ascii ());
1296 parameters.remove (
"content-disposition");
1297 TQAsciiDictIterator < TQString > it (parameters);
1298 while (it.current ())
1300 localPart->setDispositionParm (it.currentKey (),
1304 parameters.clear ();
1308 parseSentence (inWords);
1315 inWords.data[inWords.pos] =
'(';
1317 inSection = inSection +
".1";
1318 localPart = parseSimplePart (inWords, inSection, localPart);
1320 inWords.data[inWords.pos] =
')';
1324 while (!inWords.isEmpty () && inWords[0] !=
')')
1327 if (inWords[0] ==
'(')
1328 parseSentence (inWords);
1330 parseLiteralC(inWords);
1333 if (inWords[0] ==
')')
1340 void imapParser::parseBody (
parseString & inWords)
1343 if (inWords[0] ==
'[')
1345 TQCString specifier;
1349 specifier = parseOneWordC (inWords, TRUE);
1351 if (inWords[0] ==
'(')
1355 while (!inWords.isEmpty () && inWords[0] !=
')')
1357 label = parseOneWordC (inWords);
1360 if (!inWords.isEmpty () && inWords[0] ==
')')
1363 if (!inWords.isEmpty () && inWords[0] ==
']')
1368 if (specifier ==
"0")
1372 envelope = lastHandled->getHeader ();
1374 if (!envelope || seenUid.isEmpty ())
1376 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1378 parseLiteralC(inWords,
true);
1382 kdDebug(7116) <<
"imapParser::parseBody - reading " << envelope <<
" " << seenUid.ascii () << endl;
1384 TQString theHeader = parseLiteralC(inWords,
true);
1385 mimeIOTQString myIO;
1387 myIO.setString (theHeader);
1388 envelope->parseHeader (myIO);
1392 else if (specifier ==
"HEADER.FIELDS")
1397 if (label ==
"REFERENCES")
1401 envelope = lastHandled->getHeader ();
1403 if (!envelope || seenUid.isEmpty ())
1405 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1407 parseLiteralC (inWords,
true);
1411 TQCString references = parseLiteralC(inWords,
true);
1412 int start = references.find (
'<');
1413 int end = references.findRev (
'>');
1415 references = references.mid (start, end - start + 1);
1416 envelope->setReferences(references.simplifyWhiteSpace());
1421 parseLiteralC(inWords,
true);
1426 if (specifier.find(
".MIME") != -1)
1429 TQString theHeader = parseLiteralC(inWords,
false);
1430 mimeIOTQString myIO;
1431 myIO.setString (theHeader);
1432 envelope->parseHeader (myIO);
1434 lastHandled->setHeader (envelope);
1438 kdDebug(7116) <<
"imapParser::parseBody - discarding " << seenUid.ascii () << endl;
1439 parseLiteralC(inWords,
true);
1447 envelope = lastHandled->getHeader ();
1449 if (!envelope || seenUid.isEmpty ())
1451 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1453 parseSentence (inWords);
1457 kdDebug(7116) <<
"imapParser::parseBody - reading " << envelope <<
" " << seenUid.ascii () << endl;
1460 mimeHeader *body = parseBodyStructure (inWords, section, envelope);
1461 if (body != envelope)
1467 void imapParser::parseFetch (ulong ,
parseString & inWords)
1469 if (inWords[0] !=
'(')
1477 while (!inWords.isEmpty () && inWords[0] !=
')')
1479 if (inWords[0] ==
'(')
1480 parseSentence (inWords);
1483 TQCString word = parseLiteralC(inWords,
false,
true);
1485 if(!word.isEmpty()) {
1489 if (word ==
"ENVELOPE")
1494 envelope = lastHandled->getHeader ();
1496 lastHandled =
new imapCache();
1498 if (envelope && !envelope->getMessageId ().isEmpty ())
1502 parseSentence (inWords);
1506 envelope = parseEnvelope (inWords);
1509 envelope->setPartSpecifier (seenUid +
".0");
1510 lastHandled->setHeader (envelope);
1511 lastHandled->setUid (seenUid.toULong ());
1520 parseBody (inWords);
1522 else if (word ==
"BODY[]" )
1525 parseLiteralC(inWords,
true);
1527 else if (word ==
"BODYSTRUCTURE")
1532 envelope = lastHandled->getHeader ();
1537 parseBodyStructure (inWords, section, envelope);
1539 TQDataStream stream( data, IO_WriteOnly );
1540 if (body) body->serialize(stream);
1550 seenUid = parseOneWordC(inWords);
1553 envelope = lastHandled->getHeader ();
1555 lastHandled =
new imapCache();
1557 if (seenUid.isEmpty ())
1560 kdDebug(7116) <<
"imapParser::parseFetch - UID empty" << endl;
1564 lastHandled->setUid (seenUid.toULong ());
1567 envelope->setPartSpecifier (seenUid);
1572 if (word ==
"RFC822.SIZE")
1575 parseOneNumber (inWords, size);
1577 if (!lastHandled) lastHandled =
new imapCache();
1578 lastHandled->setSize (size);
1580 else if (word.find (
"RFC822") == 0)
1583 parseLiteralC(inWords,
true);
1588 if (word ==
"INTERNALDATE")
1590 TQCString date = parseOneWordC(inWords);
1591 if (!lastHandled) lastHandled =
new imapCache();
1592 lastHandled->setDate(date);
1597 if (word ==
"FLAGS")
1600 if (!lastHandled) lastHandled =
new imapCache();
1601 lastHandled->setFlags (imapInfo::_flags (inWords.cstr()));
1606 parseLiteralC(inWords);
1610 parseLiteralC(inWords);
1616 while (!inWords.isEmpty () && inWords[0] !=
')')
1619 if (inWords[0] ==
'(')
1620 parseSentence (inWords);
1622 parseLiteralC(inWords);
1625 if (inWords.isEmpty() || inWords[0] !=
')')
1633 void imapParser::parseSentence (
parseString & inWords)
1640 while (!inWords.isEmpty () && (stack != 0 || first))
1645 unsigned char ch = inWords[0];
1665 parseLiteralC(inWords);
1673 void imapParser::parseRecent (ulong value,
parseString & result)
1675 selectInfo.setRecent (value);
1676 result.pos = result.data.size();
1679 void imapParser::parseNamespace (
parseString & result)
1681 if ( result[0] !=
'(' )
1684 TQString delimEmpty;
1685 if ( namespaceToDelimiter.contains( TQString() ) )
1686 delimEmpty = namespaceToDelimiter[TQString()];
1688 namespaceToDelimiter.clear();
1689 imapNamespaces.clear();
1693 bool personalAvailable =
false;
1694 while ( !result.isEmpty() )
1696 if ( result[0] ==
'(' )
1699 if ( result[0] ==
'(' )
1706 TQCString prefix = parseOneWordC( result );
1708 TQCString delim = parseOneWordC( result );
1709 kdDebug(7116) <<
"imapParser::parseNamespace ns='" << prefix <<
1710 "',delim='" << delim <<
"'" << endl;
1714 personalAvailable =
true;
1716 TQString nsentry = TQString::number( ns ) +
"=" + TQString(prefix) +
1717 "=" + TQString(delim);
1718 imapNamespaces.append( nsentry );
1719 if ( prefix.right( 1 ) == delim ) {
1721 prefix.resize( prefix.length() );
1723 namespaceToDelimiter[prefix] = delim;
1727 }
else if ( result[0] ==
')' )
1731 }
else if ( result[0] ==
'N' )
1735 parseOneWordC( result );
1738 parseOneWordC( result );
1741 if ( !delimEmpty.isEmpty() ) {
1743 namespaceToDelimiter[TQString()] = delimEmpty;
1744 if ( !personalAvailable )
1747 kdDebug(7116) <<
"imapParser::parseNamespace - registering own personal ns" << endl;
1748 TQString nsentry =
"0==" + delimEmpty;
1749 imapNamespaces.append( nsentry );
1754 int imapParser::parseLoop ()
1758 if (!parseReadLine(result.data))
return -1;
1762 if (result.data.isEmpty())
1764 if (!sentQueue.count ())
1767 kdDebug(7116) <<
"imapParser::parseLoop - unhandledResponse: \n" << result.cstr() << endl;
1768 unhandled << result.cstr();
1776 result.data.resize(result.data.size() - 2);
1777 parseUntagged (result);
1780 continuation.duplicate(result.data);
1784 TQCString tag = parseLiteralC(result);
1785 if (current->
id() == tag.data())
1787 result.data.resize(result.data.size() - 2);
1788 TQByteArray resultCode = parseLiteral (result);
1793 sentQueue.removeRef (current);
1794 completeQueue.append (current);
1795 if (result.length())
1796 parseResult (resultCode, result, current->
command());
1800 kdDebug(7116) <<
"imapParser::parseLoop - unknown tag '" << tag <<
"'" << endl;
1801 TQCString cstr = tag +
" " + result.cstr();
1804 result.data.resize(cstr.length());
1815 imapParser::parseRelay (
const TQByteArray & buffer)
1819 (
"imapParser::parseRelay - virtual function not reimplemented - data lost");
1823 imapParser::parseRelay (ulong len)
1827 (
"imapParser::parseRelay - virtual function not reimplemented - announcement lost");
1830 bool imapParser::parseRead (TQByteArray & buffer, ulong len, ulong relay)
1836 (
"imapParser::parseRead - virtual function not reimplemented - no data read");
1840 bool imapParser::parseReadLine (TQByteArray & buffer, ulong relay)
1845 (
"imapParser::parseReadLine - virtual function not reimplemented - no data read");
1850 imapParser::parseWriteLine (
const TQString & str)
1854 (
"imapParser::parseWriteLine - virtual function not reimplemented - no data written");
1858 imapParser::parseURL (
const KURL & _url, TQString & _box, TQString & _section,
1859 TQString & _type, TQString & _uid, TQString & _validity, TQString & _info)
1861 TQStringList parameters;
1863 _box = _url.path ();
1864 kdDebug(7116) <<
"imapParser::parseURL " << _box << endl;
1865 int paramStart = _box.find(
"/;");
1866 if ( paramStart > -1 )
1868 TQString paramString = _box.right( _box.length() - paramStart-2 );
1869 parameters = TQStringList::split (
';', paramString);
1870 _box.truncate( paramStart );
1873 for (TQStringList::ConstIterator it (parameters.begin ());
1874 it != parameters.end (); ++it)
1876 TQString temp = (*it);
1878 int pt = temp.find (
'/');
1881 if (temp.findRev (
'"', pt) == -1 || temp.find(
'"', pt) == -1)
1887 if (temp.find (
"section=", 0,
false) == 0)
1888 _section = temp.right (temp.length () - 8);
1889 else if (temp.find (
"type=", 0,
false) == 0)
1890 _type = temp.right (temp.length () - 5);
1891 else if (temp.find (
"uid=", 0,
false) == 0)
1892 _uid = temp.right (temp.length () - 4);
1893 else if (temp.find (
"uidvalidity=", 0,
false) == 0)
1894 _validity = temp.right (temp.length () - 12);
1895 else if (temp.find (
"info=", 0,
false) == 0)
1896 _info = temp.right (temp.length () - 5);
1903 if (!_box.isEmpty ())
1907 _box = _box.right (_box.length () - 1);
1908 if (!_box.isEmpty () && _box[_box.length () - 1] ==
'/')
1909 _box.truncate(_box.length() - 1);
1911 kdDebug(7116) <<
"URL: box= " << _box <<
", section= " << _section <<
", type= "
1912 << _type <<
", uid= " << _uid <<
", validity= " << _validity <<
", info= " << _info << endl;
1916 TQCString imapParser::parseLiteralC(
parseString & inWords,
bool relay,
bool stopAtBracket,
int *outlen) {
1918 if (!inWords.isEmpty() && inWords[0] ==
'{')
1921 long srunLen = inWords.find (
'}', 1);
1924 ulong runLen = (ulong)srunLen;
1926 ulong runLenSave = runLen + 1;
1927 TQCString tmpstr(runLen);
1928 inWords.takeMidNoResize(tmpstr, 1, runLen - 1);
1929 runLen = tmpstr.toULong (&proper);
1930 inWords.pos += runLenSave;
1935 parseRelay (runLen);
1937 parseRead (rv, runLen, relay ? runLen : 0);
1938 rv.resize(TQMAX(runLen, rv.size()));
1941 parseReadLine (inWords.data);
1948 kdDebug(7116) <<
"imapParser::parseLiteral - error parsing {} - " << endl;
1954 kdDebug(7116) <<
"imapParser::parseLiteral - error parsing unmatched {" << endl;
1957 *outlen = retVal.length();
1963 return parseOneWordC(inWords, stopAtBracket, outlen);
1967 TQCString imapParser::parseOneWordC (
parseString & inWords,
bool stopAtBracket,
int *outLen)
1969 uint retValSize = 0;
1970 uint len = inWords.length();
1975 if (len > 0 && inWords[0] ==
'"')
1979 while (i < len && (inWords[i] !=
'"' || quote))
1981 if (inWords[i] ==
'\\') quote = !quote;
1987 TQCString retVal(i);
1989 inWords.takeLeftNoResize(retVal, i - 1);
1992 for (
unsigned int j = 0; j <= len; j++) {
1993 if (retVal[j] ==
'\\') {
1997 retVal[j - offset] = retVal[j];
1999 retVal[len - offset] = 0;
2000 retValSize = len - offset;
2004 *outLen = retValSize;
2010 kdDebug(7116) <<
"imapParser::parseOneWord - error parsing unmatched \"" << endl;
2011 TQCString retVal = inWords.cstr();
2015 *outLen = retValSize;
2025 for (i = 0; i < len; ++i) {
2026 char ch = inWords[i];
2027 if (ch <=
' ' || ch ==
'(' || ch ==
')' ||
2028 (stopAtBracket && (ch ==
'[' || ch ==
']')))
2032 TQCString retVal(i+1);
2033 inWords.takeLeftNoResize(retVal, i);
2037 if (retVal ==
"NIL") {
2043 *outLen = retValSize;
2049 bool imapParser::parseOneNumber (
parseString & inWords, ulong & num)
2052 num = parseOneWordC(inWords, TRUE).toULong(&valid);
2056 bool imapParser::hasCapability (
const TQString & cap)
2058 TQString c = cap.lower();
2060 for (TQStringList::ConstIterator it = imapCapabilities.begin ();
2061 it != imapCapabilities.end (); ++it)
2064 if ( !(kasciistricmp(c.ascii(), (*it).ascii())) )
2072 void imapParser::removeCapability (
const TQString & cap)
2074 imapCapabilities.remove(cap.lower());
2077 TQString imapParser::namespaceForBox(
const TQString & box )
2079 kdDebug(7116) <<
"imapParse::namespaceForBox " << box << endl;
2080 TQString myNamespace;
2081 if ( !box.isEmpty() )
2083 TQValueList<TQString> list = namespaceToDelimiter.keys();
2084 TQString cleanPrefix;
2085 for ( TQValueList<TQString>::Iterator it = list.begin(); it != list.end(); ++it )
2087 if ( !(*it).isEmpty() && box.find( *it ) != -1 )
encapulate a IMAP command
const TQString & id()
get the id
const TQString getStr()
returns the data to send to the server The function returns the complete data to be sent to the serve...
void setComplete()
set the completed state
const TQString & parameter()
get the parameter
bool isComplete()
is it complete?
const TQString & command()
get the command
void setId(const TQString &)
set the id
void setResultInfo(const TQString &)
set the completed state
const TQString & resultInfo()
get information about the result
void setResult(const TQString &)
set the completed state
const TQString & result()
get the result of the command
a string used during parsing the string allows you to move the effective start of the string using st...
static TQString quoteIMAP(const TQString &src)
replace " with \" and \ with \ " and \ characters
static TQString fromIMAP(const TQString &src)
Convert an IMAP mailbox to a Unicode path.