getmetadatajob.cpp 8.57 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
    Copyright (c) 2009 Andras Mantia <amantia@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "getmetadatajob.h"

Laurent Montel's avatar
Laurent Montel committed
22
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
23
#include "kimap_debug.h"
24
25

#include "metadatajobbase_p.h"
26
#include "response_p.h"
27
#include "session_p.h"
28
#include "rfccodecs.h"
29
30
31

namespace KIMAP
{
Laurent Montel's avatar
Laurent Montel committed
32
33
34
35
36
37
38
39
class GetMetaDataJobPrivate : public MetaDataJobBasePrivate
{
public:
    GetMetaDataJobPrivate(Session *session, const QString &name) : MetaDataJobBasePrivate(session, name), maxSize(-1), depth("0") { }
    ~GetMetaDataJobPrivate() { }

    qint64 maxSize;
    QByteArray depth;
40
41
    QSet<QByteArray> entries;
    QSet<QByteArray> attributes;
Laurent Montel's avatar
Laurent Montel committed
42
43
44
    QMap<QString, QMap<QByteArray, QMap<QByteArray, QByteArray> > > metadata;
    //    ^ mailbox        ^ entry          ^attribute  ^ value
};
45
46
47
48
}

using namespace KIMAP;

Laurent Montel's avatar
Laurent Montel committed
49
50
GetMetaDataJob::GetMetaDataJob(Session *session)
    : MetaDataJobBase(*new GetMetaDataJobPrivate(session, i18n("GetMetaData")))
51
52
53
54
55
56
57
{
}

GetMetaDataJob::~GetMetaDataJob()
{
}

58
59
static QList<QByteArray> sort(const QSet<QByteArray> &set)
{
60
    QList<QByteArray> sortedEntries = set.values();
Laurent Montel's avatar
Laurent Montel committed
61
    std::sort(sortedEntries.begin(), sortedEntries.end());
62
63
64
    return sortedEntries;
}

65
66
void GetMetaDataJob::doStart()
{
Laurent Montel's avatar
Laurent Montel committed
67
68
69
70
71
72
73
74
75
76
77
    Q_D(GetMetaDataJob);
    QByteArray parameters;
    parameters = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" ";

    QByteArray command = "GETMETADATA";
    if (d->serverCapability == Annotatemore) {
        d->m_name = i18n("GetAnnotation");
        command = "GETANNOTATION";
        if (d->entries.size() > 1) {
            parameters += '(';
        }
78
        Q_FOREACH (const QByteArray &entry, sort(d->entries)) {
Laurent Montel's avatar
Laurent Montel committed
79
80
81
82
83
84
            parameters += '\"' + entry + "\" ";
        }
        if (d->entries.size() > 1) {
            parameters[parameters.length() - 1 ] = ')';
            parameters += ' ';
        }
85

Laurent Montel's avatar
Laurent Montel committed
86
87
88
        if (d->attributes.size() > 1) {
            parameters += '(';
        }
89
        Q_FOREACH (const QByteArray &attribute, sort(d->attributes)) {
Laurent Montel's avatar
Laurent Montel committed
90
91
92
93
94
            parameters += '\"' + attribute + "\" ";
        }
        if (d->attributes.size() > 1) {
            parameters[parameters.length() - 1 ] = ')';
        } else {
Laurent Montel's avatar
Laurent Montel committed
95
            parameters.chop(1);
Laurent Montel's avatar
Laurent Montel committed
96
        }
97

Laurent Montel's avatar
Laurent Montel committed
98
    } else {
99

Laurent Montel's avatar
Laurent Montel committed
100
101
102
103
104
105
106
107
108
109
        QByteArray options;
        if (d->depth != "0") {
            options = "DEPTH " + d->depth;
        }
        if (d->maxSize != -1) {
            if (!options.isEmpty()) {
                options += ' ';
            }
            options += "MAXSIZE " + QByteArray::number(d->maxSize);
        }
110

Laurent Montel's avatar
Laurent Montel committed
111
112
113
        if (!options.isEmpty()) {
            parameters = "(" + options + ") " + parameters;
        }
114

Laurent Montel's avatar
Laurent Montel committed
115
116
        if (d->entries.size() >= 1) {
            parameters += '(';
117
            Q_FOREACH (const QByteArray &entry, sort(d->entries)) {
Laurent Montel's avatar
Laurent Montel committed
118
119
120
121
                parameters += entry + " ";
            }
            parameters[parameters.length() - 1 ] = ')';
        } else {
Laurent Montel's avatar
Laurent Montel committed
122
            parameters.chop(1);
Laurent Montel's avatar
Laurent Montel committed
123
        }
124
    }
125

Laurent Montel's avatar
Laurent Montel committed
126
    d->tags << d->sessionInternal()->sendCommand(command, parameters);
Laurent Montel's avatar
Laurent Montel committed
127
//  qCDebug(KIMAP_LOG) << "SENT: " << command << " " << parameters;
128
129
}

