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 );
335 #endif //HAVE_LIBSASL2
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 )