KIMAP

listjob.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Kevin Ottens <ervin@kde.org>
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
17namespace KIMAP
18{
19class ListJobPrivate : public JobPrivate
20{
21public:
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
56using namespace KIMAP;
57
58ListJob::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
67ListJob::~ListJob()
68{
69}
70
71void 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
81bool ListJob::isIncludeUnsubscribed() const
82{
83 Q_D(const ListJob);
84 return (d->option == ListJob::IncludeUnsubscribed);
85}
86
87void ListJob::setOption(Option option)
88{
89 Q_D(ListJob);
90 d->option = option;
91}
92
93ListJob::Option ListJob::option() const
94{
95 Q_D(const ListJob);
96 return d->option;
97}
98
99void ListJob::setQueriedNamespaces(const QList<MailBoxDescriptor> &namespaces)
100{
101 Q_D(ListJob);
102 d->namespaces = namespaces;
103}
104
105QList<MailBoxDescriptor> ListJob::queriedNamespaces() const
106{
107 Q_D(const ListJob);
108 return d->namespaces;
109}
110
111QList<MailBoxDescriptor> ListJob::mailBoxes() const
112{
114}
115
116QMap<MailBoxDescriptor, QList<QByteArray>> ListJob::flags() const
117{
119}
120
121void 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
155void 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
199void 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(QLatin1StringView("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"
QString i18n(const char *text, const TYPE &arg...)
QString fullName(const PartType &type)
QString name(StandardShortcut id)
bool isEmpty() const const
qsizetype size() const const
iterator begin()
void clear()
iterator end()
bool isEmpty() const const
void removeAt(qsizetype i)
QString arg(Args &&... args) const const
void chop(qsizetype n)
QString fromUtf8(QByteArrayView str)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toUtf8() const const
QString join(QChar separator) const const
CaseInsensitive
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
This file is part of the IMAP support library and defines the RfcCodecs class.
KIMAP_EXPORT QByteArray decodeImapFolderName(const QByteArray &inSrc)
Converts an UTF-7 encoded IMAP mailbox to a QByteArray.
Definition rfccodecs.cpp:53
KIMAP_EXPORT QByteArray encodeImapFolderName(const QByteArray &src)
Converts an Unicode IMAP mailbox to a QByteArray which can be used in IMAP communication.
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:37 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.