130
void GetMetaDataJob::handleResponse(const Response &response)
131
{
Laurent Montel's avatar
Laurent Montel committed
132
    Q_D(GetMetaDataJob);
Laurent Montel's avatar
Laurent Montel committed
133
//  qCDebug(KIMAP_LOG) << "GOT: " << response.toString();
134

Laurent Montel's avatar
Laurent Montel committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    //TODO: handle NO error messages having [METADATA MAXSIZE NNN], [METADATA TOOMANY], [METADATA NOPRIVATE] (see rfc5464)
    // or [ANNOTATEMORE TOOBIG], [ANNOTATEMORE TOOMANY] respectively
    if (handleErrorReplies(response) == NotHandled) {
        if (response.content.size() >= 4) {
            if (d->serverCapability == Annotatemore && response.content[1].toString() == "ANNOTATION") {
                QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));

                int i = 3;
                while (i < response.content.size() - 1) {
                    QByteArray entry = response.content[i].toString();
                    QList<QByteArray> attributes = response.content[i + 1].toList();
                    int j = 0;
                    while (j < attributes.size() - 1) {
                        d->metadata[mailBox][entry][attributes[j]] = attributes[j + 1];
                        j += 2;
                    }
                    i += 2;
                }
            } else if (d->serverCapability == Metadata && response.content[1].toString() == "METADATA") {
                QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));

                const QList<QByteArray> &entries = response.content[3].toList();
                int i = 0;
                while (i < entries.size() - 1) {
                    const QByteArray &value = entries[i + 1];
                    QByteArray &targetValue = d->metadata[mailBox][entries[i]][""];
                    if (value != "NIL") {   //This just indicates no value
                        targetValue = value;
                    }
                    i += 2;
                }
            }
167
168
169
170
        }
    }
}

Andras Mantia's avatar
Andras Mantia committed
171
void GetMetaDataJob::addEntry(const QByteArray &entry, const QByteArray &attribute)
172
{
Laurent Montel's avatar
Laurent Montel committed
173
174
    Q_D(GetMetaDataJob);
    if (d->serverCapability == Annotatemore && attribute.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
175
        qCWarning(KIMAP_LOG) << "In ANNOTATEMORE mode an attribute must be specified with addEntry!";
Laurent Montel's avatar
Laurent Montel committed
176
    }
177
178
    d->entries.insert(entry);
    d->attributes.insert(attribute);
179
180
}

181
182
void GetMetaDataJob::addRequestedEntry(const QByteArray &entry)
{
Laurent Montel's avatar
Laurent Montel committed
183
    Q_D(GetMetaDataJob);
184
185
    d->entries.insert(d->removePrefix(entry));
    d->attributes.insert(d->getAttribute(entry));
186
187
}

188
void GetMetaDataJob::setMaximumSize(qint64 size)
189
{
Laurent Montel's avatar
Laurent Montel committed
190
191
    Q_D(GetMetaDataJob);
    d->maxSize = size;
192
193
194
195
}

