Diffstat (limited to 'noncore/unsupported/mail2/libmail/imapresponse.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/unsupported/mail2/libmail/imapresponse.cpp | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/noncore/unsupported/mail2/libmail/imapresponse.cpp b/noncore/unsupported/mail2/libmail/imapresponse.cpp new file mode 100644 index 0000000..06dca33 --- a/dev/null +++ b/noncore/unsupported/mail2/libmail/imapresponse.cpp | |||
@@ -0,0 +1,448 @@ | |||
1 | #include "imapresponse.h" | ||
2 | |||
3 | static QString _previousData; | ||
4 | static unsigned int _neededData; | ||
5 | |||
6 | IMAPResponseParser::IMAPResponseParser(const QString &data) | ||
7 | { | ||
8 | QString _data = data, more; | ||
9 | _data.replace((QString)"\r\n", "\n"); | ||
10 | |||
11 | QStringList lines = QStringList::split('\n', _data); | ||
12 | QStringList::Iterator it; | ||
13 | for (it = lines.begin(); it != lines.end(); it++) { | ||
14 | QString tag, lineData; | ||
15 | |||
16 | if (!_previousData.isNull()) { | ||
17 | qDebug(QString("IMAPResponseParser: got additional data. (%1/%2)").arg(_previousData.length()).arg(_neededData)); | ||
18 | _previousData += *it + "\n"; | ||
19 | if (_previousData.length() >= _neededData) { | ||
20 | _previousData += ")"; | ||
21 | qDebug("IMAPResponseParser: got ALL additional data."); | ||
22 | qDebug("Data is: " + _previousData); | ||
23 | parseResponse(_previousData); | ||
24 | _previousData = QString(0); | ||
25 | _neededData = 0; | ||
26 | } | ||
27 | } else { | ||
28 | splitTagData(*it, tag, lineData); | ||
29 | if (tag == "*") { | ||
30 | int pos; | ||
31 | if ((pos = data.find(QRegExp("\\{\\d*\\}"))) != -1) { | ||
32 | qDebug("IMAPResponseParser: waiting for additional data..."); | ||
33 | _previousData = lineData + "\n"; | ||
34 | |||
35 | QString tmp = data.right(data.length() - pos - 1).stripWhiteSpace(); | ||
36 | tmp.truncate(tmp.length() - 1); | ||
37 | |||
38 | _neededData = tmp.toUInt(); | ||
39 | if (_previousData.length() >= _neededData) { | ||
40 | qDebug("IMAPResponseParser: got ALL additional data. (1st)"); | ||
41 | parseResponse(_previousData); | ||
42 | _previousData = QString(0); | ||
43 | _neededData = 0; | ||
44 | } else { | ||
45 | break; | ||
46 | } | ||
47 | } else { | ||
48 | parseResponse(lineData); | ||
49 | } | ||
50 | } else if (tag == "+") { | ||
51 | emit needMoreData(_data); | ||
52 | } else { | ||
53 | _iresponse.setTag(tag); | ||
54 | parseResponse(_data, true); | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | IMAPResponse IMAPResponseParser::response() | ||
61 | { | ||
62 | return _iresponse; | ||
63 | } | ||
64 | |||
65 | void IMAPResponseParser::parseResponse(const QString &data, bool tagged) | ||
66 | { | ||
67 | QString response, line; | ||
68 | int pos; | ||
69 | bool isNum = false; | ||
70 | if ((pos = data.find(' ')) != -1) { | ||
71 | response = data.left(pos).upper(); | ||
72 | response.toInt(&isNum); | ||
73 | line = data.right(data.length() - pos - 1); | ||
74 | } else { | ||
75 | qWarning("IMAPResponseParser: parseResponse: No response found."); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | if (response == "OK" && tagged) { | ||
80 | IMAPResponseStatusResponse status(OK, line); | ||
81 | status.setResponseCode(getResponseCode(status.comment())); | ||
82 | _iresponse.setStatusResponse(status); | ||
83 | } else if (response == "OK" && !tagged) { | ||
84 | IMAPResponseOK ok(line, getResponseCode(line)); | ||
85 | _iresponse.addOK(ok); | ||
86 | } else if (response == "NO" && tagged) { | ||
87 | IMAPResponseStatusResponse status(NO, line); | ||
88 | status.setResponseCode(getResponseCode(status.comment())); | ||
89 | _iresponse.setStatusResponse(status); | ||
90 | } else if (response == "NO" && !tagged) { | ||
91 | IMAPResponseNO no(line, getResponseCode(line)); | ||
92 | _iresponse.addNO(no); | ||
93 | } else if (response == "BAD" && tagged) { | ||
94 | IMAPResponseStatusResponse status(BAD, line); | ||
95 | status.setResponseCode(getResponseCode(status.comment())); | ||
96 | _iresponse.setStatusResponse(status); | ||
97 | } else if (response == "BAD" && !tagged) { | ||
98 | IMAPResponseBAD bad(line, getResponseCode(line)); | ||
99 | _iresponse.addBAD(bad); | ||
100 | } else if (response == "PREAUTH" && tagged) { | ||
101 | IMAPResponseStatusResponse status(PREAUTH, line); | ||
102 | _iresponse.setStatusResponse(status); | ||
103 | } else if (response == "PREAUTH" && !tagged) { | ||
104 | qDebug("IMAPResponseParser: responseParser: got untagged PREAUTH response."); | ||
105 | // XXX | ||
106 | } else if (response == "BYE") { | ||
107 | IMAPResponseStatusResponse status(BYE, line); | ||
108 | if (!tagged) status.setExitedUnexpected(true); | ||
109 | _iresponse.setStatusResponse(status); | ||
110 | } else if (response == "CAPABILITY") { | ||
111 | IMAPResponseCAPABILITY capability(QStringList::split(' ', line)); | ||
112 | _iresponse.addCAPABILITY(capability); | ||
113 | } else if (response == "LIST") { | ||
114 | QStringList list = splitData(line, true); | ||
115 | |||
116 | QStringList flags; | ||
117 | parseParenthesizedList(list[0], flags); | ||
118 | |||
119 | removeLimiters(list[1]); | ||
120 | removeLimiters(list[2]); | ||
121 | IMAPResponseLIST rlist(parseFlagList(flags), list[1], list[2]); | ||
122 | _iresponse.addLIST(rlist); | ||
123 | } else if (response == "LSUB") { | ||
124 | QStringList list = splitData(line, true); | ||
125 | |||
126 | QStringList flags; | ||
127 | parseParenthesizedList(list[0], flags); | ||
128 | |||
129 | removeLimiters(list[1]); | ||
130 | removeLimiters(list[2]); | ||
131 | IMAPResponseLSUB lsub(parseFlagList(flags), list[1], list[2]); | ||
132 | _iresponse.addLSUB(lsub); | ||
133 | } else if (response == "STATUS") { | ||
134 | QStringList list = splitData(line, true); | ||
135 | |||
136 | removeLimiters(list[0]); | ||
137 | IMAPResponseSTATUS status(list[0]); | ||
138 | |||
139 | QStringList flags; | ||
140 | parseParenthesizedList(list[1], flags); | ||
141 | QStringList::Iterator it; | ||
142 | for (it = flags.begin(); it != flags.end(); it++) { | ||
143 | if (*it == "MESSAGES") status.setMessages(*(++it)); | ||
144 | else if (*it == "RECENT") status.setRecent(*(++it)); | ||
145 | else if (*it == "UIDNEXT") status.setUidnext(*(++it)); | ||
146 | else if (*it == "UIDVALIDITY") status.setUidvalidity(*(++it)); | ||
147 | else if (*it == "UNSEEN") status.setUnseen(*(++it)); | ||
148 | else qWarning("IMAPResponseParser: parseResponse: Unknown status data: " + *(it++) + "|"); | ||
149 | } | ||
150 | _iresponse.addSTATUS(status); | ||
151 | } else if (response == "SEARCH") { | ||
152 | IMAPResponseSEARCH search(QStringList::split(' ', line)); | ||
153 | _iresponse.addSEARCH(search); | ||
154 | } else if (response == "FLAGS") { | ||
155 | QStringList list; | ||
156 | parseParenthesizedList(line, list); | ||
157 | |||
158 | IMAPResponseFLAGS flags(parseFlagList(list)); | ||
159 | _iresponse.addFLAGS(flags); | ||
160 | } else if (isNum) { | ||
161 | QStringList list = QStringList::split(' ', line); | ||
162 | if (list[0] == "EXISTS") { | ||
163 | IMAPResponseEXISTS exists(response); | ||
164 | _iresponse.addEXISTS(exists); | ||
165 | } else if (list[0] == "RECENT") { | ||
166 | IMAPResponseRECENT recent(response); | ||
167 | _iresponse.addRECENT(recent); | ||
168 | } else if (list[0] == "EXPUNGE") { | ||
169 | IMAPResponseEXPUNGE expunge(response); | ||
170 | _iresponse.addEXPUNGE(expunge); | ||
171 | } else if (list[0] == "FETCH") { | ||
172 | IMAPResponseFETCH fetch; | ||
173 | QStringList::Iterator it; | ||
174 | |||
175 | QStringList fetchList = splitData(line, true); | ||
176 | QStringList list; | ||
177 | parseParenthesizedList(fetchList[1], list); | ||
178 | |||
179 | for (it = list.begin(); it != list.end(); it++) { | ||
180 | if (*it == "BODY") { | ||
181 | qDebug("IMAPResponseParser: responseParser: got FETCH::BODY"); | ||
182 | // XXX | ||
183 | } else if ((*it).find(QRegExp("BODY\\[\\d+\\]")) != -1) { | ||
184 | QString bodydata = *(++it); | ||
185 | qDebug("IMAPResponseParser: responseParser: got FETCH::BODY[x]"); | ||
186 | |||
187 | QStringList blist; | ||
188 | parseParenthesizedList(bodydata, blist); | ||
189 | |||
190 | IMAPResponseBodyPart bodypart; | ||
191 | QString tmp; | ||
192 | for (unsigned int i = 2; i < blist.count(); i++) { | ||
193 | if (i != 2) tmp += " " + blist[i]; | ||
194 | else tmp += blist[i]; | ||
195 | } | ||
196 | bodypart.setData(tmp); | ||
197 | |||
198 | tmp = list[0]; | ||
199 | tmp.replace(0, 5, ""); | ||
200 | tmp.truncate(blist[0].length() - 1); | ||
201 | bodypart.setPart(tmp); | ||
202 | |||
203 | fetch.addBodyPart(bodypart); | ||
204 | } else if (*it == "BODYSTRUCTURE") { | ||
205 | qDebug("IMAPResponseParser: responseParser: got FETCH::BODYSTRUCTURE"); | ||
206 | /* | ||
207 | QString bsdata = *(++it); | ||
208 | QStringList bsList; | ||
209 | parseParenthesizedList(bsdata, bsList); | ||
210 | |||
211 | IMAPResponseBodystructure bodystructure; | ||
212 | QStringList attachml; | ||
213 | |||
214 | for (int i = 0; i < bsList.count() - 1; i++) { | ||
215 | parseParenthesizedList(bsList[0], attachml); | ||
216 | |||
217 | IMAPResponseBodypart bodypart; | ||
218 | bodypart.setMimeTypeMain(attachml[0] == "NIL" ? QString(0) : attachml[0]); | ||
219 | bodypart.setMimeTypeSub(attachml[1] == "NIL" ? QString(0) : attachml[1]); | ||
220 | bodypart.setAddData(attachml[2] == "NIL" ? QString(0) : attachml[2]); | ||
221 | // 3 (NIL) | ||
222 | // 4 (NIL) | ||
223 | bodypart.setEncoding(attachml[5] == "NIL" ? QString(0) : attachml[5]); | ||
224 | bodypart.setSize(attachml[6] == "NIL" ? QString(0) : attachml[6]); | ||
225 | bodypart.setLength(attachml[7] == "NIL" ? QString(0) : attachml[7]); | ||
226 | bodypart.setAttachInfo(attachml[8] == "NIL" ? QString(0) : attachml[8]); | ||
227 | // 9 (NIL) | ||
228 | // 10 (NIL) | ||
229 | |||
230 | bodystructure.addBodyPart(bodypart); | ||
231 | } | ||
232 | */ | ||
233 | } else if (*it == "ENVELOPE") { | ||
234 | QString envdata = *(++it); | ||
235 | QStringList envList; | ||
236 | parseParenthesizedList(envdata, envList); | ||
237 | |||
238 | IMAPResponseEnvelope envelope; | ||
239 | envelope.setMailDate(envList[0] == "NIL" ? QString(0) : removeLimiters(envList[0])); | ||
240 | envelope.setSubject(envList[1] == "NIL" ? QString(0) : removeLimiters(envList[1])); | ||
241 | |||
242 | QStringList froml, senderl, replytol, tol, ccl, bccl; | ||
243 | QStringList froma, sendera, replytoa, toa, cca, bcca; | ||
244 | parseParenthesizedList(envList[2], froml); | ||
245 | parseParenthesizedList(envList[3], senderl); | ||
246 | parseParenthesizedList(envList[4], replytol); | ||
247 | parseParenthesizedList(envList[5], tol); | ||
248 | parseParenthesizedList(envList[6], ccl); | ||
249 | parseParenthesizedList(envList[7], bccl); | ||
250 | |||
251 | QStringList::Iterator it; | ||
252 | for (it = froml.begin(); it != froml.end(); it++) { | ||
253 | parseParenthesizedList(*it, froma); | ||
254 | if (froml[0] != "NIL") | ||
255 | envelope.addFrom(IMAPResponseAddress( | ||
256 | removeLimiters(froma[0]), | ||
257 | removeLimiters(froma[1]), | ||
258 | removeLimiters(froma[2]), | ||
259 | removeLimiters(froma[3]))); | ||
260 | } | ||
261 | |||
262 | for (it = senderl.begin(); it != senderl.end(); it++) { | ||
263 | parseParenthesizedList(*it, sendera); | ||
264 | if (senderl[0] != "NIL") | ||
265 | envelope.addSender(IMAPResponseAddress( | ||
266 | removeLimiters(sendera[0]), | ||
267 | removeLimiters(sendera[1]), | ||
268 | removeLimiters(sendera[2]), | ||
269 | removeLimiters(sendera[3]))); | ||
270 | } | ||
271 | |||
272 | for (it = replytol.begin(); it != replytol.end(); it++) { | ||
273 | parseParenthesizedList(*it, replytoa); | ||
274 | if (replytol[0] != "NIL") | ||
275 | envelope.addReplyTo(IMAPResponseAddress( | ||
276 | removeLimiters(replytoa[0]), | ||
277 | removeLimiters(replytoa[1]), | ||
278 | removeLimiters(replytoa[2]), | ||
279 | removeLimiters(replytoa[3]))); | ||
280 | } | ||
281 | |||
282 | for (it = tol.begin(); it != tol.end(); it++) { | ||
283 | parseParenthesizedList(*it, toa); | ||
284 | if (tol[0] != "NIL") | ||
285 | envelope.addTo(IMAPResponseAddress( | ||
286 | removeLimiters(toa[0]), | ||
287 | removeLimiters(toa[1]), | ||
288 | removeLimiters(toa[2]), | ||
289 | removeLimiters(toa[3]))); | ||
290 | } | ||
291 | |||
292 | for (it = ccl.begin(); it != ccl.end(); it++) { | ||
293 | parseParenthesizedList(*it, cca); | ||
294 | if (ccl[0] != "NIL") | ||
295 | envelope.addCc(IMAPResponseAddress( | ||
296 | removeLimiters(cca[0]), | ||
297 | removeLimiters(cca[1]), | ||
298 | removeLimiters(cca[2]), | ||
299 | removeLimiters(cca[3]))); | ||
300 | } | ||
301 | |||
302 | for (it = bccl.begin(); it != bccl.end(); it++) { | ||
303 | parseParenthesizedList(*it, bcca); | ||
304 | if (bccl[0] != "NIL") | ||
305 | envelope.addBcc(IMAPResponseAddress( | ||
306 | removeLimiters(bcca[0]), | ||
307 | removeLimiters(bcca[1]), | ||
308 | removeLimiters(bcca[2]), | ||
309 | removeLimiters(bcca[3]))); | ||
310 | } | ||
311 | |||
312 | envelope.setInReplyTo(envList[7] == "NIL" ? QString(0) : removeLimiters(envList[7])); | ||
313 | envelope.setMessageId(envList[8] == "NIL" ? QString(0) : removeLimiters(envList[8])); | ||
314 | |||
315 | fetch.setEnvelope(envelope); | ||
316 | } else if (*it == "FLAGS") { | ||
317 | QString flagdata = *(++it); | ||
318 | QStringList flags; | ||
319 | parseParenthesizedList(flagdata, flags); | ||
320 | fetch.setFlags(parseFlagList(flags)); | ||
321 | } else if (*it == "INTERNALDATE") { | ||
322 | fetch.setInternalDate(removeLimiters(*(++it))); | ||
323 | } else if (*it == "RFC822" || *it == "BODY[]") { | ||
324 | qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822"); | ||
325 | // XXX | ||
326 | } else if (*it == "RFC822.HEADER" || *it == "BODY.PEEK[HEADER]") { | ||
327 | qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822.HEADER"); | ||
328 | // XXX | ||
329 | } else if (*it == "RFC822.SIZE") { | ||
330 | fetch.setRFC822Size(*(++it)); | ||
331 | } else if (*it == "RFC822.TEXT" || *it == "BODY[TEXT]") { | ||
332 | qDebug("IMAPResponseParser: responseParser: got FETCH::RFC822.TEXT"); | ||
333 | // XXX | ||
334 | } else if (*it == "UID") { | ||
335 | fetch.setUid(*(++it)); | ||
336 | } | ||
337 | } | ||
338 | _iresponse.addFETCH(fetch); | ||
339 | } | ||
340 | } else qWarning("IMAPResponseParser: parseResponse: Unknown response: " + response + "|"); | ||
341 | } | ||
342 | |||
343 | QStringList IMAPResponseParser::splitData(const QString &data, bool withBrackets) | ||
344 | { | ||
345 | int b = 0; | ||
346 | bool a = false, noappend = false, escaped = false; | ||
347 | QString temp; | ||
348 | QStringList list; | ||
349 | |||
350 | for (unsigned int i = 0; i <= data.length(); i++) { | ||
351 | if (withBrackets && data[i] == '(' && !a) b++; | ||
352 | else if (withBrackets && data[i] == ')' && !a) b--; | ||
353 | |||
354 | if (data[i] == '"' && !escaped) a = !a; | ||
355 | else escaped = false; | ||
356 | |||
357 | if (data[i] == '\\' && data[i + 1] == '"') escaped = true; | ||
358 | |||
359 | if ((data[i] == ' ' || i == data.length()) && b == 0 && !a) { | ||
360 | list.append(temp); | ||
361 | temp = QString(0); | ||
362 | if (data[i] == ' ') noappend = true; | ||
363 | } | ||
364 | |||
365 | if (!noappend) temp += data[i]; | ||
366 | noappend = false; | ||
367 | } | ||
368 | |||
369 | return list; | ||
370 | } | ||
371 | |||
372 | void IMAPResponseParser::parseParenthesizedList(const QString &data, QStringList &parsed) | ||
373 | { | ||
374 | QString data_(data); | ||
375 | removeLimiters(data_, '(', ')'); | ||
376 | parsed = splitData(data_, true); | ||
377 | } | ||
378 | |||
379 | void IMAPResponseParser::splitTagData(const QString &line, QString &tag, QString &data) | ||
380 | { | ||
381 | int pos; | ||
382 | if ((pos = line.find(' ')) != -1) { | ||
383 | tag = line.left(pos); | ||
384 | data = line.right(line.length() - pos - 1); | ||
385 | } else qWarning("IMAPResponseParser: splitTagData: tag not found. Line was " + line + "|"); | ||
386 | } | ||
387 | |||
388 | QString IMAPResponseParser::removeLimiters(QString &string, const QChar &sl, const QChar &el) | ||
389 | { | ||
390 | QString tmpString; | ||
391 | if (string[0] == sl && string[string.length() - 1] == el) { | ||
392 | string.truncate(string.length() - 1); | ||
393 | string.replace(0, 1, ""); | ||
394 | |||
395 | for (unsigned int i = 1; i <= string.length(); i++) { | ||
396 | if (string[i - 1] == '\\' && sl == '"') ++i; | ||
397 | tmpString += string[i - 1]; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return tmpString; | ||
402 | } | ||
403 | |||
404 | IMAPResponseEnums::IMAPResponseCode IMAPResponseParser::getResponseCode(const QString &line) | ||
405 | { | ||
406 | if (line.find(QRegExp((QString) "^\\[.*\\]" + ' ' + ".*")) != -1) { | ||
407 | int pos = line.find("] "); | ||
408 | QString code = line.left(pos + 1).upper(); | ||
409 | |||
410 | if (code.find(QRegExp("[ALERT]")) != -1) return ALERT; | ||
411 | else if (code.find(QRegExp("[NEWNAME .* .*]")) != -1) return NEWNAME; // XXX | ||
412 | else if (code.find(QRegExp("[PARSE]")) != -1) return PARSE; | ||
413 | else if (code.find(QRegExp("[PERMANENTFLAGS \\d*]")) != -1) return PERMANENTFLAGS; // XXX | ||
414 | else if (code.find(QRegExp("[READ-ONLY]")) != -1) return READONLY; | ||
415 | else if (code.find(QRegExp("[READ-WRITE]")) != -1) return READWRITE; | ||
416 | else if (code.find(QRegExp("[TRYCREATE]")) != -1) return TRYCREATE; | ||
417 | else if (code.find(QRegExp("[UIDVALIDITY \\d*]")) != -1) return UIDVALIDITY; // XXX | ||
418 | else if (code.find(QRegExp("[UNSEEN \\d*]")) != -1) return UNSEEN; // XXX | ||
419 | else { | ||
420 | qWarning("IMAPResponseParser: getResponseCode: Unknown code: " + code + "|"); | ||
421 | return UnknownCode; | ||
422 | } | ||
423 | } | ||
424 | return NoCode; | ||
425 | } | ||
426 | |||
427 | QValueList<IMAPResponseEnums::IMAPResponseFlags> IMAPResponseParser::parseFlagList(const QStringList &flagList) | ||
428 | { | ||
429 | QValueList<IMAPResponseFlags> flags; | ||
430 | QStringList::ConstIterator it; | ||
431 | for (it = flagList.begin(); it != flagList.end(); it++) { | ||
432 | QString flag = (*it).lower(); | ||
433 | if (flag == "\\seen") flags.append(Seen); | ||
434 | else if (flag == "\\answered") flags.append(Answered); | ||
435 | else if (flag == "\\flagged") flags.append(Flagged); | ||
436 | else if (flag == "\\deleted") flags.append(Deleted); | ||
437 | else if (flag == "\\draft") flags.append(Draft); | ||
438 | else if (flag == "\\recent") flags.append(Recent); | ||
439 | else if (flag == "\\noinferiors") flags.append(Noinferiors); | ||
440 | else if (flag == "\\noselect") flags.append(Noselect); | ||
441 | else if (flag == "\\marked") flags.append(Marked); | ||
442 | else if (flag == "\\unmarked") flags.append(Unmarked); | ||
443 | else if (flag.isEmpty()) { } | ||
444 | else qWarning("IMAPResponseParser: parseFlagList: Unknown flag: " + *it + "|"); | ||
445 | } | ||
446 | return flags; | ||
447 | } | ||
448 | |||