KIMAP

listjob.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Kevin Ottens <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "listjob.h"
8 
9 #include <KLocalizedString>
10 #include <QTimer>
11 
12 #include "job_p.h"
13 #include "response_p.h"
14 #include "rfccodecs.h"
15 #include "session_p.h"
16 
17 namespace KIMAP
18 {
19 class ListJobPrivate : public JobPrivate
20 {
21 public:
22  ListJobPrivate(ListJob *job, Session *session, const QString &name)
23  : JobPrivate(session, name)
24  , q(job)
25  , option(ListJob::NoOption)
26  {
27  }
28  ~ListJobPrivate()
29  {
30  }
31 
32  void emitPendings()
33  {
34  if (pendingDescriptors.isEmpty()) {
35  return;
36  }
37 
38  Q_EMIT q->mailBoxesReceived(pendingDescriptors, pendingFlags);
39 
40  pendingDescriptors.clear();
41  pendingFlags.clear();
42  }
43 
44  ListJob *const q;
45 
46  ListJob::Option option;
47  QList<MailBoxDescriptor> namespaces;
48  QByteArray command;
49 
50  QTimer emitPendingsTimer;
51  QList<MailBoxDescriptor> pendingDescriptors;
52  QList<QList<QByteArray>> pendingFlags;
53 };
54 }
55 
56 using namespace KIMAP;
57 
58 ListJob::ListJob(Session *session)
59  : Job(*new ListJobPrivate(this, session, i18n("List")))
60 {
61  Q_D(ListJob);
62  connect(&d->emitPendingsTimer, &QTimer::timeout, this, [d]() {
63  d->emitPendings();
64  });
65 }
66 
67 ListJob::~ListJob()
68 {
69 }
70 
71 void ListJob::setIncludeUnsubscribed(bool include)
72 {
73  Q_D(ListJob);
74  if (include) {
75  d->option = ListJob::IncludeUnsubscribed;
76  } else {
77  d->option = ListJob::NoOption;
78  }
79 }
80 
81 bool ListJob::isIncludeUnsubscribed() const
82 {
83  Q_D(const ListJob);
84  return (d->option == ListJob::IncludeUnsubscribed);
85 }
86 
87 void ListJob::setOption(Option option)
88 {
89  Q_D(ListJob);
90  d->option = option;
91 }
92 
93 ListJob::Option ListJob::option() const
94 {
95  Q_D(const ListJob);
96  return d->option;
97 }
98 
99 void ListJob::setQueriedNamespaces(const QList<MailBoxDescriptor> &namespaces)
100 {
101  Q_D(ListJob);
102  d->namespaces = namespaces;
103 }
104 
105 QList<MailBoxDescriptor> ListJob::queriedNamespaces() const
106 {
107  Q_D(const ListJob);
108  return d->namespaces;
109 }
110 
111 QList<MailBoxDescriptor> ListJob::mailBoxes() const
112 {
113  return QList<MailBoxDescriptor>();
114 }
115 
116 QMap<MailBoxDescriptor, QList<QByteArray>> ListJob::flags() const
117 {
119 }
120 
121 void ListJob::doStart()
122 {
123  Q_D(ListJob);
124 
125  switch (d->option) {
126  case IncludeUnsubscribed:
127  d->command = "LIST";
128  break;
129  case IncludeFolderRoleFlags:
130  d->command = "XLIST";
131  break;
132  case NoOption:
133  d->command = "LSUB";
134  }
135 
136  d->emitPendingsTimer.start(100);
137 
138  if (d->namespaces.isEmpty()) {
139  d->tags << d->sessionInternal()->sendCommand(d->command, "\"\" *");
140  } else {
141  for (const MailBoxDescriptor &descriptor : std::as_const(d->namespaces)) {
142  QString parameters = QStringLiteral("\"\" \"%1\"");
143 
144  if (descriptor.name.endsWith(descriptor.separator)) {
145  QString name = encodeImapFolderName(descriptor.name);
146  name.chop(1);
147  d->tags << d->sessionInternal()->sendCommand(d->command, parameters.arg(name).toUtf8());
148  }
149 
150  d->tags << d->sessionInternal()->sendCommand(d->command, parameters.arg(descriptor.name + QLatin1Char('*')).toUtf8());
151  }
152  }
153 }
154 
155 void ListJob::handleResponse(const Response &response)
156 {
157  Q_D(ListJob);
158 
159  // We can predict it'll be handled by handleErrorReplies() so stop
160  // the timer now so that result() will really be the last emitted signal.
161  if (!response.content.isEmpty() && d->tags.size() == 1 && d->tags.contains(response.content.first().toString())) {
162  d->emitPendingsTimer.stop();
163  d->emitPendings();
164  }
165 
166  if (handleErrorReplies(response) == NotHandled) {
167  if (response.content.size() >= 5 && response.content[1].toString() == d->command) {
168  QList<QByteArray> flags = response.content[2].toList();
169  for (QList<QByteArray>::iterator it = flags.begin(), itEnd = flags.end(); it != itEnd; ++it) {
170  *it = it->toLower();
171  }
172  QByteArray separator = response.content[3].toString();
173  if (separator.isEmpty()) {
174  // Defaults to / for servers reporting an empty list
175  // it's supposedly not a problem as servers doing that
176  // only do it for mailboxes with no child.
177  separator = "/"; // krazy:exclude=doublequote_chars since a QByteArray
178  }
179  Q_ASSERT(separator.size() == 1);
181  for (int i = 4; i < response.content.size(); i++) {
182  fullName += response.content[i].toString() + ' ';
183  }
184  fullName.chop(1);
185 
186  fullName = decodeImapFolderName(fullName);
187 
188  MailBoxDescriptor mailBoxDescriptor;
189  mailBoxDescriptor.separator = QLatin1Char(separator[0]);
190  mailBoxDescriptor.name = QString::fromUtf8(fullName);
191  convertInboxName(mailBoxDescriptor);
192 
193  d->pendingDescriptors << mailBoxDescriptor;
194  d->pendingFlags << flags;
195  }
196  }
197 }
198 
199 void ListJob::convertInboxName(KIMAP::MailBoxDescriptor &descriptor)
200 {
201  // Inbox must be case sensitive, according to the RFC, so make it always uppercase
202  QStringList pathParts = descriptor.name.split(descriptor.separator);
203  if (!pathParts.isEmpty() && pathParts[0].compare(QLatin1String("INBOX"), Qt::CaseInsensitive) == 0) {
204  pathParts.removeAt(0);
205  descriptor.name = QStringLiteral("INBOX");
206  if (!pathParts.isEmpty()) {
207  descriptor.name += descriptor.separator + pathParts.join(descriptor.separator);
208  }
209  }
210 }
211 #include "moc_listjob.cpp"
KIMAP2_EXPORT QByteArray encodeImapFolderName(const QByteArray &src)
Converts an Unicode IMAP mailbox to a QByteArray which can be used in IMAP communication.
Definition: rfccodecs.cpp:185
QString fromUtf8(const char *str, int size)
CaseInsensitive
void chop(int n)
KIMAP2_EXPORT QByteArray decodeImapFolderName(const QByteArray &inSrc)
Converts an UTF-7 encoded IMAP mailbox to a QByteArray.
Definition: rfccodecs.cpp:53
void removeAt(int i)
QString i18n(const char *text, const TYPE &arg...)
void timeout()
QByteArray toUtf8() const const
bool isEmpty() const const
QString join(const QString &separator) const const
bool isEmpty() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const char * name(StandardAction id)
QList::iterator begin()
int size() const const
QList::iterator end()
Provides handlers for various RFC/MIME encodings.
QString fullName(const PartType &type)
Q_D(Todo)
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.