1 | /* |
2 | Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com> |
3 | |
4 | This library is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU Library General Public License as published by |
6 | the Free Software Foundation; either version 2 of the License, or (at your |
7 | option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
12 | License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to the |
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17 | 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "tagfetchjob.h" |
21 | #include "job_p.h" |
22 | #include "tag.h" |
23 | #include "protocolhelper_p.h" |
24 | #include "tagfetchscope.h" |
25 | #include <QTimer> |
26 | #include <QFile> |
27 | #include <akonadi/attributefactory.h> |
28 | |
29 | using namespace Akonadi; |
30 | |
31 | class Akonadi::TagFetchJobPrivate : public JobPrivate |
32 | { |
33 | public: |
34 | TagFetchJobPrivate(TagFetchJob *parent) |
35 | : JobPrivate(parent) |
36 | , mEmitTimer(0) |
37 | { |
38 | } |
39 | |
40 | void init() |
41 | { |
42 | Q_Q(TagFetchJob); |
43 | mEmitTimer = new QTimer(q); |
44 | mEmitTimer->setSingleShot(true); |
45 | mEmitTimer->setInterval(100); |
46 | q->connect(mEmitTimer, SIGNAL(timeout()), q, SLOT(timeout())); |
47 | } |
48 | |
49 | void aboutToFinish() |
50 | { |
51 | timeout(); |
52 | } |
53 | |
54 | void timeout() |
55 | { |
56 | Q_Q(TagFetchJob); |
57 | mEmitTimer->stop(); // in case we are called by result() |
58 | if (!mPendingTags.isEmpty()) { |
59 | if (!q->error()) { |
60 | emit q->tagsReceived(mPendingTags); |
61 | } |
62 | mPendingTags.clear(); |
63 | } |
64 | } |
65 | |
66 | Q_DECLARE_PUBLIC(TagFetchJob) |
67 | |
68 | Tag::List mRequestedTags; |
69 | Tag::List mResultTags; |
70 | Tag::List mPendingTags; // items pending for emitting itemsReceived() |
71 | QTimer *mEmitTimer; |
72 | TagFetchScope mFetchScope; |
73 | }; |
74 | |
75 | TagFetchJob::TagFetchJob(QObject *parent) |
76 | : Job(new TagFetchJobPrivate(this), parent) |
77 | { |
78 | Q_D(TagFetchJob); |
79 | d->init(); |
80 | } |
81 | |
82 | TagFetchJob::TagFetchJob(const Tag &tag, QObject *parent) |
83 | : Job(new TagFetchJobPrivate(this), parent) |
84 | { |
85 | Q_D(TagFetchJob); |
86 | d->init(); |
87 | d->mRequestedTags << tag; |
88 | } |
89 | |
90 | TagFetchJob::TagFetchJob(const Tag::List &tags, QObject *parent) |
91 | : Job(new TagFetchJobPrivate(this), parent) |
92 | { |
93 | Q_D(TagFetchJob); |
94 | d->init(); |
95 | d->mRequestedTags = tags; |
96 | } |
97 | |
98 | TagFetchJob::TagFetchJob(const QList<Tag::Id> &ids, QObject *parent) |
99 | : Job(new TagFetchJobPrivate(this), parent) |
100 | { |
101 | Q_D(TagFetchJob); |
102 | d->init(); |
103 | Q_FOREACH (Tag::Id id, ids) { |
104 | d->mRequestedTags << Tag(id); |
105 | } |
106 | } |
107 | |
108 | void TagFetchJob::setFetchScope(const TagFetchScope &fetchScope) |
109 | { |
110 | Q_D(TagFetchJob); |
111 | d->mFetchScope = fetchScope; |
112 | } |
113 | |
114 | TagFetchScope &TagFetchJob::fetchScope() |
115 | { |
116 | Q_D(TagFetchJob); |
117 | return d->mFetchScope; |
118 | } |
119 | |
120 | void TagFetchJob::doStart() |
121 | { |
122 | Q_D(TagFetchJob); |
123 | |
124 | QByteArray command = d->newTag(); |
125 | if (d->mRequestedTags.isEmpty()) { |
126 | command += " UID TAGFETCH 1:*" ; |
127 | } else { |
128 | try { |
129 | command += ProtocolHelper::tagSetToByteArray(d->mRequestedTags, "TAGFETCH" ); |
130 | } catch (const Exception &e) { |
131 | setError(Job::Unknown); |
132 | setErrorText(QString::fromUtf8(e.what())); |
133 | emitResult(); |
134 | return; |
135 | } |
136 | } |
137 | command += " (UID" ; |
138 | Q_FOREACH (const QByteArray &part, d->mFetchScope.attributes()) { |
139 | command += ' ' + ProtocolHelper::encodePartIdentifier(ProtocolHelper::PartAttribute, part); |
140 | } |
141 | command += ")\n" ; |
142 | |
143 | d->writeData(command); |
144 | } |
145 | |
146 | void TagFetchJob::doHandleResponse(const QByteArray &tag, const QByteArray &data) |
147 | { |
148 | Q_D(TagFetchJob); |
149 | |
150 | if (tag == "*" ) { |
151 | int begin = data.indexOf("TAGFETCH" ); |
152 | if (begin >= 0) { |
153 | // split fetch response into key/value pairs |
154 | QList<QByteArray> fetchResponse; |
155 | ImapParser::parseParenthesizedList(data, fetchResponse, begin + 8); |
156 | |
157 | Tag tag; |
158 | ProtocolHelper::parseTagFetchResult(fetchResponse, tag); |
159 | |
160 | if (tag.isValid()) { |
161 | d->mResultTags.append(tag); |
162 | d->mPendingTags.append(tag); |
163 | if (!d->mEmitTimer->isActive()) { |
164 | d->mEmitTimer->start(); |
165 | } |
166 | } |
167 | return; |
168 | } |
169 | } |
170 | kDebug() << "Unhandled response: " << tag << data; |
171 | } |
172 | |
173 | Tag::List TagFetchJob::tags() const |
174 | { |
175 | Q_D(const TagFetchJob); |
176 | return d->mResultTags; |
177 | } |
178 | |
179 | #include "moc_tagfetchjob.cpp" |
180 | |