void GetMetaDataJob::setDepth(Depth depth)
{
Laurent Montel's avatar
Laurent Montel committed
196
    Q_D(GetMetaDataJob);
197

Laurent Montel's avatar
Laurent Montel committed
198
    switch (depth) {
199
    case OneLevel:
Laurent Montel's avatar
Laurent Montel committed
200
201
        d->depth = "1"; //krazy:exclude=doublequote_chars
        break;
202
    case AllLevels:
Laurent Montel's avatar
Laurent Montel committed
203
204
        d->depth = "infinity";
        break;
205
    default:
Laurent Montel's avatar
Laurent Montel committed
206
207
        d->depth = "0"; //krazy:exclude=doublequote_chars
    }
208
209
}

210
QByteArray GetMetaDataJob::metaData(const QString &mailBox, const QByteArray &entry, const QByteArray &attribute) const
211
{
Laurent Montel's avatar
Laurent Montel committed
212
213
    Q_D(const GetMetaDataJob);
    QByteArray attr = attribute;
214

Laurent Montel's avatar
Laurent Montel committed
215
216
217
    if (d->serverCapability == Metadata) {
        attr = "";
    }
218

Laurent Montel's avatar
Laurent Montel committed
219
220
221
222
223
    QByteArray result;
    if (d->metadata.contains(mailBox)) {
        if (d->metadata[mailBox].contains(entry)) {
            result = d->metadata[mailBox][entry].value(attr);
        }
224
    }
Laurent Montel's avatar
Laurent Montel committed
225
    return result;
226
227
}

Laurent Montel's avatar
Laurent Montel committed
228
QByteArray GetMetaDataJob::metaData(const QByteArray &entry) const
229
{
Laurent Montel's avatar
Laurent Montel committed
230
    qCDebug(KIMAP_LOG) << entry;
Laurent Montel's avatar
Laurent Montel committed
231
232
    Q_D(const GetMetaDataJob);
    return d->metadata.value(d->mailBox).value(d->removePrefix(entry)).value(d->getAttribute(entry));
233
234
}

235
QMap<QByteArray, QMap<QByteArray, QByteArray> > GetMetaDataJob::allMetaData(const QString &mailBox) const
Kevin Ottens's avatar
Kevin Ottens committed
236
{
Laurent Montel's avatar
Laurent Montel committed
237
238
    Q_D(const GetMetaDataJob);
    return d->metadata[mailBox];
Kevin Ottens's avatar
Kevin Ottens committed
239
}
240
241
242

QMap<QByteArray, QByteArray> GetMetaDataJob::allMetaData() const
{
Laurent Montel's avatar
Laurent Montel committed
243
    Q_D(const GetMetaDataJob);
244
245
246
247
248
249
250
    return allMetaDataForMailbox(d->mailBox);
}

QMap<QByteArray, QByteArray> GetMetaDataJob::allMetaDataForMailbox(const QString &mailbox) const
{
    Q_D(const GetMetaDataJob);
    const QMap<QByteArray, QMap<QByteArray, QByteArray> > &entries = d->metadata[mailbox];
Laurent Montel's avatar
Laurent Montel committed
251
252
253
254
255
256
    QMap<QByteArray, QByteArray> map;
    foreach (const QByteArray &entry, entries.keys()) {
        const QMap<QByteArray, QByteArray> &values = entries[entry];
        foreach (const QByteArray &attribute, values.keys()) {
            map.insert(d->addPrefix(entry, attribute), values[attribute]);
        }
257
    }
Laurent Montel's avatar
Laurent Montel committed
258
    return map;
259
260
}

261
262
263
264
QHash<QString, QMap<QByteArray, QByteArray> > GetMetaDataJob::allMetaDataForMailboxes() const
{
    Q_D(const GetMetaDataJob);
    QHash<QString, QMap<QByteArray, QByteArray> > mailboxHash;
Laurent Montel's avatar
Laurent Montel committed
265
266
267
268
269

    QMapIterator<QString, QMap<QByteArray, QMap<QByteArray, QByteArray> > > i(d->metadata);
    while (i.hasNext()) {
        i.next();
        mailboxHash.insert(i.key(), allMetaDataForMailbox(i.key()));
270
271
272
273
    }
    return mailboxHash;
}