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 );
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 )
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.