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 <kasciistricmp.h>
60 #include <kasciistringtools.h>
63 static sasl_callback_t callbacks[] = {
64 { SASL_CB_ECHOPROMPT, NULL, NULL },
65 { SASL_CB_NOECHOPROMPT, NULL, NULL },
66 { SASL_CB_GETREALM, NULL, NULL },
67 { SASL_CB_USER, NULL, NULL },
68 { SASL_CB_AUTHNAME, NULL, NULL },
69 { SASL_CB_PASS, NULL, NULL },
70 { SASL_CB_CANON_USER, NULL, NULL },
71 { SASL_CB_LIST_END, NULL, NULL }
75 imapParser::imapParser ()
77 sentQueue.setAutoDelete (
false);
78 completeQueue.setAutoDelete (
true);
79 currentState = ISTATE_NO;
84 imapParser::~imapParser ()
96 while ((pl = parseLoop ()) == 0)
106 aCmd->
setId (TQString::number(commandCounter++));
107 sentQueue.append (aCmd);
109 continuation.resize(0);
110 const TQString& command = aCmd->
command();
112 if (command ==
"SELECT" || command ==
"EXAMINE")
117 currentBox = parseOneWordC(p);
118 kdDebug(7116) <<
"imapParser::sendCommand - setting current box to " << currentBox << endl;
120 else if (command ==
"CLOSE")
123 currentBox = TQString();
125 else if (command.find (
"SEARCH") != -1
126 || command ==
"GETACL"
127 || command ==
"LISTRIGHTS"
128 || command ==
"MYRIGHTS"
129 || command ==
"GETANNOTATION"
130 || command ==
"NAMESPACE"
131 || command ==
"GETQUOTAROOT"
132 || command ==
"GETQUOTA"
133 || command ==
"X-GET-OTHER-USERS"
134 || command ==
"X-GET-DELEGATES"
135 || command ==
"X-GET-OUT-OF-OFFICE")
137 lastResults.clear ();
139 else if (command ==
"LIST"
140 || command ==
"LSUB")
142 listResponses.clear ();
144 parseWriteLine (aCmd->
getStr ());
149 imapParser::clientLogin (
const TQString & aUser,
const TQString & aPass,
150 TQString & resultInfo)
160 if (cmd->
result () ==
"OK")
162 currentState = ISTATE_LOGIN;
166 completeQueue.removeRef (cmd);
172 static bool sasl_interact( TDEIO::SlaveBase *slave, TDEIO::AuthInfo &ai,
void *in )
174 kdDebug(7116) <<
"sasl_interact" << endl;
175 sasl_interact_t *interact = ( sasl_interact_t * ) in;
179 for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
180 if ( interact->id == SASL_CB_AUTHNAME ||
181 interact->id == SASL_CB_PASS ) {
183 if ( ai.username.isEmpty() || ai.password.isEmpty() ) {
184 if (!slave->openPassDlg(ai))
191 interact = ( sasl_interact_t * ) in;
192 while( interact->id != SASL_CB_LIST_END ) {
193 kdDebug(7116) <<
"SASL_INTERACT id: " << interact->id << endl;
194 switch( interact->id ) {
196 case SASL_CB_AUTHNAME:
197 kdDebug(7116) <<
"SASL_CB_[USER|AUTHNAME]: '" << ai.username <<
"'" << endl;
198 interact->result = strdup( ai.username.utf8() );
199 interact->len = strlen( (
const char *) interact->result );
202 kdDebug(7116) <<
"SASL_CB_PASS: [hidden] " << endl;
203 interact->result = strdup( ai.password.utf8() );
204 interact->len = strlen( (
const char *) interact->result );
207 interact->result = 0;
218 imapParser::clientAuthenticate ( TDEIO::SlaveBase *slave, TDEIO::AuthInfo &ai,
219 const TQString & aFTQDN,
const TQString & aAuth,
bool isSSL, TQString & resultInfo)
224 sasl_conn_t *conn = 0;
225 sasl_interact_t *client_interact = 0;
228 const char *mechusing = 0;
229 TQByteArray tmp, challenge;
231 kdDebug(7116) <<
"aAuth: " << aAuth <<
" FTQDN: " << aFTQDN <<
" isSSL: " << isSSL << endl;
234 if (!hasCapability (
"AUTH=" + aAuth))
238 result = sasl_client_new(
"imap",
241 0, 0, callbacks, 0, &conn );
243 if ( result != SASL_OK ) {
244 kdDebug(7116) <<
"sasl_client_new failed with: " << result << endl;
245 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
250 result = sasl_client_start(conn, aAuth.latin1(), &client_interact,
251 hasCapability(
"SASL-IR") ? &out : 0, &outlen, &mechusing);
253 if ( result == SASL_INTERACT ) {
254 if ( !sasl_interact( slave, ai, client_interact ) ) {
255 sasl_dispose( &conn );
259 }
while ( result == SASL_INTERACT );
261 if ( result != SASL_CONTINUE && result != SASL_OK ) {
262 kdDebug(7116) <<
"sasl_client_start failed with: " << result << endl;
263 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
264 sasl_dispose( &conn );
269 tmp.setRawData( out, outlen );
270 KCodecs::base64Encode( tmp, challenge );
271 tmp.resetRawData( out, outlen );
273 TQString firstCommand = aAuth;
274 if ( !challenge.isEmpty() ) {
276 firstCommand += TQString::fromLatin1( challenge.data(), challenge.size() );
278 cmd = sendCommand (
new imapCommand (
"AUTHENTICATE", firstCommand.latin1()));
284 while ((pl = parseLoop()) == 0) ;
286 if (!continuation.isEmpty())
289 if ( continuation.size() > 4 ) {
290 tmp.setRawData( continuation.data() + 2, continuation.size() - 4 );
291 KCodecs::base64Decode( tmp, challenge );
293 tmp.resetRawData( continuation.data() + 2, continuation.size() - 4 );
297 result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(),
302 if (result == SASL_INTERACT) {
303 if ( !sasl_interact( slave, ai, client_interact ) ) {
304 sasl_dispose( &conn );
308 }
while ( result == SASL_INTERACT );
310 if ( result != SASL_CONTINUE && result != SASL_OK ) {
311 kdDebug(7116) <<
"sasl_client_step failed with: " << result << endl;
312 resultInfo = TQString::fromUtf8( sasl_errdetail( conn ) );
313 sasl_dispose( &conn );
317 tmp.setRawData( out, outlen );
319 KCodecs::base64Encode( tmp, challenge );
320 tmp.resetRawData( out, outlen );
322 parseWriteLine (challenge);
323 continuation.resize(0);
327 if (cmd->
result () ==
"OK")
329 currentState = ISTATE_LOGIN;
333 completeQueue.removeRef (cmd);
335 sasl_dispose( &conn );
336 #endif //HAVE_LIBSASL2
345 parseOneWordC(result);
346 TQByteArray what = parseLiteral (result);
348 if(!what.isEmpty ()) {
353 if (tqstrncmp(what,
"BAD", what.size()) == 0)
355 parseResult (what, result);
357 else if (tqstrncmp(what,
"BYE", what.size()) == 0)
359 parseResult (what, result);
360 if ( sentQueue.count() ) {
365 currentState = ISTATE_NO;
370 if (what[1] ==
'O' && what.size() == 2)
372 parseResult (what, result);
374 else if (tqstrncmp(what,
"NAMESPACE", what.size()) == 0)
376 parseNamespace (result);
381 if (what[1] ==
'K' && what.size() == 2)
383 parseResult (what, result);
384 }
else if (tqstrncmp(what,
"OTHER-USER", 10) == 0) {
385 parseOtherUser (result);
386 }
else if (tqstrncmp(what,
"OUT-OF-OFFICE", 13) == 0) {
387 parseOutOfOffice (result);
391 if (tqstrncmp(what,
"DELEGATE", 8) == 0) {
392 parseDelegate (result);
397 if (tqstrncmp(what,
"PREAUTH", what.size()) == 0)
399 parseResult (what, result);
400 currentState = ISTATE_LOGIN;
406 if (tqstrncmp(what,
"CAPABILITY", what.size()) == 0)
408 parseCapability (result);
413 if (tqstrncmp(what,
"FLAGS", what.size()) == 0)
420 if (tqstrncmp(what,
"LIST", what.size()) == 0)
424 else if (tqstrncmp(what,
"LSUB", what.size()) == 0)
428 else if (tqstrncmp(what,
"LISTRIGHTS", what.size()) == 0)
430 parseListRights (result);
435 if (tqstrncmp(what,
"MYRIGHTS", what.size()) == 0)
437 parseMyRights (result);
441 if (tqstrncmp(what,
"SEARCH", what.size()) == 0)
443 parseSearch (result);
445 else if (tqstrncmp(what,
"STATUS", what.size()) == 0)
447 parsetStatus (result);
452 if (tqstrncmp(what,
"ACL", what.size()) == 0)
456 else if (tqstrncmp(what,
"ANNOTATION", what.size()) == 0)
458 parseAnnotation (result);
462 if ( what.size() > 5 && tqstrncmp(what,
"QUOTAROOT", what.size()) == 0)
464 parseQuotaRoot( result );
466 else if (tqstrncmp(what,
"QUOTA", what.size()) == 0)
468 parseQuota( result );
473 parseCustom( result );
482 number = TQCString(what, what.size() + 1).toUInt(&valid);
485 what = parseLiteral (result);
486 if(!what.isEmpty ()) {
490 if (tqstrncmp(what,
"EXISTS", what.size()) == 0)
492 parseExists (number, result);
494 else if (tqstrncmp(what,
"EXPUNGE", what.size()) == 0)
496 parseExpunge (number, result);
501 if (tqstrncmp(what,
"FETCH", what.size()) == 0)
503 seenUid = TQString();
504 parseFetch (number, result);
509 if (tqstrncmp(what,
"STORE", what.size()) == 0)
511 seenUid = TQString();
512 parseFetch (number, result);
517 if (tqstrncmp(what,
"RECENT", what.size()) == 0)
519 parseRecent (number, result);
535 imapParser::parseResult (TQByteArray & result,
parseString & rest,
536 const TQString & command)
538 if (command ==
"SELECT")
539 selectInfo.setReadWrite(
true);
544 TQCString option = parseOneWordC(rest, TRUE);
549 if (option ==
"ALERT")
551 rest.pos = rest.data.find(
']', rest.pos) + 1;
554 selectInfo.setAlert( rest.cstr() );
559 if (option ==
"NEWNAME")
565 if (option ==
"PARSE")
568 else if (option ==
"PERMANENTFLAGS")
570 uint end = rest.data.find(
']', rest.pos);
571 TQCString flags(rest.data.data() + rest.pos, end - rest.pos);
572 selectInfo.setPermanentFlags (flags);
578 if (option ==
"READ-ONLY")
580 selectInfo.setReadWrite (
false);
582 else if (option ==
"READ-WRITE")
584 selectInfo.setReadWrite (
true);
589 if (option ==
"TRYCREATE")
595 if (option ==
"UIDVALIDITY")
598 if (parseOneNumber (rest, value))
599 selectInfo.setUidValidity (value);
601 else if (option ==
"UNSEEN")
604 if (parseOneNumber (rest, value))
605 selectInfo.setUnseen (value);
607 else if (option ==
"UIDNEXT")
610 if (parseOneNumber (rest, value))
611 selectInfo.setUidNext (value);
622 if (command.isEmpty())
629 switch (command[0].latin1 ())
632 if (command ==
"AUTHENTICATE")
633 if (tqstrncmp(result,
"OK", result.size()) == 0)
634 currentState = ISTATE_LOGIN;
638 if (command ==
"LOGIN")
639 if (tqstrncmp(result,
"OK", result.size()) == 0)
640 currentState = ISTATE_LOGIN;
644 if (command ==
"EXAMINE")
646 if (tqstrncmp(result,
"OK", result.size()) == 0)
647 currentState = ISTATE_SELECT;
650 if (currentState == ISTATE_SELECT)
651 currentState = ISTATE_LOGIN;
652 currentBox = TQString();
654 kdDebug(7116) <<
"imapParser::parseResult - current box is now " << currentBox << endl;
659 if (command ==
"SELECT")
661 if (tqstrncmp(result,
"OK", result.size()) == 0)
662 currentState = ISTATE_SELECT;
665 if (currentState == ISTATE_SELECT)
666 currentState = ISTATE_LOGIN;
667 currentBox = TQString();
669 kdDebug(7116) <<
"imapParser::parseResult - current box is now " << currentBox << endl;
679 void imapParser::parseCapability (
parseString & result)
681 TQCString temp( result.cstr() );
682 imapCapabilities = TQStringList::split (
' ', KPIM::kAsciiToLower( temp.data() ) );
687 selectInfo.setFlags(result.cstr());
694 if (result[0] !=
'(')
699 this_one.parseAttributes( result );
704 this_one.setHierarchyDelimiter(parseLiteralC(result));
707 listResponses.append (this_one);
712 imapList this_one (result.cstr(), *
this);
713 listResponses.append (this_one);
716 void imapParser::parseListRights (
parseString & result)
718 parseOneWordC (result);
719 parseOneWordC (result);
722 TQCString word = parseOneWordC (result,
false, &outlen);
723 lastResults.append (word);
729 parseOneWordC (result);
732 while ( outlen && !result.isEmpty() ) {
733 TQCString word = parseLiteralC (result,
false,
false, &outlen);
734 lastResults.append (word);
738 void imapParser::parseAnnotation (
parseString & result)
740 parseOneWordC (result);
742 parseOneWordC (result);
744 if (result.isEmpty() || result[0] !=
'(')
750 while ( outlen && !result.isEmpty() && result[0] !=
')' ) {
751 TQCString word = parseLiteralC (result,
false,
false, &outlen);
752 lastResults.append (word);
762 TQCString root = parseOneWordC( result );
763 if ( root.isEmpty() ) {
764 lastResults.append(
"" );
766 lastResults.append( root );
768 if (result.isEmpty() || result[0] !=
'(')
772 TQStringList triplet;
774 while ( outlen && !result.isEmpty() && result[0] !=
')' ) {
775 TQCString word = parseLiteralC (result,
false,
false, &outlen);
776 triplet.append(word);
778 lastResults.append( triplet.join(
" ") );
781 void imapParser::parseQuotaRoot (
parseString & result)
785 parseOneWordC (result);
787 if ( result.isEmpty() )
791 while ( outlen && !result.isEmpty() ) {
792 TQCString word = parseLiteralC (result,
false,
false, &outlen);
795 lastResults.append( roots.isEmpty()?
"" : roots.join(
" ") );
798 void imapParser::parseCustom (
parseString & result)
801 TQCString word = parseLiteralC (result,
false,
false, &outlen);
802 lastResults.append( word );
805 void imapParser::parseOtherUser (
parseString & result)
807 lastResults.append( parseOneWordC( result ) );
810 void imapParser::parseDelegate (
parseString & result)
812 const TQString email = parseOneWordC( result );
816 while ( outlen && !result.isEmpty() ) {
817 TQCString word = parseLiteralC( result,
false,
false, &outlen );
818 rights.append( word );
821 lastResults.append( email +
":" + rights.join(
"," ) );
824 void imapParser::parseOutOfOffice (
parseString & result)
826 const TQString state = parseOneWordC (result);
827 parseOneWordC (result);
830 TQCString msg = parseLiteralC (result,
false,
false, &outlen);
832 lastResults.append( state +
"^" + TQString::fromUtf8( msg ) );
835 void imapParser::parseMyRights (
parseString & result)
837 parseOneWordC (result);
838 Q_ASSERT( lastResults.isEmpty() );
839 lastResults.append (parseOneWordC (result) );
842 void imapParser::parseSearch (
parseString & result)
846 while (parseOneNumber (result, value))
848 lastResults.append (TQString::number(value));
852 void imapParser::parsetStatus (
parseString & inWords)
854 lasStatus = imapInfo ();
856 parseLiteralC(inWords);
857 if (inWords.isEmpty() || inWords[0] !=
'(')
863 while (!inWords.isEmpty() && inWords[0] !=
')')
867 TQCString label = parseOneWordC(inWords);
868 if (parseOneNumber (inWords, value))
870 if (label ==
"MESSAGES")
871 lasStatus.setCount (value);
872 else if (label ==
"RECENT")
873 lasStatus.setRecent (value);
874 else if (label ==
"UIDVALIDITY")
875 lasStatus.setUidValidity (value);
876 else if (label ==
"UNSEEN")
877 lasStatus.setUnseen (value);
878 else if (label ==
"UIDNEXT")
879 lasStatus.setUidNext (value);
883 if (inWords[0] ==
')')
888 void imapParser::parseExists (ulong value,
parseString & result)
890 selectInfo.setCount (value);
891 result.pos = result.data.size();
894 void imapParser::parseExpunge (ulong value,
parseString & result)
900 void imapParser::parseAddressList (
parseString & inWords, TQPtrList<mailAddress>& list)
902 if (inWords.isEmpty())
904 if (inWords[0] !=
'(')
906 parseOneWordC (inWords);
913 while (!inWords.isEmpty () && inWords[0] !=
')')
915 if (inWords[0] ==
'(') {
916 mailAddress *addr =
new mailAddress;
917 parseAddress(inWords, *addr);
924 if (!inWords.isEmpty() && inWords[0] ==
')')
930 const mailAddress& imapParser::parseAddress (
parseString & inWords, mailAddress& retVal)
935 retVal.setFullName(parseLiteralC(inWords));
936 retVal.setCommentRaw(parseLiteralC(inWords));
937 retVal.setUser(parseLiteralC(inWords));
938 retVal.setHost(parseLiteralC(inWords));
940 if (!inWords.isEmpty() && inWords[0] ==
')')
951 if (inWords[0] !=
'(')
959 envelope->
setDate(parseLiteralC(inWords));
964 TQPtrList<mailAddress> list;
965 list.setAutoDelete(
true);
968 parseAddressList(inWords, list);
969 if (!list.isEmpty()) {
970 envelope->setFrom(*list.last());
975 parseAddressList(inWords, list);
976 if (!list.isEmpty()) {
977 envelope->setSender(*list.last());
982 parseAddressList(inWords, list);
983 if (!list.isEmpty()) {
984 envelope->setReplyTo(*list.last());
989 parseAddressList (inWords, envelope->to());
992 parseAddressList (inWords, envelope->cc());
995 parseAddressList (inWords, envelope->bcc());
998 envelope->setInReplyTo(parseLiteralC(inWords));
1001 envelope->setMessageId(parseLiteralC(inWords));
1004 while (!inWords.isEmpty () && inWords[0] !=
')')
1007 if (inWords[0] ==
'(')
1008 parseSentence (inWords);
1010 parseLiteralC (inWords);
1013 if (!inWords.isEmpty() && inWords[0] ==
')')
1022 TQAsciiDict < TQString > imapParser::parseDisposition (
parseString & inWords)
1024 TQCString disposition;
1025 TQAsciiDict < TQString > retVal (17,
false);
1028 retVal.setAutoDelete (
false);
1030 if (inWords[0] !=
'(')
1033 disposition = parseOneWordC (inWords);
1041 disposition = parseOneWordC (inWords);
1042 retVal = parseParameters (inWords);
1043 if (inWords[0] !=
')')
1049 if (!disposition.isEmpty ())
1051 retVal.insert (
"content-disposition",
new TQString(disposition));
1059 TQAsciiDict < TQString > imapParser::parseParameters (
parseString & inWords)
1061 TQAsciiDict < TQString > retVal (17,
false);
1064 retVal.setAutoDelete (
false);
1066 if (inWords[0] !=
'(')
1069 parseOneWordC (inWords);
1076 while (!inWords.isEmpty () && inWords[0] !=
')')
1078 TQCString l1 = parseLiteralC(inWords);
1079 TQCString l2 = parseLiteralC(inWords);
1080 retVal.insert (l1,
new TQString(l2));
1083 if (inWords[0] !=
')')
1093 TQString & inSection,
mimeHeader * localPart)
1097 TQAsciiDict < TQString > parameters (17,
false);
1100 parameters.setAutoDelete (
true);
1102 if (inWords[0] !=
'(')
1108 localPart->setPartSpecifier (inSection);
1114 typeStr = parseLiteralC(inWords);
1117 subtype = parseLiteralC(inWords);
1119 localPart->setType (typeStr +
"/" + subtype);
1122 parameters = parseParameters (inWords);
1124 TQAsciiDictIterator < TQString > it (parameters);
1126 while (it.current ())
1128 localPart->setTypeParm (it.currentKey (), *(it.current ()));
1131 parameters.clear ();
1135 localPart->setID (parseLiteralC(inWords));
1138 localPart->setDescription (parseLiteralC(inWords));
1141 localPart->setEncoding (parseLiteralC(inWords));
1144 if (parseOneNumber (inWords, size))
1145 localPart->setLength (size);
1148 if (localPart->getType().upper() ==
"MESSAGE/RFC822")
1151 mailHeader *envelope = parseEnvelope (inWords);
1154 parseBodyStructure (inWords, inSection, envelope);
1156 localPart->setNestedMessage (envelope);
1160 parseOneNumber (inWords, lines);
1164 if (typeStr ==
"TEXT")
1168 parseOneNumber (inWords, lines);
1172 parseLiteralC(inWords);
1175 parameters = parseDisposition (inWords);
1177 TQString *disposition = parameters[
"content-disposition"];
1180 localPart->setDisposition (disposition->ascii ());
1181 parameters.remove (
"content-disposition");
1182 TQAsciiDictIterator < TQString > it (parameters);
1183 while (it.current ())
1185 localPart->setDispositionParm (it.currentKey (),
1190 parameters.clear ();
1194 parseSentence (inWords);
1198 while (!inWords.isEmpty () && inWords[0] !=
')')
1201 if (inWords[0] ==
'(')
1202 parseSentence (inWords);
1204 parseLiteralC(inWords);
1206 if (inWords[0] ==
')')
1214 TQString & inSection,
mimeHeader * localPart)
1217 if (inSection.isEmpty())
1226 if (inWords[0] !=
'(')
1229 parseOneWordC (inWords);
1235 if (inWords[0] ==
'(')
1237 TQByteArray subtype;
1238 TQAsciiDict < TQString > parameters (17,
false);
1239 TQString outSection;
1240 parameters.setAutoDelete (
true);
1246 localPart->clearNestedParts ();
1247 localPart->clearTypeParameters ();
1248 localPart->clearDispositionParameters ();
1250 outSection = inSection +
".HEADER";
1252 if (inWords[0] ==
'(' && init)
1256 if ( !outSection.isEmpty() ) {
1257 localPart->setPartSpecifier(outSection);
1259 localPart->setPartSpecifier(inSection);
1263 while (inWords[0] ==
'(')
1265 outSection = TQString::number(++section);
1267 outSection = inSection +
"." + outSection;
1268 mimeHeader *subpart = parseBodyStructure (inWords, outSection, 0);
1269 localPart->addNestedPart (subpart);
1273 subtype = parseOneWordC (inWords);
1275 localPart->setType (
"MULTIPART/" + b2c(subtype));
1278 parameters = parseParameters (inWords);
1280 TQAsciiDictIterator < TQString > it (parameters);
1282 while (it.current ())
1284 localPart->setTypeParm (it.currentKey (), *(it.current ()));
1287 parameters.clear ();
1291 parameters = parseDisposition (inWords);
1293 TQString *disposition = parameters[
"content-disposition"];
1296 localPart->setDisposition (disposition->ascii ());
1297 parameters.remove (
"content-disposition");
1298 TQAsciiDictIterator < TQString > it (parameters);
1299 while (it.current ())
1301 localPart->setDispositionParm (it.currentKey (),
1305 parameters.clear ();
1309 parseSentence (inWords);
1316 inWords.data[inWords.pos] =
'(';
1318 inSection = inSection +
".1";
1319 localPart = parseSimplePart (inWords, inSection, localPart);
1321 inWords.data[inWords.pos] =
')';
1325 while (!inWords.isEmpty () && inWords[0] !=
')')
1328 if (inWords[0] ==
'(')
1329 parseSentence (inWords);
1331 parseLiteralC(inWords);
1334 if (inWords[0] ==
')')
1341 void imapParser::parseBody (
parseString & inWords)
1344 if (inWords[0] ==
'[')
1346 TQCString specifier;
1350 specifier = parseOneWordC (inWords, TRUE);
1352 if (inWords[0] ==
'(')
1356 while (!inWords.isEmpty () && inWords[0] !=
')')
1358 label = parseOneWordC (inWords);
1361 if (!inWords.isEmpty () && inWords[0] ==
')')
1364 if (!inWords.isEmpty () && inWords[0] ==
']')
1369 if (specifier ==
"0")
1373 envelope = lastHandled->getHeader ();
1375 if (!envelope || seenUid.isEmpty ())
1377 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1379 parseLiteralC(inWords,
true);
1383 kdDebug(7116) <<
"imapParser::parseBody - reading " << envelope <<
" " << seenUid.ascii () << endl;
1385 TQString theHeader = parseLiteralC(inWords,
true);
1386 mimeIOTQString myIO;
1388 myIO.setString (theHeader);
1389 envelope->parseHeader (myIO);
1393 else if (specifier ==
"HEADER.FIELDS")
1398 if (label ==
"REFERENCES")
1402 envelope = lastHandled->getHeader ();
1404 if (!envelope || seenUid.isEmpty ())
1406 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1408 parseLiteralC (inWords,
true);
1412 TQCString references = parseLiteralC(inWords,
true);
1413 int start = references.find (
'<');
1414 int end = references.findRev (
'>');
1416 references = references.mid (start, end - start + 1);
1417 envelope->setReferences(references.simplifyWhiteSpace());
1422 parseLiteralC(inWords,
true);
1427 if (specifier.find(
".MIME") != -1)
1430 TQString theHeader = parseLiteralC(inWords,
false);
1431 mimeIOTQString myIO;
1432 myIO.setString (theHeader);
1433 envelope->parseHeader (myIO);
1435 lastHandled->setHeader (envelope);
1439 kdDebug(7116) <<
"imapParser::parseBody - discarding " << seenUid.ascii () << endl;
1440 parseLiteralC(inWords,
true);
1448 envelope = lastHandled->getHeader ();
1450 if (!envelope || seenUid.isEmpty ())
1452 kdDebug(7116) <<
"imapParser::parseBody - discarding " << envelope <<
" " << seenUid.ascii () << endl;
1454 parseSentence (inWords);
1458 kdDebug(7116) <<
"imapParser::parseBody - reading " << envelope <<
" " << seenUid.ascii () << endl;
1461 mimeHeader *body = parseBodyStructure (inWords, section, envelope);
1462 if (body != envelope)
1468 void imapParser::parseFetch (ulong ,
parseString & inWords)
1470 if (inWords[0] !=
'(')
1478 while (!inWords.isEmpty () && inWords[0] !=
')')
1480 if (inWords[0] ==
'(')
1481 parseSentence (inWords);
1484 TQCString word = parseLiteralC(inWords,
false,
true);
1486 if(!word.isEmpty()) {
1490 if (word ==
"ENVELOPE")
1495 envelope = lastHandled->getHeader ();
1497 lastHandled =
new imapCache();
1499 if (envelope && !envelope->getMessageId ().isEmpty ())
1503 parseSentence (inWords);
1507 envelope = parseEnvelope (inWords);
1510 envelope->setPartSpecifier (seenUid +
".0");
1511 lastHandled->setHeader (envelope);
1512 lastHandled->setUid (seenUid.toULong ());
1521 parseBody (inWords);
1523 else if (word ==
"BODY[]" )
1526 parseLiteralC(inWords,
true);
1528 else if (word ==
"BODYSTRUCTURE")
1533 envelope = lastHandled->getHeader ();
1538 parseBodyStructure (inWords, section, envelope);
1540 TQDataStream stream( data, IO_WriteOnly );
1541 if (body) body->serialize(stream);
1551 seenUid = parseOneWordC(inWords);
1554 envelope = lastHandled->getHeader ();
1556 lastHandled =
new imapCache();
1558 if (seenUid.isEmpty ())
1561 kdDebug(7116) <<
"imapParser::parseFetch - UID empty" << endl;
1565 lastHandled->setUid (seenUid.toULong ());
1568 envelope->setPartSpecifier (seenUid);
1573 if (word ==
"RFC822.SIZE")
1576 parseOneNumber (inWords, size);
1578 if (!lastHandled) lastHandled =
new imapCache();
1579 lastHandled->setSize (size);
1581 else if (word.find (
"RFC822") == 0)
1584 parseLiteralC(inWords,
true);
1589 if (word ==
"INTERNALDATE")
1591 TQCString date = parseOneWordC(inWords);
1592 if (!lastHandled) lastHandled =
new imapCache();
1593 lastHandled->setDate(date);
1598 if (word ==
"FLAGS")
1601 if (!lastHandled) lastHandled =
new imapCache();
1602 lastHandled->setFlags (imapInfo::_flags (inWords.cstr()));
1607 parseLiteralC(inWords);
1611 parseLiteralC(inWords);
1617 while (!inWords.isEmpty () && inWords[0] !=
')')
1620 if (inWords[0] ==
'(')
1621 parseSentence (inWords);
1623 parseLiteralC(inWords);
1626 if (inWords.isEmpty() || inWords[0] !=
')')
1634 void imapParser::parseSentence (
parseString & inWords)
1641 while (!inWords.isEmpty () && (stack != 0 || first))
1646 unsigned char ch = inWords[0];
1666 parseLiteralC(inWords);
1674 void imapParser::parseRecent (ulong value,
parseString & result)
1676 selectInfo.setRecent (value);
1677 result.pos = result.data.size();
1680 void imapParser::parseNamespace (
parseString & result)
1682 if ( result[0] !=
'(' )
1685 TQString delimEmpty;
1686 if ( namespaceToDelimiter.contains( TQString() ) )
1687 delimEmpty = namespaceToDelimiter[TQString()];
1689 namespaceToDelimiter.clear();
1690 imapNamespaces.clear();
1694 bool personalAvailable =
false;
1695 while ( !result.isEmpty() )
1697 if ( result[0] ==
'(' )
1700 if ( result[0] ==
'(' )
1707 TQCString prefix = parseOneWordC( result );
1709 TQCString delim = parseOneWordC( result );
1710 kdDebug(7116) <<
"imapParser::parseNamespace ns='" << prefix <<
1711 "',delim='" << delim <<
"'" << endl;
1715 personalAvailable =
true;
1717 TQString nsentry = TQString::number( ns ) +
"=" + TQString(prefix) +
1718 "=" + TQString(delim);
1719 imapNamespaces.append( nsentry );
1720 if ( prefix.right( 1 ) == delim ) {
1722 prefix.resize( prefix.length() );
1724 namespaceToDelimiter[prefix] = delim;
1728 }
else if ( result[0] ==
')' )
1732 }
else if ( result[0] ==
'N' )
1736 parseOneWordC( result );
1739 parseOneWordC( result );
1742 if ( !delimEmpty.isEmpty() ) {
1744 namespaceToDelimiter[TQString()] = delimEmpty;
1745 if ( !personalAvailable )
1748 kdDebug(7116) <<
"imapParser::parseNamespace - registering own personal ns" << endl;
1749 TQString nsentry =
"0==" + delimEmpty;
1750 imapNamespaces.append( nsentry );
1755 int imapParser::parseLoop ()
1759 if (!parseReadLine(result.data))
return -1;
1763 if (result.data.isEmpty())
1765 if (!sentQueue.count ())
1768 kdDebug(7116) <<
"imapParser::parseLoop - unhandledResponse: \n" << result.cstr() << endl;
1769 unhandled << result.cstr();
1777 result.data.resize(result.data.size() - 2);
1778 parseUntagged (result);
1781 continuation.duplicate(result.data);
1785 TQCString tag = parseLiteralC(result);
1786 if (current->
id() == tag.data())
1788 result.data.resize(result.data.size() - 2);
1789 TQByteArray resultCode = parseLiteral (result);
1794 sentQueue.removeRef (current);
1795 completeQueue.append (current);
1796 if (result.length())
1797 parseResult (resultCode, result, current->
command());
1801 kdDebug(7116) <<
"imapParser::parseLoop - unknown tag '" << tag <<
"'" << endl;
1802 TQCString cstr = tag +
" " + result.cstr();
1805 result.data.resize(cstr.length());
1816 imapParser::parseRelay (
const TQByteArray & buffer)
1820 (
"imapParser::parseRelay - virtual function not reimplemented - data lost");
1824 imapParser::parseRelay (ulong len)
1828 (
"imapParser::parseRelay - virtual function not reimplemented - announcement lost");
1831 bool imapParser::parseRead (TQByteArray & buffer, ulong len, ulong relay)
1837 (
"imapParser::parseRead - virtual function not reimplemented - no data read");
1841 bool imapParser::parseReadLine (TQByteArray & buffer, ulong relay)
1846 (
"imapParser::parseReadLine - virtual function not reimplemented - no data read");
1851 imapParser::parseWriteLine (
const TQString & str)
1855 (
"imapParser::parseWriteLine - virtual function not reimplemented - no data written");
1859 imapParser::parseURL (
const KURL & _url, TQString & _box, TQString & _section,
1860 TQString & _type, TQString & _uid, TQString & _validity, TQString & _info)
1862 TQStringList parameters;
1864 _box = _url.path ();
1865 kdDebug(7116) <<
"imapParser::parseURL " << _box << endl;
1866 int paramStart = _box.find(
"/;");
1867 if ( paramStart > -1 )
1869 TQString paramString = _box.right( _box.length() - paramStart-2 );
1870 parameters = TQStringList::split (
';', paramString);
1871 _box.truncate( paramStart );
1874 for (TQStringList::ConstIterator it (parameters.begin ());
1875 it != parameters.end (); ++it)
1877 TQString temp = (*it);
1879 int pt = temp.find (
'/');
1882 if (temp.findRev (
'"', pt) == -1 || temp.find(
'"', pt) == -1)
1888 if (temp.find (
"section=", 0,
false) == 0)
1889 _section = temp.right (temp.length () - 8);
1890 else if (temp.find (
"type=", 0,
false) == 0)
1891 _type = temp.right (temp.length () - 5);
1892 else if (temp.find (
"uid=", 0,
false) == 0)
1893 _uid = temp.right (temp.length () - 4);
1894 else if (temp.find (
"uidvalidity=", 0,
false) == 0)
1895 _validity = temp.right (temp.length () - 12);
1896 else if (temp.find (
"info=", 0,
false) == 0)
1897 _info = temp.right (temp.length () - 5);
1904 if (!_box.isEmpty ())
1908 _box = _box.right (_box.length () - 1);
1909 if (!_box.isEmpty () && _box[_box.length () - 1] ==
'/')
1910 _box.truncate(_box.length() - 1);
1912 kdDebug(7116) <<
"URL: box= " << _box <<
", section= " << _section <<
", type= "
1913 << _type <<
", uid= " << _uid <<
", validity= " << _validity <<
", info= " << _info << endl;
1917 TQCString imapParser::parseLiteralC(
parseString & inWords,
bool relay,
bool stopAtBracket,
int *outlen) {
1919 if (!inWords.isEmpty() && inWords[0] ==
'{')
1922 long srunLen = inWords.find (
'}', 1);
1925 ulong runLen = (ulong)srunLen;
1927 ulong runLenSave = runLen + 1;
1928 TQCString tmpstr(runLen);
1929 inWords.takeMidNoResize(tmpstr, 1, runLen - 1);
1930 runLen = tmpstr.toULong (&proper);
1931 inWords.pos += runLenSave;
1936 parseRelay (runLen);
1938 parseRead (rv, runLen, relay ? runLen : 0);
1939 rv.resize(TQMAX(runLen, rv.size()));
1942 parseReadLine (inWords.data);
1949 kdDebug(7116) <<
"imapParser::parseLiteral - error parsing {} - " << endl;
1955 kdDebug(7116) <<
"imapParser::parseLiteral - error parsing unmatched {" << endl;
1958 *outlen = retVal.length();
1964 return parseOneWordC(inWords, stopAtBracket, outlen);
1968 TQCString imapParser::parseOneWordC (
parseString & inWords,
bool stopAtBracket,
int *outLen)
1970 uint retValSize = 0;
1971 uint len = inWords.length();
1976 if (len > 0 && inWords[0] ==
'"')
1980 while (i < len && (inWords[i] !=
'"' || quote))
1982 if (inWords[i] ==
'\\') quote = !quote;
1988 TQCString retVal(i);
1990 inWords.takeLeftNoResize(retVal, i - 1);
1993 for (
unsigned int j = 0; j <= len; j++) {
1994 if (retVal[j] ==
'\\') {
1998 retVal[j - offset] = retVal[j];
2000 retVal[len - offset] = 0;
2001 retValSize = len - offset;
2005 *outLen = retValSize;
2011 kdDebug(7116) <<
"imapParser::parseOneWord - error parsing unmatched \"" << endl;
2012 TQCString retVal = inWords.cstr();
2016 *outLen = retValSize;
2026 for (i = 0; i < len; ++i) {
2027 char ch = inWords[i];
2028 if (ch <=
' ' || ch ==
'(' || ch ==
')' ||
2029 (stopAtBracket && (ch ==
'[' || ch ==
']')))
2033 TQCString retVal(i+1);
2034 inWords.takeLeftNoResize(retVal, i);
2038 if (retVal ==
"NIL") {
2044 *outLen = retValSize;
2050 bool imapParser::parseOneNumber (
parseString & inWords, ulong & num)
2053 num = parseOneWordC(inWords, TRUE).toULong(&valid);
2057 bool imapParser::hasCapability (
const TQString & cap)
2059 TQString c = cap.lower();
2061 for (TQStringList::ConstIterator it = imapCapabilities.begin ();
2062 it != imapCapabilities.end (); ++it)
2065 if ( !(kasciistricmp(c.ascii(), (*it).ascii())) )
2073 void imapParser::removeCapability (
const TQString & cap)
2075 imapCapabilities.remove(cap.lower());
2078 TQString imapParser::namespaceForBox(
const TQString & box )
2080 kdDebug(7116) <<
"imapParse::namespaceForBox " << box << endl;
2081 TQString myNamespace;
2082 if ( !box.isEmpty() )
2084 TQValueList<TQString> list = namespaceToDelimiter.keys();
2085 TQString cleanPrefix;
2086 for ( TQValueList<TQString>::Iterator it = list.begin(); it != list.end(); ++it )
2088 if ( !(*it).isEmpty() && box.find( *it ) != -1 )