00001 #include "imapresponse.h"
00002
00003
00004 IMAPResponseParser::IMAPResponseParser()
00005 {
00006 }
00007
00008 void IMAPResponseParser::parse ( const QString &_data )
00009 {
00010 QString data = _data;
00011
00012 int pos = 0;
00013 int len = data. length ( );
00014
00015
00016 while ( pos < len ) {
00017 pos = data. find ( QRegExp ( "[^\\s]" ), pos );
00018
00019 if (( pos < 0 ) || ( pos >= len ))
00020 break;
00021
00022 switch ( data [pos]. latin1 ( )) {
00023 case '*': {
00024 qDebug ( "* ASTERIX\n" );
00025
00026 int eol = data. find ( '\n', pos );
00027 int bracket = data. findRev ( '{', eol );
00028 int rest = data. find ( QRegExp ( "[^\\s]" ), pos + 1 );
00029
00030 qDebug ( "pos=%d, rest=%d, bracket=%d, eol=%d\n", pos, rest, bracket, eol );
00031
00032 if ( bracket > pos ) {
00033 uint needdata = data. mid ( bracket + 1, data. find ( '}', bracket + 1 ) - bracket - 1 ). toUInt ( );
00034
00035 if ( needdata ) {
00036 qDebug ( "nd=%d - hd=%d\n", needdata, ( len - eol - 1 ));
00037
00038 while ( needdata > ( len - eol - 1 )) {
00039 qDebug ( "emitting need more...\n" );
00040 emit needMoreData ( data );
00041 len = data. length ( );
00042 }
00043 qDebug ( "Got all data...\n" );
00044
00045 QString tmp = data. mid ( rest, eol - rest + 1 + needdata );
00046
00047 int tail = 0;
00048
00049 while ( data [eol - rest + 1 + needdata + tail] != ')' )
00050 tail++;
00051 tmp. append ( data. mid ( eol - rest + 1 + needdata, tail + 1 ));
00052
00053
00054 qDebug ( "Complete parse = |%s|\n", tmp.latin1());
00055
00056 parseResponse ( tmp );
00057
00058 pos = rest + needdata + tail + 1;
00059 break;
00060 }
00061 }
00062
00063 parseResponse ( data. mid ( rest, eol - rest + 1 ). stripWhiteSpace ( ));
00064 break;
00065 }
00066 case '+': {
00067 qDebug ( "+ PLUS\n" );
00068
00069 emit needMoreData ( data );
00070 len = data. length ( );
00071 break;
00072 }
00073 default : {
00074 qDebug ( "OTHER: '%s...'\n", data. mid ( pos, 20 ). latin1 ( ));
00075
00076 uint rest = data. find ( ' ', pos + 1 );
00077 rest = data. find ( QRegExp ( "[^\\s]" ), rest + 1 );
00078 _iresponse. setTag ( data. mid ( pos, rest - pos ). stripWhiteSpace ( ));
00079 parseResponse ( data. mid ( rest, data. find ( '\n', rest )). stripWhiteSpace ( ), true );
00080 break;
00081 }
00082 }
00083
00084
00085 while (( pos < len ) && ( data [pos] != '\n' ))
00086 pos++;
00087 }
00088 }
00089
00090
00091 IMAPResponse IMAPResponseParser::response()
00092 {
00093 return _iresponse;
00094 }
00095
00096 void IMAPResponseParser::parseResponse(const QString &data, bool tagged)
00097 {
00098 QString response, line;
00099 int pos;
00100 bool isNum = false;
00101
00102
00103
00104
00105 if ((pos = data.find(' ')) != -1) {
00106 response = data.left(pos).upper();
00107 response.toInt(&isNum);
00108 line = data.right(data.length() - pos - 1);
00109 } else {
00110 qWarning("IMAPResponseParser: parseResponse: No response found.");
00111 return;
00112 }
00113
00114 if (response == "OK" && tagged) {
00115 IMAPResponseStatusResponse status(OK, line);
00116 status.setResponseCode(getResponseCode(status.comment()));
00117 _iresponse.setStatusResponse(status);
00118 } else if (response == "OK" && !tagged) {
00119 IMAPResponseOK ok(line, getResponseCode(line));
00120 _iresponse.addOK(ok);
00121 } else if (response == "NO" && tagged) {
00122 IMAPResponseStatusResponse status(NO, line);
00123 status.setResponseCode(getResponseCode(status.comment()));
00124 _iresponse.setStatusResponse(status);
00125 } else if (response == "NO" && !tagged) {
00126 IMAPResponseNO no(line, getResponseCode(line));
00127 _iresponse.addNO(no);
00128 } else if (response == "BAD" && tagged) {
00129 IMAPResponseStatusResponse status(BAD, line);
00130 status.setResponseCode(getResponseCode(status.comment()));
00131 _iresponse.setStatusResponse(status);
00132 } else if (response == "BAD" && !tagged) {
00133 IMAPResponseBAD bad(line, getResponseCode(line));
00134 _iresponse.addBAD(bad);
00135 } else if (response == "PREAUTH" && tagged) {
00136 IMAPResponseStatusResponse status(PREAUTH, line);
00137 _iresponse.setStatusResponse(status);
00138 } else if (response == "PREAUTH" && !tagged) {
00139 qDebug("IMAPResponseParser: responseParser: got untagged PREAUTH response.");
00140
00141 } else if (response == "BYE") {
00142 IMAPResponseStatusResponse status(BYE, line);
00143 if (!tagged) status.setExitedUnexpected(true);
00144 _iresponse.setStatusResponse(status);
00145 } else if (response == "CAPABILITY") {
00146 IMAPResponseCAPABILITY capability(QStringList::split(' ', line));
00147 _iresponse.addCAPABILITY(capability);
00148 } else if (response == "LIST") {
00149 QStringList list = splitData(line, true);
00150
00151 QStringList flags;
00152 parseParenthesizedList(list[0], flags);
00153
00154 removeLimiters(list[1]);
00155 removeLimiters(list[2]);
00156 IMAPResponseLIST rlist(parseFlagList(flags), list[1], list[2]);
00157 _iresponse.addLIST(rlist);
00158 } else if (response == "LSUB") {
00159 QStringList list = splitData(line, true);
00160
00161 QStringList flags;
00162 parseParenthesizedList(list[0], flags);
00163
00164 removeLimiters(list[1]);
00165 removeLimiters(list[2]);
00166 IMAPResponseLSUB lsub(parseFlagList(flags), list[1], list[2]);
00167 _iresponse.addLSUB(lsub);
00168 } else if (response == "STATUS") {
00169 QStringList list = splitData(line, true);
00170
00171 removeLimiters(list[0]);
00172 IMAPResponseSTATUS status(list[0]);
00173
00174 QStringList flags;
00175 parseParenthesizedList(list[1], flags);
00176 QStringList::Iterator it;
00177 for (it = flags.begin(); it != flags.end(); it++) {
00178 if (*it == "MESSAGES") status.setMessages(*(++it));
00179 else if (*it == "RECENT") status.setRecent(*(++it));
00180 else if (*it == "UIDNEXT") status.setUidnext(*(++it));
00181 else if (*it == "UIDVALIDITY") status.setUidvalidity(*(++it));
00182 else if (*it == "UNSEEN") status.setUnseen(*(++it));
00183 else qWarning((QString("IMAPResponseParser: parseResponse: Unknown status data: " )+ *(it++) + "|").latin1());
00184 }
00185 _iresponse.addSTATUS(status);
00186 } else if (response == "SEARCH") {
00187 IMAPResponseSEARCH search(QStringList::split(' ', line));
00188 _iresponse.addSEARCH(search);
00189 } else if (response == "FLAGS") {
00190 QStringList list;
00191 parseParenthesizedList(line, list);
00192
00193 IMAPResponseFLAGS flags(parseFlagList(list));
00194 _iresponse.addFLAGS(flags);
00195 } else if (isNum) {
00196 QStringList list = QStringList::split(' ', line);
00197 if (list[0] == "EXISTS") {
00198 IMAPResponseEXISTS exists(response);
00199 _iresponse.addEXISTS(exists);
00200 } else if (list[0] == "RECENT") {
00201 IMAPResponseRECENT recent(response);
00202 _iresponse.addRECENT(recent);
00203 } else if (list[0] == "EXPUNGE") {
00204 IMAPResponseEXPUNGE expunge(response);
00205 _iresponse.addEXPUNGE(expunge);
00206 } else if (list[0] == "FETCH") {
00207 IMAPResponseFETCH fetch;
00208 QStringList::Iterator it;
00209
00210 qDebug ( "Got FETCH\n" );
00211
00212 QStringList fetchList = splitData(line, true);
00213 QStringList list;
00214
00215 qDebug ( "fl [0]=%s, fl [1]=%s, fl[2]=%s\n", fetchList[0].latin1(),fetchList[1].latin1(),fetchList[2].latin1());
00216
00217 parseParenthesizedList(fetchList[1], list);
00218
00219 for (it = list.begin(); it != list.end(); it++) {
00220 qDebug ( "Checking list[] == %s\n", (*it).latin1());
00221
00222 if (*it == "BODY") {
00223 qDebug("IMAPResponseParser: responseParser: got FETCH::BODY");
00224
00225 } else if ((*it).find(QRegExp("^BODY\\[\\d+\\]")) != -1) {
00226 qDebug("IMAPResponseParser: responseParser: got FETCH::BODY[x]");
00227
00228 QString number = ( *it ). mid ( 5, ( *it ). length ( ) - 6 );
00229 QString bodydata = *(++it);
00230
00231
00232
00233
00234 IMAPResponseBodyPart bodypart;
00235
00236
00237
00238
00239
00240 bodypart.setData(bodydata);
00241
00242
00243
00244
00245 bodypart.setPart(number);
00246
00247 qDebug("added bodypart [%s]: '%s'\n\n", number.latin1(), bodydata.latin1());
00248
00249 fetch.addBodyPart(bodypart);
00250 } else if (*it == "BODYSTRUCTURE") {
00251 qDebug("IMAPResponseParser: responseParser: got FETCH::BODYSTRUCTURE");
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 } else if (*it == "ENVELOPE") {
00280 QString envdata = *(++it);
00281 QStringList envList;
00282 parseParenthesizedList(envdata, envList);
00283
00284 IMAPResponseEnvelope envelope;
00285 envelope.setMailDate(envList[0] == "NIL" ? QString(0) : removeLimiters(envList[0]));
00286 envelope.setSubject(envList[1] == "NIL" ? QString(0) : removeLimiters(envList[1]));
00287
00288 QStringList froml, senderl, replytol, tol, ccl, bccl;
00289 QStringList froma, sendera, replytoa, toa, cca, bcca;
00290 parseParenthesizedList(envList[2], froml);
00291 parseParenthesizedList(envList[3], senderl);
00292 parseParenthesizedList(envList[4], replytol);
00293 parseParenthesizedList(envList[5], tol);
00294 parseParenthesizedList(envList[6], ccl);
00295 parseParenthesizedList(envList[7], bccl);
00296
00297 QStringList::Iterator it;
00298 for (it = froml.begin(); it != froml.end(); it++) {
00299 parseParenthesizedList(*it, froma);
00300 if (froml[0] != "NIL")
00301 envelope.addFrom(IMAPResponseAddress(
00302 removeLimiters(froma[0]),
00303 removeLimiters(froma[1]),
00304 removeLimiters(froma[2]),
00305 removeLimiters(froma[3])));
00306 }
00307
00308 for (it = senderl.begin(); it != senderl.end(); it++) {
00309 parseParenthesizedList(*it, sendera);
00310 if (senderl[0] != "NIL")
00311 envelope.addSender(IMAPResponseAddress(
00312 removeLimiters(sendera[0]),
00313 removeLimiters(sendera[1]),
00314 removeLimiters(sendera[2]),
00315 removeLimiters(sendera[3])));
00316 }
00317
00318 for (it = replytol.begin(); it != replytol.end(); it++) {
00319 parseParenthesizedList(*it, replytoa);
00320 if (replytol[0] != "NIL")
00321 envelope.addReplyTo(IMAPResponseAddress(
00322 removeLimiters(replytoa[0]),
00323 removeLimiters(replytoa[1]),
00324 removeLimiters(replytoa[2]),
00325 removeLimiters(replytoa[3])));
00326 }
00327
00328 for (it = tol.begin(); it != tol.end(); it++) {
00329 parseParenthesizedList(*it, toa);
00330 if (tol[0] != "NIL")
00331 envelope.addTo(IMAPResponseAddress(
00332 removeLimiters(toa[0]),
00333 removeLimiters(toa[1]),
00334 removeLimiters(toa[2]),
00335 removeLimiters(toa[3])));
00336 }
00337
00338 for (it = ccl.begin(); it != ccl.end(); it++) {
00339 parseParenthesizedList(*it, cca);
00340 if (ccl[0] != "NIL")
00341 envelope.addCc(IMAPResponseAddress(
00342 removeLimiters(cca[0]),
00343 removeLimiters(cca[1]),
00344 removeLimiters(cca[2]),
00345 removeLimiters(cca[3])));
00346 }
00347
00348 for (it = bccl.begin(); it != bccl.end(); it++) {
00349 parseParenthesizedList(*it, bcca);
00350 if (bccl[0] != "NIL")
00351 envelope.addBcc(IMAPResponseAddress(
00352 removeLimiters(bcca[0]),
00353 removeLimiters(bcca[1]),
00354 removeLimiters(bcca[2]),
00355 removeLimiters(bcca[3])));
00356 }
00357
00358 envelope.setInReplyTo(envList[7] == "NIL" ? QString(0) : removeLimiters(envList[7]));
00359 envelope.setMessageId(envList[8] == "NIL" ? QString(0) : removeLimiters(envList[8]));
00360
00361 fetch.setEnvelope(envelope);
00362 } else if (*it == "FLAGS") {
00363 QString flagdata = *(++it);
00364 QStringList flags;
00365 parseParenthesizedList(flagdata, flags);
00366 fetch.setFlags(parseFlagList(flags));
00367 } else if (*it == "INTERNALDATE") {
00368 fetch.setInternalDate(removeLimiters(*(++it)));
00369 } else if (*it == "RFC822" || *it == "BODY[]") {
00370 qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822");
00371
00372 } else if (*it == "RFC822.HEADER" || *it == "BODY.PEEK[HEADER]") {
00373 qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822.HEADER");
00374
00375 } else if (*it == "RFC822.SIZE") {
00376 fetch.setRFC822Size(*(++it));
00377 } else if (*it == "RFC822.TEXT" || *it == "BODY[TEXT]") {
00378 qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822.TEXT");
00379
00380 } else if (*it == "UID") {
00381 fetch.setUid(*(++it));
00382 }
00383 }
00384 _iresponse.addFETCH(fetch);
00385 }
00386 } else qWarning((QString("IMAPResponseParser: parseResponse: Unknown response: ") + response + "|").latin1());
00387
00388 }
00389
00390 QStringList IMAPResponseParser::splitData(const QString &data, bool withBrackets)
00391 {
00392 int b = 0;
00393 bool a = false, noappend = false, escaped = false;
00394 QString temp;
00395 QStringList list;
00396
00397 qDebug ( "sd: '%s'\n", data.latin1());
00398
00399 for (unsigned int i = 0; i <= data.length(); i++) {
00400 if (withBrackets && data[i] == '(' && !a) b++;
00401 else if (withBrackets && data[i] == ')' && !a) b--;
00402
00403 if (data[i] == '{' && !escaped && !a ) {
00404 qDebug ( "sd: found a {\n" );
00405
00406 int p = data. find ( '}', i + 1 );
00407 int eol = data. find ( '\n', i + 1 );
00408
00409 if ( p > int( i )) {
00410 int len = data. mid ( i + 1, p - i - 1 ). toInt ( );
00411
00412 qDebug ( "sd: skipping %d bytes\n", len );
00413
00414 if ( b == 0 ) {
00415 temp = data. mid ( eol + 1, len );
00416 noappend = false;
00417 i = eol + len;
00418 continue;
00419 }
00420 else {
00421 temp. append ( '{' );
00422 temp. append ( QString::number ( len ));
00423 temp. append ( "}\r\n" );
00424 temp. append ( data. mid ( eol + 1, len ));
00425 i = eol + len;
00426 continue;
00427 }
00428 }
00429 }
00430
00431 if (data[i] == '\"' && !escaped) a = !a;
00432 else escaped = false;
00433
00434 if (data[i] == '\\' && data[i + 1] == '\"') escaped = true;
00435
00436 if ((data[i] == ' ' || i == data.length()) && b == 0 && !a) {
00437 list.append(temp);
00438 temp = QString::null;
00439 if (data[i] == ' ') noappend = true;
00440 }
00441
00442 if (!noappend) temp += data[i];
00443 noappend = false;
00444 }
00445
00446 return list;
00447 }
00448
00449 void IMAPResponseParser::parseParenthesizedList(const QString &data, QStringList &parsed)
00450 {
00451 QString data_(data);
00452 removeLimiters(data_, '(', ')');
00453 parsed = splitData(data_, true);
00454 }
00455
00456 void IMAPResponseParser::splitTagData(const QString &line, QString &tag, QString &data)
00457 {
00458 int pos;
00459 if ((pos = line.find(' ')) != -1) {
00460 tag = line.left(pos);
00461 data = line.right(line.length() - pos - 1);
00462 } else qWarning((QString("IMAPResponseParser: splitTagData: tag not found. Line was ") + line + "|").latin1());
00463 }
00464
00465 QString IMAPResponseParser::removeLimiters(QString &string, const QChar &sl, const QChar &el)
00466 {
00467 QString tmpString;
00468 string = string. stripWhiteSpace ( );
00469
00470 if (string[0] == sl && string[string.length() - 1] == el) {
00471 string.truncate(string.length() - 1);
00472 string.replace(0, 1, "");
00473
00474 for (unsigned int i = 1; i <= string.length(); i++) {
00475 if (string[i - 1] == '\\' && sl == '\"') ++i;
00476 tmpString += string[i - 1];
00477 }
00478 }
00479 return tmpString;
00480 }
00481
00482 IMAPResponseEnums::IMAPResponseCode IMAPResponseParser::getResponseCode(const QString &line)
00483 {
00484 if (line.find(QRegExp((QString) "^\\[.*\\]" + ' ' + ".*")) != -1) {
00485 int pos = line.find("] ");
00486 QString code = line.left(pos + 1).upper();
00487
00488 if (code.find(QRegExp("[ALERT]")) != -1) return ALERT;
00489 else if (code.find(QRegExp("[NEWNAME .* .*]")) != -1) return NEWNAME;
00490 else if (code.find(QRegExp("[PARSE]")) != -1) return PARSE;
00491 else if (code.find(QRegExp("[PERMANENTFLAGS \\d*]")) != -1) return PERMANENTFLAGS;
00492 else if (code.find(QRegExp("[READ-ONLY]")) != -1) return READONLY;
00493 else if (code.find(QRegExp("[READ-WRITE]")) != -1) return READWRITE;
00494 else if (code.find(QRegExp("[TRYCREATE]")) != -1) return TRYCREATE;
00495 else if (code.find(QRegExp("[UIDVALIDITY \\d*]")) != -1) return UIDVALIDITY;
00496 else if (code.find(QRegExp("[UNSEEN \\d*]")) != -1) return UNSEEN;
00497 else {
00498 qWarning((QString("IMAPResponseParser: getResponseCode: Unknown code: ") + code + "|").latin1());
00499 return UnknownCode;
00500 }
00501 }
00502 return NoCode;
00503 }
00504
00505 QValueList<IMAPResponseEnums::IMAPResponseFlags> IMAPResponseParser::parseFlagList(const QStringList &flagList)
00506 {
00507 QValueList<IMAPResponseFlags> flags;
00508 QStringList::ConstIterator it;
00509 for (it = flagList.begin(); it != flagList.end(); it++) {
00510 QString flag = (*it).lower();
00511 if (flag == "\\seen") flags.append(Seen);
00512 else if (flag == "\\answered") flags.append(Answered);
00513 else if (flag == "\\flagged") flags.append(Flagged);
00514 else if (flag == "\\deleted") flags.append(Deleted);
00515 else if (flag == "\\draft") flags.append(Draft);
00516 else if (flag == "\\recent") flags.append(Recent);
00517 else if (flag == "\\noinferiors") flags.append(Noinferiors);
00518 else if (flag == "\\noselect") flags.append(Noselect);
00519 else if (flag == "\\marked") flags.append(Marked);
00520 else if (flag == "\\unmarked") flags.append(Unmarked);
00521 else if (flag.isEmpty()) { }
00522 else qWarning((QString("IMAPResponseParser: parseFlagList: Unknown flag: ") + *it + "|").latin1());
00523 }
00524 return flags;
00525 }
00526