KIMAP

getmetadatajob.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Andras Mantia <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "getmetadatajob.h"
8 
9 #include "kimap_debug.h"
10 #include <KLocalizedString>
11 
12 #include "metadatajobbase_p.h"
13 #include "response_p.h"
14 #include "rfccodecs.h"
15 #include "session_p.h"
16 
17 namespace KIMAP
18 {
19 class GetMetaDataJobPrivate : public MetaDataJobBasePrivate
20 {
21 public:
22  GetMetaDataJobPrivate(Session *session, const QString &name)
23  : MetaDataJobBasePrivate(session, name)
24  , depth("0")
25  {
26  }
27  ~GetMetaDataJobPrivate()
28  {
29  }
30 
31  qint64 maxSize = -1;
32  QByteArray depth;
33  QSet<QByteArray> entries;
34  QSet<QByteArray> attributes;
36  // ^ mailbox ^ entry ^attribute ^ value
37 };
38 }
39 
40 using namespace KIMAP;
41 
42 GetMetaDataJob::GetMetaDataJob(Session *session)
43  : MetaDataJobBase(*new GetMetaDataJobPrivate(session, i18n("GetMetaData")))
44 {
45 }
46 
47 GetMetaDataJob::~GetMetaDataJob()
48 {
49 }
50 
51 static QList<QByteArray> sort(const QSet<QByteArray> &set)
52 {
53  QList<QByteArray> sortedEntries = set.values();
54  std::sort(sortedEntries.begin(), sortedEntries.end());
55  return sortedEntries;
56 }
57 
58 void GetMetaDataJob::doStart()
59 {
61  QByteArray parameters;
62  parameters = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" ";
63 
64  QByteArray command = "GETMETADATA";
65  if (d->serverCapability == Annotatemore) {
66  d->m_name = i18n("GetAnnotation");
67  command = "GETANNOTATION";
68  if (d->entries.size() > 1) {
69  parameters += '(';
70  }
71  const auto sortedEntries = sort(d->entries);
72  for (const QByteArray &entry : sortedEntries) {
73  parameters += '\"' + entry + "\" ";
74  }
75  if (d->entries.size() > 1) {
76  parameters[parameters.length() - 1] = ')';
77  parameters += ' ';
78  }
79 
80  if (d->attributes.size() > 1) {
81  parameters += '(';
82  }
83  const auto sortedAttributes = sort(d->attributes);
84  for (const QByteArray &attribute : sortedAttributes) {
85  parameters += '\"' + attribute + "\" ";
86  }
87  if (d->attributes.size() > 1) {
88  parameters[parameters.length() - 1] = ')';
89  } else {
90  parameters.chop(1);
91  }
92 
93  } else {
94  QByteArray options;
95  if (d->depth != "0") {
96  options = "DEPTH " + d->depth;
97  }
98  if (d->maxSize != -1) {
99  if (!options.isEmpty()) {
100  options += ' ';
101  }
102  options += "MAXSIZE " + QByteArray::number(d->maxSize);
103  }
104 
105  if (!options.isEmpty()) {
106  parameters = "(" + options + ") " + parameters;
107  }
108 
109  if (d->entries.size() >= 1) {
110  parameters += '(';
111  const auto sortedEntries = sort(d->entries);
112  for (const QByteArray &entry : sortedEntries) {
113  parameters += entry + " ";
114  }
115  parameters[parameters.length() - 1] = ')';
116  } else {
117  parameters.chop(1);
118  }
119  }
120 
121  d->tags << d->sessionInternal()->sendCommand(command, parameters);
122  // qCDebug(KIMAP_LOG) << "SENT: " << command << " " << parameters;
123 }
124 
125 void GetMetaDataJob::handleResponse(const Response &response)
126 {
128  // qCDebug(KIMAP_LOG) << "GOT: " << response.toString();
129 
130  // TODO: handle NO error messages having [METADATA MAXSIZE NNN], [METADATA TOOMANY], [METADATA NOPRIVATE] (see rfc5464)
131  // or [ANNOTATEMORE TOOBIG], [ANNOTATEMORE TOOMANY] respectively
132  if (handleErrorReplies(response) == NotHandled) {
133  if (response.content.size() >= 4) {
134  if (d->serverCapability == Annotatemore && response.content[1].toString() == "ANNOTATION") {
135  QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));
136 
137  int i = 3;
138  while (i < response.content.size() - 1) {
139  QByteArray entry = response.content[i].toString();
140  QList<QByteArray> attributes = response.content[i + 1].toList();
141  int j = 0;
142  while (j < attributes.size() - 1) {
143  d->metadata[mailBox][entry][attributes[j]] = attributes[j + 1];
144  j += 2;
145  }
146  i += 2;
147  }
148  } else if (d->serverCapability == Metadata && response.content[1].toString() == "METADATA") {
149  QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));
150 
151  const QList<QByteArray> &entries = response.content[3].toList();
152  int i = 0;
153  while (i < entries.size() - 1) {
154  const QByteArray &value = entries[i + 1];
155  QByteArray &targetValue = d->metadata[mailBox][entries[i]][""];
156  if (value != "NIL") { // This just indicates no value
157  targetValue = value;
158  }
159  i += 2;
160  }
161  }
162  }
163  }
164 }
165 
166 void GetMetaDataJob::addEntry(const QByteArray &entry, const QByteArray &attribute)
167 {
169  if (d->serverCapability == Annotatemore && attribute.isNull()) {
170  qCWarning(KIMAP_LOG) << "In ANNOTATEMORE mode an attribute must be specified with addEntry!";
171  }
172  d->entries.insert(entry);
173  d->attributes.insert(attribute);
174 }
175 
177 {
179  d->entries.insert(d->removePrefix(entry));
180  d->attributes.insert(d->getAttribute(entry));
181 }
182 
184 {
186  d->maxSize = size;
187 }
188 
190 {
192 
193  switch (depth) {
194  case OneLevel:
195  d->depth = "1"; // krazy:exclude=doublequote_chars
196  break;
197  case AllLevels:
198  d->depth = "infinity";
199  break;
200  default:
201  d->depth = "0"; // krazy:exclude=doublequote_chars
202  }
203 }
204 
205 QByteArray GetMetaDataJob::metaData(const QString &mailBox, const QByteArray &entry, const QByteArray &attribute) const
206 {
207  Q_D(const GetMetaDataJob);
208  QByteArray attr = attribute;
209 
210  if (d->serverCapability == Metadata) {
211  attr = "";
212  }
213 
215  if (d->metadata.contains(mailBox)) {
216  if (d->metadata[mailBox].contains(entry)) {
217  result = d->metadata[mailBox][entry].value(attr);
218  }
219  }
220  return result;
221 }
222 
224 {
225  qCDebug(KIMAP_LOG) << entry;
226  Q_D(const GetMetaDataJob);
227  return d->metadata.value(d->mailBox).value(d->removePrefix(entry)).value(d->getAttribute(entry));
228 }
229 
231 {
232  Q_D(const GetMetaDataJob);
233  return d->metadata[mailBox];
234 }
235 
237 {
238  Q_D(const GetMetaDataJob);
239  return allMetaDataForMailbox(d->mailBox);
240 }
241 
243 {
244  Q_D(const GetMetaDataJob);
245  const QMap<QByteArray, QMap<QByteArray, QByteArray>> &entries = d->metadata[mailbox];
247  const auto entriesKeys = entries.keys();
248  for (const QByteArray &entry : entriesKeys) {
249  const QMap<QByteArray, QByteArray> &values = entries[entry];
250  const auto valuesKeys = values.keys();
251  for (const QByteArray &attribute : valuesKeys) {
252  map.insert(d->addPrefix(entry, attribute), values[attribute]);
253  }
254  }
255  return map;
256 }
257 
259 {
260  Q_D(const GetMetaDataJob);
262 
264  while (i.hasNext()) {
265  i.next();
266  mailboxHash.insert(i.key(), allMetaDataForMailbox(i.key()));
267  }
268  return mailboxHash;
269 }
270 
271 #include "moc_getmetadatajob.cpp"
KIMAP_EXPORT QString encodeImapFolderName(const QString &src)
Converts an Unicode IMAP mailbox to a QString which can be used in IMAP communication.
Definition: rfccodecs.cpp:180
QMap< QByteArray, QByteArray > allMetaDataForMailbox(const QString &mailbox) const
Get all the metadata for the mailbox.
bool isNull() const const
QMap< QByteArray, QByteArray > allMetaData() const
Get all the metadata for the mailbox set with setMailBox().
QString fromUtf8(const char *str, int size)
void result(KJob *job)
KIMAP_DEPRECATED QByteArray metaData(const QString &mailBox, const QByteArray &entry, const QByteArray &attribute=QByteArray()) const
Get a single metadata entry.
QByteArray number(int n, int base)
@ AllLevels
The requested entries and all their descendants.
bool hasNext() const const
QString mailBox() const
The mailbox that will be acted upon.
QHash< QString, QMap< QByteArray, QByteArray > > allMetaDataForMailboxes() const
Get all the metadata for for all mailboxes.
Fetches mailbox metadata.
QHash::iterator insert(const Key &key, const T &value)
int size() const const
void chop(int n)
QString i18n(const char *text, const TYPE &arg...)
void addRequestedEntry(const QByteArray &entry)
Add an entry to the query list.
Depth
Used to specify the depth of the metadata hierarchy to walk.
void setMaximumSize(qint64 size)
Limits the size of returned metadata entries.
@ Metadata
Used to indicate that the server supports the RFC 5464 version of the extension.
KIMAP_DEPRECATED void addEntry(const QByteArray &entry, const QByteArray &attribute=QByteArray())
Add an entry to the query list.
QMapIterator::Item next()
bool isEmpty() const const
QList< Key > keys() const const
@ OneLevel
The requested entries and all their direct children.
const Key & key() const const
const char * name(StandardAction id)
void setDepth(Depth depth)
Sets whether to retrieve children or descendants of the requested entries.
@ Annotatemore
Used to indicate that the server supports the draft-daboo-imap-annotatemore-07 version of the extensi...
QList::iterator begin()
int length() const const
QList::iterator end()
QList< T > values() const const
Provides handlers for various RFC/MIME encodings.
QVector< V > values(const QMultiHash< K, V > &c)
Q_D(Todo)
Base class for jobs that operate on mailbox metadata.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 3 2023 03:51:44 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.