├── .codespellrc ├── .codespellrc.license ├── .git-blame-ignore-revs ├── .gitignore ├── .gitlab-ci.yml ├── .kde-ci.yml ├── .krazy ├── .krazy.license ├── CMakeLists.txt ├── CMakePresets.json ├── CMakePresets.json.license ├── KPimIMAPConfig.cmake.in ├── LICENSES ├── BSD-3-Clause.txt ├── CC0-1.0.txt ├── GPL-2.0-or-later.txt ├── LGPL-2.0-only.txt └── LGPL-2.0-or-later.txt ├── README.md ├── README.md.license ├── REUSE.toml ├── autotests ├── CMakeLists.txt ├── appendjobtest.cpp ├── capabilitiesjobtest.cpp ├── closejobtest.cpp ├── createjobtest.cpp ├── deletejobtest.cpp ├── enablejobtest.cpp ├── expungejobtest.cpp ├── fakeserverscenario.log ├── fakeservertest.cpp ├── fetchjobtest.cpp ├── getmetadatajobtest.cpp ├── idjobtest.cpp ├── idlejobtest.cpp ├── imapsettest.cpp ├── kimaptest │ ├── CMakeLists.txt │ ├── fakeserver.cpp │ ├── fakeserver.h │ ├── mockjob.cpp │ ├── mockjob.h │ ├── sslserver.cpp │ └── sslserver.h ├── listjobtest.cpp ├── loginjobtest.cpp ├── logoutjobtest.cpp ├── movejobtest.cpp ├── quotarootjobtest.cpp ├── renamejobtest.cpp ├── searchjobtest.cpp ├── selectjobtest.cpp ├── setmetadatajobtest.cpp ├── statusjobtest.cpp ├── storejobtest.cpp ├── streamparsertest.cpp ├── subscribejobtest.cpp ├── testrfccodecs.cpp ├── testrfccodecs.h ├── testsession.cpp └── unsubscribejobtest.cpp ├── metainfo.yaml ├── metainfo.yaml.license ├── po ├── ar │ └── libkimap6.po ├── ast │ └── libkimap6.po ├── bs │ └── libkimap6.po ├── ca │ └── libkimap6.po ├── ca@valencia │ └── libkimap6.po ├── cs │ └── libkimap6.po ├── da │ └── libkimap6.po ├── de │ └── libkimap6.po ├── el │ └── libkimap6.po ├── en_GB │ └── libkimap6.po ├── eo │ └── libkimap6.po ├── es │ └── libkimap6.po ├── et │ └── libkimap6.po ├── eu │ └── libkimap6.po ├── fi │ └── libkimap6.po ├── fr │ └── libkimap6.po ├── ga │ └── libkimap6.po ├── gl │ └── libkimap6.po ├── he │ └── libkimap6.po ├── hi │ └── libkimap6.po ├── hu │ └── libkimap6.po ├── ia │ └── libkimap6.po ├── it │ └── libkimap6.po ├── ja │ └── libkimap6.po ├── ka │ └── libkimap6.po ├── kk │ └── libkimap6.po ├── km │ └── libkimap6.po ├── ko │ └── libkimap6.po ├── lt │ └── libkimap6.po ├── lv │ └── libkimap6.po ├── mr │ └── libkimap6.po ├── nb │ └── libkimap6.po ├── nds │ └── libkimap6.po ├── nl │ └── libkimap6.po ├── nn │ └── libkimap6.po ├── pa │ └── libkimap6.po ├── pl │ └── libkimap6.po ├── pt │ └── libkimap6.po ├── pt_BR │ └── libkimap6.po ├── ro │ └── libkimap6.po ├── ru │ └── libkimap6.po ├── sa │ └── libkimap6.po ├── sk │ └── libkimap6.po ├── sl │ └── libkimap6.po ├── sq │ └── libkimap6.po ├── sr │ └── libkimap6.po ├── sr@ijekavian │ └── libkimap6.po ├── sr@ijekavianlatin │ └── libkimap6.po ├── sr@latin │ └── libkimap6.po ├── sv │ └── libkimap6.po ├── ta │ └── libkimap6.po ├── tr │ └── libkimap6.po ├── ug │ └── libkimap6.po ├── uk │ └── libkimap6.po ├── zh_CN │ └── libkimap6.po └── zh_TW │ └── libkimap6.po ├── readme-build-ftime.txt ├── sanitizers.supp ├── src ├── CMakeLists.txt ├── Messages.sh ├── acl.cpp ├── acl.h ├── acljobbase.cpp ├── acljobbase.h ├── acljobbase_p.h ├── appendjob.cpp ├── appendjob.h ├── capabilitiesjob.cpp ├── capabilitiesjob.h ├── closejob.cpp ├── closejob.h ├── common.h ├── copyjob.cpp ├── copyjob.h ├── createjob.cpp ├── createjob.h ├── deleteacljob.cpp ├── deleteacljob.h ├── deletejob.cpp ├── deletejob.h ├── enablejob.cpp ├── enablejob.h ├── expungejob.cpp ├── expungejob.h ├── fetchjob.cpp ├── fetchjob.h ├── getacljob.cpp ├── getacljob.h ├── getmetadatajob.cpp ├── getmetadatajob.h ├── getquotajob.cpp ├── getquotajob.h ├── getquotarootjob.cpp ├── getquotarootjob.h ├── idjob.cpp ├── idjob.h ├── idlejob.cpp ├── idlejob.h ├── imapset.cpp ├── imapset.h ├── imapstreamparser.cpp ├── imapstreamparser.h ├── job.cpp ├── job.h ├── job_p.h ├── listjob.cpp ├── listjob.h ├── listrightsjob.cpp ├── listrightsjob.h ├── loginjob.cpp ├── loginjob.h ├── logoutjob.cpp ├── logoutjob.h ├── metadatajobbase.cpp ├── metadatajobbase.h ├── metadatajobbase_p.h ├── movejob.cpp ├── movejob.h ├── myrightsjob.cpp ├── myrightsjob.h ├── namespacejob.cpp ├── namespacejob.h ├── quotajobbase.cpp ├── quotajobbase.h ├── quotajobbase_p.h ├── renamejob.cpp ├── renamejob.h ├── response_p.h ├── rfccodecs.cpp ├── rfccodecs.h ├── searchjob.cpp ├── searchjob.h ├── selectjob.cpp ├── selectjob.h ├── session.cpp ├── session.h ├── session_p.h ├── sessionlogger.cpp ├── sessionlogger_p.h ├── sessionthread.cpp ├── sessionthread_p.h ├── sessionuiproxy.cpp ├── sessionuiproxy.h ├── setacljob.cpp ├── setacljob.h ├── setmetadatajob.cpp ├── setmetadatajob.h ├── setquotajob.cpp ├── setquotajob.h ├── statusjob.cpp ├── statusjob.h ├── storejob.cpp ├── storejob.h ├── subscribejob.cpp ├── subscribejob.h ├── unsubscribejob.cpp └── unsubscribejob.h └── tests ├── CMakeLists.txt ├── testimapidle.cpp └── testimapserver.cpp /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | skip = ./build*,.git,*.notifyrc,*.desktop,*.json,*.xml 3 | interactive = 3 4 | ignore-words-list = accessort 5 | -------------------------------------------------------------------------------- /.codespellrc.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022-2025 Laurent Montel 2 | # SPDX-License-Identifier: CC0-1.0 3 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: CC0-1.0 2 | # SPDX-FileCopyrightText: none 3 | # clang-format 4 | dab484f8cf3ba7809a134e8589690c9bed6b45d5 5 | 5ffbc07640fc932ebf7b87928bb1f8d6405e1b96 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: CC0-1.0 2 | # SPDX-FileCopyrightText: none 3 | # Ignore the following files 4 | *~ 5 | *.[oa] 6 | *.diff 7 | *.kate-swp 8 | *.kdev4 9 | .kdev_include_paths 10 | *.kdevelop.pcs 11 | *.moc 12 | *.moc.cpp 13 | *.orig 14 | *.user 15 | .*.swp 16 | .swp.* 17 | Doxyfile 18 | Makefile 19 | /build*/ 20 | .cmake/ 21 | CMakeLists.txt.user* 22 | *.unc-backup* 23 | compile_commands.json 24 | .clang-format 25 | .clangd 26 | .idea 27 | /cmake-build* 28 | .cache 29 | Testing/ 30 | /.vscode/ 31 | .qtcreator/ 32 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2020-2025 Laurent Montel 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | include: 5 | - project: sysadmin/ci-utilities 6 | file: 7 | - /gitlab-templates/linux-qt6-next.yml 8 | - /gitlab-templates/json-validation.yml 9 | - /gitlab-templates/freebsd-qt6.yml 10 | - /gitlab-templates/windows-qt6.yml 11 | - /gitlab-templates/reuse-lint.yml 12 | - /gitlab-templates/cppcheck.yml 13 | - /gitlab-templates/clang-format.yml 14 | - /gitlab-templates/alpine-qt6.yml 15 | - /gitlab-templates/xml-lint.yml 16 | - /gitlab-templates/yaml-lint.yml 17 | -------------------------------------------------------------------------------- /.kde-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | Dependencies: 5 | - 'on': ['Linux', 'FreeBSD', 'Windows'] 6 | 'require': 7 | 'frameworks/extra-cmake-modules': '@latest-kf6' 8 | 'pim/kmime': '@same' 9 | 'frameworks/kcoreaddons': '@latest-kf6' 10 | 'frameworks/ki18n': '@latest-kf6' 11 | 'frameworks/kio': '@latest-kf6' 12 | 13 | Options: 14 | require-passing-tests-on: ['Linux', 'FreeBSD'] 15 | allow-failing-tests-on: ['Windows'] 16 | tests-run-in-parallel: True 17 | -------------------------------------------------------------------------------- /.krazy: -------------------------------------------------------------------------------- 1 | SKIP /tests/ 2 | -------------------------------------------------------------------------------- /.krazy.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: none 2 | SPDX-License-Identifier: CC0-1.0 3 | -------------------------------------------------------------------------------- /CMakePresets.json.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021-2025 Laurent Montel 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | -------------------------------------------------------------------------------- /KPimIMAPConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2019 Christophe Giboudeaux 2 | # SPDX-FileCopyrightText: 2017-2025 Laurent Montel 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | @PACKAGE_INIT@ 6 | 7 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH}) 8 | include(CMakeFindDependencyMacro) 9 | find_dependency(KF6CoreAddons "@KF_MIN_VERSION@") 10 | find_dependency(KPim6Mime "@KMIME_LIBS_VERSION@") 11 | include("${CMAKE_CURRENT_LIST_DIR}/KPim6IMAPTargets.cmake") 12 | @PACKAGE_INCLUDE_QCHTARGETS@ 13 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KIMAP # 2 | 3 | This library provides a job-based API for interacting with an IMAP4rev1 server. 4 | It manages connections, encryption and parameter quoting and encoding, but 5 | otherwise provides quite a low-level interface to the protocol. This library 6 | does not implement an IMAP client; it merely makes it easier to do so. 7 | 8 | Users should be familiar with [RFC 3501](https://tools.ietf.org/html/rfc3501 "IMAP 4rev1") 9 | as well as [other related RFCs](https://www.iana.org/assignments/imap4-capabilities) 10 | although the library hides some of the nastier details like the encoding and quoting of 11 | strings. 12 | -------------------------------------------------------------------------------- /README.md.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: none 2 | SPDX-License-Identifier: CC0-1.0 3 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: none 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | version = 1 5 | SPDX-PackageName = "kimap" 6 | SPDX-PackageSupplier = "Montel Laurent " 7 | SPDX-PackageDownloadLocation = "https://invent.kde.org/pim/kimap" 8 | 9 | [[annotations]] 10 | path = ["autotests/fakeserverscenario.log", "readme-build-ftime.txt"] 11 | precedence = "aggregate" 12 | SPDX-FileCopyrightText = "none" 13 | SPDX-License-Identifier = "CC0-1.0" 14 | -------------------------------------------------------------------------------- /autotests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: none 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | kde_enable_exceptions() 4 | 5 | include(ECMMarkAsTest) 6 | 7 | add_subdirectory(kimaptest) 8 | 9 | macro(KIMAP_UNIT_TESTS) 10 | foreach(_testname ${ARGN}) 11 | add_executable(${_testname} ${_testname}.cpp) 12 | add_test(NAME ${_testname} COMMAND ${_testname}) 13 | ecm_mark_as_test(${_testname}) 14 | target_link_libraries(${_testname} KPim6IMAP Qt::Test kimaptest6 Qt::Network) 15 | set_target_properties(${_testname} PROPERTIES COMPILE_FLAGS -DTEST_DATA="\\"${CMAKE_CURRENT_SOURCE_DIR}\\"") 16 | set_tests_properties(${_testname} PROPERTIES RUN_SERIAL TRUE) 17 | endforeach() 18 | endmacro() 19 | 20 | ########### automated tests ############### 21 | 22 | KIMAP_UNIT_TESTS( 23 | fakeservertest 24 | testrfccodecs 25 | testsession 26 | loginjobtest 27 | logoutjobtest 28 | capabilitiesjobtest 29 | closejobtest 30 | selectjobtest 31 | createjobtest 32 | deletejobtest 33 | enablejobtest 34 | expungejobtest 35 | fetchjobtest 36 | renamejobtest 37 | subscribejobtest 38 | unsubscribejobtest 39 | listjobtest 40 | storejobtest 41 | imapsettest 42 | idjobtest 43 | idlejobtest 44 | quotarootjobtest 45 | searchjobtest 46 | getmetadatajobtest 47 | streamparsertest 48 | setmetadatajobtest 49 | appendjobtest 50 | statusjobtest 51 | movejobtest 52 | ) 53 | -------------------------------------------------------------------------------- /autotests/appendjobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2013 Christian Mollekopf 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include "kimap/appendjob.h" 10 | #include "kimap/session.h" 11 | #include "kimaptest/fakeserver.h" 12 | 13 | #include 14 | #include 15 | 16 | class AppendJobTest : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | private Q_SLOTS: 21 | 22 | void testAppend_data() 23 | { 24 | QTest::addColumn("mailbox"); 25 | QTest::addColumn>("scenario"); 26 | QTest::addColumn>("flags"); 27 | QTest::addColumn("internaldate"); 28 | QTest::addColumn("content"); 29 | QTest::addColumn("uid"); 30 | 31 | QList flags; 32 | flags << QByteArray("\\Seen"); 33 | { 34 | QList scenario; 35 | scenario << FakeServer::preauth() << "C: A000001 APPEND \"INBOX\" (\\Seen) {7}\r\ncontent" 36 | << "S: A000001 OK APPEND completed. [ APPENDUID 492 2671 ]"; 37 | QTest::newRow("good") << "INBOX" << scenario << flags << QDateTime() << QByteArray("content") << qint64(2671); 38 | } 39 | { 40 | QList scenario; 41 | scenario << FakeServer::preauth() << "C: A000001 APPEND \"INBOX\" (\\Seen) \"26-Feb-2014 12:38:00 +0000\" {7}\r\ncontent" 42 | << "S: A000001 OK APPEND completed. [ APPENDUID 493 2672 ]"; 43 | QTest::newRow("good, with internalDate set") 44 | << "INBOX" << scenario << flags << QDateTime::fromString(QStringLiteral("2014-02-26T12:38:00Z"), Qt::ISODate) << QByteArray("content") 45 | << qint64(2672); 46 | } 47 | 48 | { 49 | QList scenario; 50 | scenario << FakeServer::preauth() << "C: A000001 APPEND \"INBOX\" (\\Seen) {7}\r\ncontent" 51 | << "S: BYE" 52 | << "X"; 53 | QTest::newRow("bad") << "INBOX" << scenario << flags << QDateTime() << QByteArray("content") << qint64(0); 54 | } 55 | { 56 | QList scenario; 57 | scenario << FakeServer::preauth() << "C: A000001 APPEND \"INBOX\" (\\Seen) {7}\r\ncontent" 58 | << "S: " 59 | << "X"; 60 | QTest::newRow("Don't crash on empty response") << "INBOX" << scenario << flags << QDateTime() << QByteArray("content") << qint64(0); 61 | } 62 | } 63 | 64 | void testAppend() 65 | { 66 | QFETCH(QString, mailbox); 67 | QFETCH(QList, scenario); 68 | QFETCH(QList, flags); 69 | QFETCH(QDateTime, internaldate); 70 | QFETCH(QByteArray, content); 71 | QFETCH(qint64, uid); 72 | 73 | FakeServer fakeServer; 74 | fakeServer.setScenario(scenario); 75 | fakeServer.startAndWait(); 76 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 77 | 78 | auto job = new KIMAP::AppendJob(&session); 79 | job->setContent(content); 80 | job->setFlags(flags); 81 | job->setInternalDate(internaldate); 82 | job->setMailBox(mailbox); 83 | const bool result = job->exec(); 84 | QEXPECT_FAIL("bad", "Expected failure on connection abort", Continue); 85 | QEXPECT_FAIL("Don't crash on empty response", "Expected failure on connection abort", Continue); 86 | QVERIFY(result); 87 | QCOMPARE(job->uid(), uid); 88 | 89 | fakeServer.quit(); 90 | } 91 | }; 92 | 93 | QTEST_GUILESS_MAIN(AppendJobTest) 94 | 95 | #include "appendjobtest.moc" 96 | -------------------------------------------------------------------------------- /autotests/capabilitiesjobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/capabilitiesjob.h" 13 | #include "kimap/session.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class CapabilitiesJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testCapabilities_data() 25 | { 26 | QTest::addColumn>("scenario"); 27 | QTest::addColumn("capabilities"); 28 | QList scenario; 29 | scenario << "S: * PREAUTH" 30 | << "C: A000001 CAPABILITY" 31 | << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI" 32 | << "S: A000001 OK CAPABILITY completed"; 33 | 34 | QStringList capabilities; 35 | capabilities << QStringLiteral("IMAP4REV1") << QStringLiteral("STARTTLS") << QStringLiteral("AUTH=GSSAPI"); 36 | QTest::newRow("good") << scenario << capabilities; 37 | 38 | scenario.clear(); 39 | capabilities.clear(); 40 | scenario << "S: * PREAUTH" 41 | << "C: A000001 CAPABILITY" 42 | << "S: A000001 BAD command unknown or arguments invalid"; 43 | QTest::newRow("bad") << scenario << capabilities; 44 | 45 | scenario.clear(); 46 | capabilities.clear(); 47 | scenario << "S: * PREAUTH" 48 | << "C: A000001 CAPABILITY" 49 | << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=PLAIN" 50 | << "S: * some response" 51 | << "S: A000001 OK CAPABILITY completed"; 52 | 53 | capabilities << QStringLiteral("IMAP4REV1") << QStringLiteral("STARTTLS") << QStringLiteral("AUTH=PLAIN"); 54 | QTest::newRow("extra-untagged") << scenario << capabilities; 55 | } 56 | 57 | void testCapabilities() 58 | { 59 | QFETCH(QList, scenario); 60 | QFETCH(QStringList, capabilities); 61 | 62 | FakeServer fakeServer; 63 | fakeServer.setScenario(scenario); 64 | fakeServer.startAndWait(); 65 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 66 | 67 | auto job = new KIMAP::CapabilitiesJob(&session); 68 | bool result = job->exec(); 69 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 70 | QVERIFY(result); 71 | if (result) { 72 | QCOMPARE(job->capabilities(), capabilities); 73 | } 74 | fakeServer.quit(); 75 | } 76 | }; 77 | 78 | QTEST_GUILESS_MAIN(CapabilitiesJobTest) 79 | 80 | #include "capabilitiesjobtest.moc" 81 | -------------------------------------------------------------------------------- /autotests/closejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include "kimap/closejob.h" 10 | #include "kimap/session.h" 11 | #include "kimaptest/fakeserver.h" 12 | 13 | #include 14 | 15 | class CloseJobTest : public QObject 16 | { 17 | Q_OBJECT 18 | 19 | private Q_SLOTS: 20 | 21 | void testClose_data() 22 | { 23 | QTest::addColumn>("scenario"); 24 | QTest::addColumn("highestModSeq"); 25 | 26 | QList scenario; 27 | scenario << FakeServer::preauth() << "C: A000001 CLOSE" 28 | << "S: A000001 OK Closed"; 29 | QTest::newRow("good") << scenario << 0ULL; 30 | 31 | scenario.clear(); 32 | scenario << FakeServer::preauth() << "C: A000001 CLOSE" 33 | << "S: A000001 BAD No mailbox selected"; 34 | QTest::newRow("bad") << scenario << 0ULL; 35 | 36 | scenario.clear(); 37 | scenario << FakeServer::preauth() << "C: A000001 CLOSE" 38 | << "S: A000001 OK [HIGHESTMODSEQ 123456789] Closed."; 39 | QTest::newRow("qresync") << scenario << 123456789ULL; 40 | } 41 | 42 | void testClose() 43 | { 44 | QFETCH(QList, scenario); 45 | QFETCH(quint64, highestModSeq); 46 | 47 | FakeServer fakeServer; 48 | fakeServer.setScenario(scenario); 49 | fakeServer.startAndWait(); 50 | 51 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 52 | 53 | auto job = new KIMAP::CloseJob(&session); 54 | bool result = job->exec(); 55 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 56 | QVERIFY(result); 57 | if (result) { 58 | QCOMPARE(job->newHighestModSeq(), highestModSeq); 59 | } 60 | 61 | fakeServer.quit(); 62 | } 63 | }; 64 | 65 | QTEST_GUILESS_MAIN(CloseJobTest) 66 | 67 | #include "closejobtest.moc" 68 | -------------------------------------------------------------------------------- /autotests/createjobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/createjob.h" 13 | #include "kimap/session.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class CreateJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testCreate_data() 25 | { 26 | QTest::addColumn("mailbox"); 27 | QTest::addColumn>("scenario"); 28 | 29 | QList scenario; 30 | scenario << FakeServer::preauth() << "C: A000001 CREATE \"INBOX\"" 31 | << "S: A000001 OK CREATE completed"; 32 | QTest::newRow("good") << "INBOX" << scenario; 33 | 34 | scenario.clear(); 35 | scenario << FakeServer::preauth() << "C: A000001 CREATE \"INBOX-FAIL-BAD\"" 36 | << "S: A000001 BAD command unknown or arguments invalid"; 37 | QTest::newRow("bad") << "INBOX-FAIL-BAD" << scenario; 38 | 39 | scenario.clear(); 40 | scenario << FakeServer::preauth() << "C: A000001 CREATE \"INBOX-FAIL-NO\"" 41 | << "S: A000001 NO create failure"; 42 | QTest::newRow("no") << "INBOX-FAIL-NO" << scenario; 43 | 44 | scenario.clear(); 45 | scenario << FakeServer::preauth() << "C: A000001 CREATE \"INBOX-FAIL-IGNOREDCODE\"" 46 | << "S: A000001 NO create failure [IGNOREDCODE]"; 47 | QTest::newRow("ignoredcode") << "INBOX-FAIL-IGNOREDCODE" << scenario; 48 | 49 | scenario.clear(); 50 | scenario << FakeServer::preauth() << "C: A000001 CREATE \"INBOX-ALREADYEXISTS\"" 51 | << "S: A000001 NO create failure [ALREADYEXISTS]"; 52 | QTest::newRow("alreadyexists") << "INBOX-ALREADYEXISTS" << scenario; 53 | } 54 | 55 | void testCreate() 56 | { 57 | QFETCH(QString, mailbox); 58 | QFETCH(QList, scenario); 59 | 60 | FakeServer fakeServer; 61 | fakeServer.setScenario(scenario); 62 | fakeServer.startAndWait(); 63 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 64 | 65 | auto job = new KIMAP::CreateJob(&session); 66 | job->setMailBox(mailbox); 67 | bool result = job->exec(); 68 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 69 | QEXPECT_FAIL("no", "Expected failure on NO response", Continue); 70 | QEXPECT_FAIL("ignoredcode", "Expected failure on NO response with ignored response code", Continue); 71 | QVERIFY(result); 72 | if (result) { 73 | QCOMPARE(job->mailBox(), mailbox); 74 | } 75 | 76 | fakeServer.quit(); 77 | } 78 | }; 79 | 80 | QTEST_GUILESS_MAIN(CreateJobTest) 81 | 82 | #include "createjobtest.moc" 83 | -------------------------------------------------------------------------------- /autotests/deletejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/deletejob.h" 13 | #include "kimap/session.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class DeleteJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testDelete_data() 25 | { 26 | QTest::addColumn("mailbox"); 27 | QTest::addColumn>("scenario"); 28 | 29 | QList scenario; 30 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo\"" 31 | << "S: A000001 OK DELETE completed"; 32 | QTest::newRow("good") << "foo" << scenario; 33 | 34 | scenario.clear(); 35 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo-BAD\"" 36 | << "S: A000001 BAD command unknown or arguments invalid"; 37 | QTest::newRow("bad") << "foo-BAD" << scenario; 38 | 39 | scenario.clear(); 40 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo\"" 41 | << "S: A000001 Name \"foo\" has inferior hierarchical names"; 42 | QTest::newRow("no") << "foo" << scenario; 43 | 44 | scenario.clear(); 45 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo-IGNOREDCODE\"" 46 | << "S: A000001 NO Name \"foo-IGNOREDCODE\" does not exist [IGNOREDCODE]"; 47 | QTest::newRow("ignoredcode") << "foo-IGNOREDCODE" << scenario; 48 | 49 | scenario.clear(); 50 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo-NONEXISTENT\"" 51 | << "S: A000001 NO Name \"foo-NONEXISTENT\" does not exist [NONEXISTENT]"; 52 | QTest::newRow("nonexistent") << "foo-NONEXISTENT" << scenario; 53 | 54 | scenario.clear(); 55 | scenario << FakeServer::preauth() << "C: A000001 DELETE \"foo/bar\"" 56 | << "S: A000001 OK DELETE completed"; 57 | QTest::newRow("hierarchical") << "foo/bar" << scenario; 58 | } 59 | 60 | void testDelete() 61 | { 62 | QFETCH(QString, mailbox); 63 | QFETCH(QList, scenario); 64 | 65 | FakeServer fakeServer; 66 | fakeServer.setScenario(scenario); 67 | fakeServer.startAndWait(); 68 | 69 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 70 | 71 | auto job = new KIMAP::DeleteJob(&session); 72 | job->setMailBox(mailbox); 73 | bool result = job->exec(); 74 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 75 | QEXPECT_FAIL("no", "Expected failure on NO response", Continue); 76 | QEXPECT_FAIL("ignoredcode", "Expected failure on NO response with ignored response code", Continue); 77 | QVERIFY(result); 78 | if (result) { 79 | QCOMPARE(job->mailBox(), mailbox); 80 | } 81 | 82 | fakeServer.quit(); 83 | } 84 | }; 85 | 86 | QTEST_GUILESS_MAIN(DeleteJobTest) 87 | 88 | #include "deletejobtest.moc" 89 | -------------------------------------------------------------------------------- /autotests/enablejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include "kimap/enablejob.h" 10 | #include "kimap/session.h" 11 | #include "kimaptest/fakeserver.h" 12 | 13 | #include 14 | 15 | Q_DECLARE_METATYPE(QList>) 16 | 17 | class EnableJobTest : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | private Q_SLOTS: 22 | 23 | void testEnable_data() 24 | { 25 | QTest::addColumn>("scenario"); 26 | QTest::addColumn("reqCapabilities"); 27 | QTest::addColumn("supportedCaps"); 28 | 29 | QList scenario; 30 | scenario << FakeServer::preauth() << "C: A000001 ENABLE CONDSTORE X-GOOD-IDEA" 31 | << "S: * ENABLED X-GOOD-IDEA" 32 | << "S: A000001 OK Enabled"; 33 | QStringList reqCapabilities = {QStringLiteral("CONDSTORE"), QStringLiteral("X-GOOD-IDEA")}; 34 | QStringList supportedCaps = {QStringLiteral("X-GOOD-IDEA")}; 35 | QTest::newRow("one feature") << scenario << reqCapabilities << supportedCaps; 36 | 37 | scenario.clear(); 38 | scenario << FakeServer::preauth() << "C: A000001 ENABLE FEATURE1 FEATURE2" 39 | << "S: * ENABLED FEATURE1 FEATURE2" 40 | << "S: A000001 OK Enabled"; 41 | reqCapabilities = QStringList{QStringLiteral("FEATURE1"), QStringLiteral("FEATURE2")}; 42 | supportedCaps = QStringList{QStringLiteral("FEATURE1"), QStringLiteral("FEATURE2")}; 43 | QTest::newRow("both features") << scenario << reqCapabilities << supportedCaps; 44 | } 45 | 46 | void testEnable() 47 | { 48 | QFETCH(QList, scenario); 49 | QFETCH(QStringList, reqCapabilities); 50 | QFETCH(QStringList, supportedCaps); 51 | 52 | FakeServer fakeServer; 53 | fakeServer.setScenario(scenario); 54 | fakeServer.startAndWait(); 55 | 56 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 57 | 58 | auto job = new KIMAP::EnableJob(&session); 59 | job->setCapabilities(reqCapabilities); 60 | QVERIFY(job->exec()); 61 | 62 | QCOMPARE(job->enabledCapabilities(), supportedCaps); 63 | 64 | fakeServer.quit(); 65 | } 66 | }; 67 | 68 | QTEST_GUILESS_MAIN(EnableJobTest) 69 | 70 | #include "enablejobtest.moc" 71 | -------------------------------------------------------------------------------- /autotests/expungejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include "imapset.h" 10 | #include "kimap/expungejob.h" 11 | #include "kimap/session.h" 12 | #include "kimaptest/fakeserver.h" 13 | 14 | #include 15 | 16 | class ExpungeJobTest : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | private Q_SLOTS: 21 | 22 | void testDelete_data() 23 | { 24 | QTest::addColumn>("scenario"); 25 | QTest::addColumn("vanishedSet"); 26 | QTest::addColumn("highestModSeq"); 27 | 28 | QList scenario; 29 | scenario << FakeServer::preauth() << "C: A000001 EXPUNGE" 30 | << "S: * 1 EXPUNGE" 31 | << "S: * 2 EXPUNGE" 32 | << "S: * 3 EXPUNGE" 33 | << "S: A000001 OK EXPUNGE completed"; 34 | QTest::newRow("good") << scenario << KIMAP::ImapSet{} << 0ULL; 35 | 36 | scenario.clear(); 37 | scenario << FakeServer::preauth() << "C: A000001 EXPUNGE" 38 | << "S: * 1" // missing EXPUNGE word 39 | << "S: A000001 OK EXPUNGE completed"; 40 | QTest::newRow("non-standard response") << scenario << KIMAP::ImapSet{} << 0ULL; 41 | 42 | scenario.clear(); 43 | scenario << FakeServer::preauth() << "C: A000001 EXPUNGE" 44 | << "S: A000001 BAD command unknown or arguments invalid"; 45 | QTest::newRow("bad") << scenario << KIMAP::ImapSet{} << 0ULL; 46 | 47 | scenario.clear(); 48 | scenario << FakeServer::preauth() << "C: A000001 EXPUNGE" 49 | << "S: A000001 NO access denied"; 50 | QTest::newRow("no") << scenario << KIMAP::ImapSet{} << 0ULL; 51 | 52 | scenario.clear(); 53 | scenario << FakeServer::preauth() << "C: A000001 EXPUNGE" 54 | << "S: * VANISHED 405,407,410:420" 55 | << "S: A000001 OK [HIGHESTMODSEQ 123456789] Expunged."; 56 | KIMAP::ImapSet vanishedSet; 57 | vanishedSet.add(QList{405, 407}); 58 | vanishedSet.add(KIMAP::ImapInterval{410, 420}); 59 | QTest::newRow("qresync") << scenario << vanishedSet << 123456789ULL; 60 | } 61 | 62 | void testDelete() 63 | { 64 | QFETCH(QList, scenario); 65 | QFETCH(KIMAP::ImapSet, vanishedSet); 66 | QFETCH(quint64, highestModSeq); 67 | 68 | FakeServer fakeServer; 69 | fakeServer.setScenario(scenario); 70 | fakeServer.startAndWait(); 71 | 72 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 73 | 74 | auto job = new KIMAP::ExpungeJob(&session); 75 | bool result = job->exec(); 76 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 77 | QEXPECT_FAIL("no", "Expected failure on NO response", Continue); 78 | QVERIFY(result); 79 | if (result) { 80 | QCOMPARE(job->vanishedMessages(), vanishedSet); 81 | QCOMPARE(job->newHighestModSeq(), highestModSeq); 82 | } 83 | 84 | fakeServer.quit(); 85 | } 86 | }; 87 | 88 | QTEST_GUILESS_MAIN(ExpungeJobTest) 89 | 90 | #include "expungejobtest.moc" 91 | -------------------------------------------------------------------------------- /autotests/fakeserverscenario.log: -------------------------------------------------------------------------------- 1 | C: A000001 LIST "" * 2 | S: * LIST ( \HasChildren ) / INBOX 3 | S: * LIST ( \HasNoChildren ) / INBOX/&AOQ- &APY- &APw- @ &IKw- 4 | S: * LIST ( \HasChildren ) / INBOX/lost+found 5 | S: * LIST ( \HasNoChildren ) / "INBOX/lost+found/Calendar Public-20080128" 6 | S: A000001 OK LIST completed 7 | -------------------------------------------------------------------------------- /autotests/fakeservertest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 3 | SPDX-FileContributor: Kevin Ottens 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #include 9 | 10 | #include "kimap/listjob.h" 11 | #include "kimap/session.h" 12 | #include "kimaptest/fakeserver.h" 13 | 14 | #include 15 | 16 | class FakeServerTest : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | private Q_SLOTS: 21 | 22 | void testLoadScenario() 23 | { 24 | KIMAP::MailBoxDescriptor descriptor; 25 | QList listresult; 26 | 27 | descriptor.separator = QLatin1Char('/'); 28 | descriptor.name = QStringLiteral("INBOX"); 29 | listresult << descriptor; 30 | descriptor.separator = QLatin1Char('/'); 31 | descriptor.name = QString::fromUtf8("INBOX/ä ö ü @ €"); 32 | listresult << descriptor; 33 | descriptor.separator = QLatin1Char('/'); 34 | descriptor.name = QStringLiteral("INBOX/lost+found"); 35 | listresult << descriptor; 36 | descriptor.separator = QLatin1Char('/'); 37 | descriptor.name = QStringLiteral("INBOX/lost+found/Calendar Public-20080128"); 38 | listresult << descriptor; 39 | 40 | FakeServer fakeServer; 41 | fakeServer.addScenarioFromFile(QStringLiteral(TEST_DATA) + QStringLiteral("/fakeserverscenario.log")); 42 | fakeServer.startAndWait(); 43 | 44 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 45 | 46 | auto job = new KIMAP::ListJob(&session); 47 | job->setOption(KIMAP::ListJob::IncludeUnsubscribed); 48 | QVERIFY(job->exec()); 49 | 50 | fakeServer.quit(); 51 | } 52 | }; 53 | 54 | QTEST_GUILESS_MAIN(FakeServerTest) 55 | 56 | #include "fakeservertest.moc" 57 | -------------------------------------------------------------------------------- /autotests/idjobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2015 Christian Mollekopf 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "kimap/idjob.h" 8 | #include "kimap/session.h" 9 | #include "kimaptest/fakeserver.h" 10 | 11 | #include 12 | 13 | using ArrayMap = QMap; 14 | Q_DECLARE_METATYPE(ArrayMap) 15 | 16 | class IdJobTest : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | private Q_SLOTS: 21 | 22 | void testId_data() 23 | { 24 | QTest::addColumn>("scenario"); 25 | QTest::addColumn("values"); 26 | QList scenario; 27 | scenario << "S: * PREAUTH" 28 | << R"(C: A000001 ID ("name" "clientid"))" 29 | << "S: * ID NIL" 30 | << "S: A000001 OK ID completed"; 31 | 32 | ArrayMap values; 33 | values.insert("name", "clientid"); 34 | QTest::newRow("good") << scenario << values; 35 | } 36 | 37 | void testId() 38 | { 39 | QFETCH(QList, scenario); 40 | QFETCH(ArrayMap, values); 41 | 42 | FakeServer fakeServer; 43 | fakeServer.setScenario(scenario); 44 | fakeServer.startAndWait(); 45 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 46 | 47 | auto job = new KIMAP::IdJob(&session); 48 | const auto keys = values.keys(); 49 | for (const QByteArray &key : keys) { 50 | job->setField(key, values.value(key)); 51 | } 52 | bool result = job->exec(); 53 | QVERIFY(result); 54 | fakeServer.quit(); 55 | } 56 | }; 57 | 58 | QTEST_GUILESS_MAIN(IdJobTest) 59 | 60 | #include "idjobtest.moc" 61 | -------------------------------------------------------------------------------- /autotests/kimaptest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: none 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | kde_enable_exceptions() 5 | 6 | set(kimaptest_SRCS 7 | fakeserver.cpp 8 | mockjob.cpp 9 | sslserver.cpp 10 | ) 11 | 12 | add_library(kimaptest6 STATIC ${kimaptest_SRCS}) 13 | if(COMPILE_WITH_UNITY_CMAKE_SUPPORT) 14 | set_target_properties(kimaptest6 PROPERTIES UNITY_BUILD ON) 15 | endif() 16 | generate_export_header(kimaptest6) 17 | add_library(KPim6::kimaptest ALIAS kimaptest6) 18 | target_include_directories(KPim6IMAP INTERFACE "$") 19 | target_link_libraries(kimaptest6 KPim6IMAP Qt::Test Qt::Network Qt::Core KF6::CoreAddons KF6::KIOCore KF6::I18n) 20 | 21 | install(TARGETS kimaptest6 EXPORT KPim6IMAPTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) 22 | 23 | ########### install files ############### 24 | 25 | install(FILES 26 | fakeserver.h 27 | mockjob.h 28 | DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KPim6/KIMAPTest/kimaptest COMPONENT Devel) 29 | -------------------------------------------------------------------------------- /autotests/kimaptest/mockjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | SPDX-FileCopyrightText: 2008 Kevin Ottens 4 | 5 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 6 | SPDX-FileContributor: Kevin Ottens 7 | 8 | SPDX-License-Identifier: LGPL-2.0-or-later 9 | */ 10 | 11 | #include "mockjob.h" 12 | 13 | #include "job_p.h" 14 | #include "session.h" 15 | #include "session_p.h" 16 | #include 17 | #include 18 | 19 | class MockJobPrivate : public KIMAP::JobPrivate 20 | { 21 | public: 22 | MockJobPrivate(KIMAP::Session *session, const QString &name) 23 | : KIMAP::JobPrivate(session, name) 24 | , timeout(10) 25 | { 26 | } 27 | 28 | ~MockJobPrivate() 29 | { 30 | } 31 | 32 | QByteArray command; 33 | int timeout; 34 | }; 35 | 36 | MockJob::MockJob(KIMAP::Session *session) 37 | : KIMAP::Job(*new MockJobPrivate(session, i18n("Mock"))) 38 | { 39 | } 40 | 41 | void MockJob::doStart() 42 | { 43 | Q_D(MockJob); 44 | if (isNull()) { 45 | QTimer::singleShot(d->timeout, this, SLOT(done())); 46 | } else { 47 | d->sessionInternal()->setSocketTimeout(d->timeout); 48 | d->tags << d->sessionInternal()->sendCommand(d->command); 49 | } 50 | } 51 | 52 | void MockJob::done() 53 | { 54 | emitResult(); 55 | } 56 | 57 | void MockJob::setCommand(const QByteArray &command) 58 | { 59 | Q_D(MockJob); 60 | d->command = command; 61 | } 62 | 63 | QByteArray MockJob::command() const 64 | { 65 | Q_D(const MockJob); 66 | return d->command; 67 | } 68 | 69 | void MockJob::setTimeout(int timeout) 70 | { 71 | Q_D(MockJob); 72 | d->timeout = timeout; 73 | } 74 | 75 | int MockJob::timeout() const 76 | { 77 | Q_D(const MockJob); 78 | return d->timeout; 79 | } 80 | 81 | bool MockJob::isNull() const 82 | { 83 | Q_D(const MockJob); 84 | return d->command.isEmpty(); 85 | } 86 | 87 | #include "moc_mockjob.cpp" 88 | -------------------------------------------------------------------------------- /autotests/kimaptest/mockjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | SPDX-FileCopyrightText: 2008 Kevin Ottens 4 | 5 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 6 | SPDX-FileContributor: Kevin Ottens 7 | 8 | SPDX-License-Identifier: LGPL-2.0-or-later 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "kimap/job.h" 14 | 15 | class MockJobPrivate; 16 | 17 | /** 18 | * Provides an easy way to send an arbitrary IMAP client command. 19 | */ 20 | class MockJob : public KIMAP::Job 21 | { 22 | Q_OBJECT 23 | Q_DECLARE_PRIVATE(MockJob) 24 | 25 | public: 26 | MockJob(KIMAP::Session *session); 27 | 28 | /** 29 | * Sets the command to execute. 30 | * 31 | * This should not include the command tag. 32 | */ 33 | void setCommand(const QByteArray &command); 34 | /** 35 | * The command that will be sent. 36 | */ 37 | QByteArray command() const; 38 | /** 39 | * Sets the timeout before the job completes. 40 | */ 41 | void setTimeout(int timeout); 42 | /** 43 | * The timeout used by the job. 44 | */ 45 | int timeout() const; 46 | /** 47 | * Whether the command is empty. 48 | * 49 | * Equivalent to command().isEmpty(). 50 | * 51 | * @return @c true if no command is set, @c false otherwise 52 | */ 53 | bool isNull() const; 54 | 55 | /** 56 | * Starts the job. 57 | * 58 | * Do not call this directly. Use start() instead. 59 | * 60 | * @reimp 61 | */ 62 | void doStart() override; 63 | 64 | private Q_SLOTS: 65 | void done(); 66 | }; 67 | -------------------------------------------------------------------------------- /autotests/kimaptest/sslserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2013 Christian Mollekopf 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | class SslServer : public QTcpServer 13 | { 14 | Q_OBJECT 15 | public: 16 | SslServer(QSsl::SslProtocol, bool waitForStartTls); 17 | void incomingConnection(qintptr handle) override; 18 | 19 | private Q_SLOTS: 20 | void sslErrors(const QList &errors); 21 | void error(QAbstractSocket::SocketError); 22 | 23 | private: 24 | QSsl::SslProtocol mProtocol; 25 | QSslSocket mSocket; 26 | bool mWaitForStartTls = false; 27 | }; 28 | -------------------------------------------------------------------------------- /autotests/logoutjobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/loginjob.h" 13 | #include "kimap/logoutjob.h" 14 | #include "kimap/session.h" 15 | #include "kimaptest/fakeserver.h" 16 | 17 | #include 18 | 19 | class LogoutJobTest : public QObject 20 | { 21 | Q_OBJECT 22 | 23 | private Q_SLOTS: 24 | 25 | void testLogout() 26 | { 27 | FakeServer fakeServer; 28 | fakeServer.setScenario(QList() << FakeServer::preauth() << "C: A000001 LOGOUT" 29 | << "S: A000001 OK LOGOUT completed"); 30 | fakeServer.startAndWait(); 31 | 32 | auto session = new KIMAP::Session(QStringLiteral("127.0.0.1"), 5989); 33 | 34 | auto logout = new KIMAP::LogoutJob(session); 35 | QVERIFY(logout->exec()); 36 | 37 | fakeServer.quit(); 38 | delete session; 39 | } 40 | 41 | void testLogoutUntagged() 42 | { 43 | FakeServer fakeServer; 44 | fakeServer.setScenario(QList() << FakeServer::preauth() << "C: A000001 LOGOUT" 45 | << "S: * some untagged response" 46 | << "S: A000001 OK LOGOUT completed"); 47 | fakeServer.startAndWait(); 48 | 49 | auto session = new KIMAP::Session(QStringLiteral("127.0.0.1"), 5989); 50 | 51 | auto logout = new KIMAP::LogoutJob(session); 52 | QVERIFY(logout->exec()); 53 | 54 | fakeServer.quit(); 55 | delete session; 56 | } 57 | }; 58 | 59 | QTEST_GUILESS_MAIN(LogoutJobTest) 60 | 61 | #include "logoutjobtest.moc" 62 | -------------------------------------------------------------------------------- /autotests/movejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include "../src/movejob.h" 10 | #include "kimap/imapset.h" 11 | #include "kimap/session.h" 12 | #include "kimaptest/fakeserver.h" 13 | 14 | #include 15 | 16 | class MoveJobTest : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | private Q_SLOTS: 21 | 22 | void testMove_data() 23 | { 24 | QTest::addColumn("uidBased"); 25 | QTest::addColumn("id"); 26 | QTest::addColumn("resultUid"); 27 | QTest::addColumn("mailbox"); 28 | QTest::addColumn>("scenario"); 29 | 30 | QList scenario; 31 | scenario << FakeServer::preauth() << "C: A000001 MOVE 3 \"foo\"" 32 | << "S: * OK [COPYUID 12345 3 7]" 33 | << "S: A000001 OK MOVE completed"; 34 | 35 | QTest::newRow("not uid based") << false << qint64(3) << qint64(7) << QStringLiteral("foo") << scenario; 36 | 37 | scenario.clear(); 38 | scenario << FakeServer::preauth() << "C: A000001 UID MOVE 1024 \"bar\"" 39 | << "S: * OK [COPYUID 12346 4 2048]" 40 | << "S: A000001 OK MOVE completed"; 41 | 42 | QTest::newRow("uid based") << true << qint64(1024) << qint64(2048) << QStringLiteral("bar") << scenario; 43 | } 44 | 45 | void testMove() 46 | { 47 | QFETCH(bool, uidBased); 48 | QFETCH(qint64, id); 49 | QFETCH(qint64, resultUid); 50 | QFETCH(QString, mailbox); 51 | QFETCH(QList, scenario); 52 | 53 | FakeServer fakeServer; 54 | fakeServer.setScenario(scenario); 55 | fakeServer.startAndWait(); 56 | 57 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 58 | 59 | auto job = new KIMAP::MoveJob(&session); 60 | job->setMailBox(mailbox); 61 | job->setUidBased(uidBased); 62 | job->setSequenceSet(KIMAP::ImapSet(id)); 63 | bool result = job->exec(); 64 | QVERIFY(result); 65 | QCOMPARE(job->resultingUids(), KIMAP::ImapSet(resultUid)); 66 | 67 | fakeServer.quit(); 68 | } 69 | }; 70 | 71 | QTEST_GUILESS_MAIN(MoveJobTest) 72 | 73 | #include "movejobtest.moc" 74 | -------------------------------------------------------------------------------- /autotests/renamejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/renamejob.h" 13 | #include "kimap/session.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class RenameJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testRename_data() 25 | { 26 | QTest::addColumn("mailbox"); 27 | QTest::addColumn("newname"); 28 | QTest::addColumn>("scenario"); 29 | 30 | QList scenario; 31 | scenario << FakeServer::preauth() << R"(C: A000001 RENAME "INBOX" "oldmail")" 32 | << "S: A000001 OK RENAME completed"; 33 | QTest::newRow("good") << "INBOX" 34 | << "oldmail" << scenario; 35 | 36 | scenario.clear(); 37 | scenario << FakeServer::preauth() << R"(C: A000001 RENAME "INBOX-FAIL-BAD" "oldmail-bad")" 38 | << "S: A000001 BAD command unknown or arguments invalid"; 39 | QTest::newRow("bad") << "INBOX-FAIL-BAD" 40 | << "oldmail-bad" << scenario; 41 | 42 | scenario.clear(); 43 | scenario << FakeServer::preauth() << R"(C: A000001 RENAME "INBOX-FAIL-NO" "oldmail-no")" 44 | << "S: A000001 NO rename failure"; 45 | QTest::newRow("no") << "INBOX-FAIL-NO" 46 | << "oldmail-no" << scenario; 47 | } 48 | 49 | void testRename() 50 | { 51 | QFETCH(QString, mailbox); 52 | QFETCH(QString, newname); 53 | QFETCH(QList, scenario); 54 | 55 | FakeServer fakeServer; 56 | fakeServer.setScenario(scenario); 57 | fakeServer.startAndWait(); 58 | 59 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 60 | 61 | auto job = new KIMAP::RenameJob(&session); 62 | job->setSourceMailBox(mailbox); 63 | job->setDestinationMailBox(newname); 64 | bool result = job->exec(); 65 | QEXPECT_FAIL("bad", "Expected failure on BAD response", Continue); 66 | QEXPECT_FAIL("no", "Expected failure on NO response", Continue); 67 | QVERIFY(result); 68 | QCOMPARE(job->sourceMailBox(), mailbox); 69 | QCOMPARE(job->destinationMailBox(), newname); 70 | 71 | fakeServer.quit(); 72 | } 73 | }; 74 | 75 | QTEST_GUILESS_MAIN(RenameJobTest) 76 | 77 | #include "renamejobtest.moc" 78 | -------------------------------------------------------------------------------- /autotests/storejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/session.h" 13 | #include "kimap/storejob.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class StoreJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testStore_data() 25 | { 26 | QTest::addColumn("uidBased"); 27 | QTest::addColumn("id"); 28 | QTest::addColumn("uid"); 29 | QTest::addColumn>("flags"); 30 | QTest::addColumn>("scenario"); 31 | 32 | QList scenario; 33 | scenario << FakeServer::preauth() << "C: A000001 STORE 3 FLAGS (\\Seen \\Foo)" 34 | << "S: * 3 FETCH (FLAGS (\\Seen \\Foo) UID 1096)" 35 | << "S: A000001 OK STORE completed"; 36 | 37 | QTest::newRow("not uid based") << false << qint64(3) << qint64(1096) 38 | << (QList() << "\\Seen" 39 | << "\\Foo") 40 | << scenario; 41 | 42 | scenario.clear(); 43 | scenario << FakeServer::preauth() << "C: A000001 UID STORE 1096 FLAGS (\\Seen \\Foo)" 44 | << "S: * 3 FETCH (FLAGS (\\Seen \\Foo) UID 1096)" 45 | << "S: A000001 OK STORE completed"; 46 | 47 | QTest::newRow("uid based") << true << qint64(3) << qint64(1096) 48 | << (QList() << "\\Seen" 49 | << "\\Foo") 50 | << scenario; 51 | } 52 | 53 | void testStore() 54 | { 55 | QFETCH(bool, uidBased); 56 | QFETCH(qint64, id); 57 | QFETCH(qint64, uid); 58 | QFETCH(QList, flags); 59 | QFETCH(QList, scenario); 60 | 61 | FakeServer fakeServer; 62 | fakeServer.setScenario(scenario); 63 | fakeServer.startAndWait(); 64 | 65 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 66 | 67 | auto job = new KIMAP::StoreJob(&session); 68 | job->setUidBased(uidBased); 69 | job->setSequenceSet(KIMAP::ImapSet(uidBased ? uid : id)); 70 | job->setFlags(flags); 71 | job->setMode(KIMAP::StoreJob::SetFlags); 72 | bool result = job->exec(); 73 | QVERIFY(result); 74 | if (uidBased) { 75 | QVERIFY(job->resultingFlags().contains(uid)); 76 | } else { 77 | QVERIFY(job->resultingFlags().contains(id)); 78 | } 79 | 80 | fakeServer.quit(); 81 | } 82 | }; 83 | 84 | QTEST_GUILESS_MAIN(StoreJobTest) 85 | 86 | #include "storejobtest.moc" 87 | -------------------------------------------------------------------------------- /autotests/subscribejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/session.h" 13 | #include "kimap/subscribejob.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class SubscribeJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testSubscribe_data() 25 | { 26 | QTest::addColumn("mailbox"); 27 | QTest::addColumn>("scenario"); 28 | 29 | QList scenario; 30 | scenario << FakeServer::preauth() << "C: A000001 SUBSCRIBE \"INBOX/foo\"" 31 | << "S: A000001 OK CREATE completed"; 32 | QTest::newRow("good") << "INBOX/foo" << scenario; 33 | 34 | scenario.clear(); 35 | scenario << FakeServer::preauth() << "C: A000001 SUBSCRIBE \"INBOX-FAIL-BAD\"" 36 | << "S: A000001 BAD command unknown or arguments invalid"; 37 | QTest::newRow("bad") << "INBOX-FAIL-BAD" << scenario; 38 | 39 | scenario.clear(); 40 | scenario << FakeServer::preauth() << "C: A000001 SUBSCRIBE \"INBOX-FAIL-NO\"" 41 | << "S: A000001 NO subscribe failure"; 42 | QTest::newRow("no") << "INBOX-FAIL-NO" << scenario; 43 | } 44 | 45 | void testSubscribe() 46 | { 47 | QFETCH(QString, mailbox); 48 | QFETCH(QList, scenario); 49 | 50 | FakeServer fakeServer; 51 | fakeServer.setScenario(scenario); 52 | fakeServer.startAndWait(); 53 | 54 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 55 | 56 | auto job = new KIMAP::SubscribeJob(&session); 57 | job->setMailBox(mailbox); 58 | bool result = job->exec(); 59 | QEXPECT_FAIL("bad", "Expected failure on BAD scenario", Continue); 60 | QEXPECT_FAIL("no", "Expected failure on NO scenario", Continue); 61 | QVERIFY(result); 62 | QCOMPARE(job->mailBox(), mailbox); 63 | 64 | fakeServer.quit(); 65 | } 66 | }; 67 | 68 | QTEST_GUILESS_MAIN(SubscribeJobTest) 69 | 70 | #include "subscribejobtest.moc" 71 | -------------------------------------------------------------------------------- /autotests/testrfccodecs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the kimap library. 3 | SPDX-FileCopyrightText: 2007 Tom Albers 4 | SPDX-FileCopyrightText: 2007 Allen Winter 5 | 6 | SPDX-License-Identifier: LGPL-2.0-only 7 | */ 8 | #include 9 | 10 | #include "testrfccodecs.h" 11 | 12 | QTEST_GUILESS_MAIN(RFCCodecsTest) 13 | 14 | #include "rfccodecs.h" 15 | using namespace KIMAP; 16 | 17 | void RFCCodecsTest::testIMAPEncoding() 18 | { 19 | QString encoded; 20 | QString decoded; 21 | QByteArray bEncoded; 22 | QByteArray bDecoded; 23 | 24 | encoded = encodeImapFolderName(QString::fromUtf8("Test.Frode Rønning")); 25 | QCOMPARE(encoded, QString::fromUtf8("Test.Frode R&APg-nning")); 26 | bEncoded = encodeImapFolderName(QString::fromUtf8("Test.Frode Rønning").toUtf8()); 27 | QCOMPARE(bEncoded, QString::fromUtf8("Test.Frode R&APg-nning").toUtf8()); 28 | 29 | decoded = decodeImapFolderName(QString::fromLatin1("Test.Frode R&APg-nning")); 30 | QCOMPARE(decoded, QString::fromUtf8("Test.Frode Rønning")); 31 | bDecoded = decodeImapFolderName(QString::fromUtf8("Test.Frode Rønning").toUtf8()); 32 | QCOMPARE(bDecoded, QString::fromUtf8("Test.Frode Rønning").toUtf8()); 33 | 34 | encoded = encodeImapFolderName(QString::fromUtf8("Test.tom & jerry")); 35 | QCOMPARE(encoded, QString::fromUtf8("Test.tom &- jerry")); 36 | bEncoded = encodeImapFolderName(QString::fromUtf8("Test.tom & jerry").toUtf8()); 37 | QCOMPARE(bEncoded, QString::fromUtf8("Test.tom &- jerry").toUtf8()); 38 | 39 | decoded = decodeImapFolderName(QString::fromUtf8("Test.tom &- jerry")); 40 | QCOMPARE(decoded, QString::fromUtf8("Test.tom & jerry")); 41 | bDecoded = decodeImapFolderName(QString::fromUtf8("Test.tom &- jerry").toUtf8()); 42 | QCOMPARE(bDecoded, QString::fromUtf8("Test.tom & jerry").toUtf8()); 43 | 44 | // Try to feed already encoded 45 | encoded = encodeImapFolderName(QString::fromUtf8("Test.Cl&AOE-udio")); 46 | QCOMPARE(encoded, QString::fromUtf8("Test.Cl&-AOE-udio")); 47 | bEncoded = encodeImapFolderName(QString::fromUtf8("Test.Cl&AOE-udio").toUtf8()); 48 | QCOMPARE(bEncoded, QString::fromUtf8("Test.Cl&-AOE-udio").toUtf8()); 49 | 50 | decoded = decodeImapFolderName(QString::fromUtf8("Test.Cl&-AOE-udio")); 51 | QCOMPARE(decoded, QString::fromUtf8("Test.Cl&AOE-udio")); 52 | bDecoded = decodeImapFolderName(QString::fromUtf8("Test.Cl&-AOE-udio").toUtf8()); 53 | QCOMPARE(bDecoded, QString::fromUtf8("Test.Cl&AOE-udio").toUtf8()); 54 | 55 | // With UTF8 characters 56 | bEncoded = "INBOX/&AOQ- &APY- &APw- @ &IKw-"; 57 | QCOMPARE(decodeImapFolderName(bEncoded), QByteArray("INBOX/ä ö ü @ €")); 58 | } 59 | 60 | void RFCCodecsTest::testQuotes() 61 | { 62 | QString test(QStringLiteral("tom\"allen")); 63 | QCOMPARE(quoteIMAP(test), QString::fromLatin1("tom\\\"allen")); 64 | test = QStringLiteral("tom\'allen"); 65 | QCOMPARE(quoteIMAP(test), QString::fromLatin1("tom\'allen")); 66 | test = QStringLiteral("tom\\allen"); 67 | QCOMPARE(quoteIMAP(test), QString::fromLatin1("tom\\\\allen")); 68 | } 69 | 70 | #include "moc_testrfccodecs.cpp" 71 | -------------------------------------------------------------------------------- /autotests/testrfccodecs.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the kimap library. 3 | 4 | SPDX-FileCopyrightText: 2007 Allen Winter 5 | 6 | SPDX-License-Identifier: LGPL-2.0-or-later 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | class RFCCodecsTest : public QObject 14 | { 15 | Q_OBJECT 16 | private Q_SLOTS: 17 | void testIMAPEncoding(); 18 | void testQuotes(); 19 | }; 20 | -------------------------------------------------------------------------------- /autotests/unsubscribejobtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 5 | SPDX-FileContributor: Kevin Ottens 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include 11 | 12 | #include "kimap/session.h" 13 | #include "kimap/unsubscribejob.h" 14 | #include "kimaptest/fakeserver.h" 15 | 16 | #include 17 | 18 | class UnsubscribeJobTest : public QObject 19 | { 20 | Q_OBJECT 21 | 22 | private Q_SLOTS: 23 | 24 | void testUnsubscribe_data() 25 | { 26 | QTest::addColumn("mailbox"); 27 | QTest::addColumn>("scenario"); 28 | 29 | QList scenario; 30 | scenario << FakeServer::preauth() << "C: A000001 UNSUBSCRIBE \"#news.comp.mail.mime\"" 31 | << "S: A000001 OK UNSUBSCRIBE completed"; 32 | QTest::newRow("good") << "#news.comp.mail.mime" << scenario; 33 | 34 | scenario.clear(); 35 | scenario << FakeServer::preauth() << "C: A000001 UNSUBSCRIBE \"INBOX-FAIL-BAD\"" 36 | << "S: A000001 BAD command unknown or arguments invalid"; 37 | QTest::newRow("bad") << "INBOX-FAIL-BAD" << scenario; 38 | 39 | scenario.clear(); 40 | scenario << FakeServer::preauth() << "C: A000001 UNSUBSCRIBE \"INBOX-FAIL-NO\"" 41 | << "S: A000001 NO unsubscribe failure"; 42 | QTest::newRow("no") << "INBOX-FAIL-NO" << scenario; 43 | } 44 | 45 | void testUnsubscribe() 46 | { 47 | QFETCH(QString, mailbox); 48 | QFETCH(QList, scenario); 49 | 50 | FakeServer fakeServer; 51 | fakeServer.setScenario(scenario); 52 | fakeServer.startAndWait(); 53 | 54 | KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 55 | 56 | auto job = new KIMAP::UnsubscribeJob(&session); 57 | job->setMailBox(mailbox); 58 | bool result = job->exec(); 59 | QEXPECT_FAIL("bad", "Expected failure on BAD scenario", Continue); 60 | QEXPECT_FAIL("no", "Expected failure on NO scenario", Continue); 61 | QVERIFY(result); 62 | QCOMPARE(job->mailBox(), mailbox); 63 | 64 | fakeServer.quit(); 65 | } 66 | }; 67 | 68 | QTEST_GUILESS_MAIN(UnsubscribeJobTest) 69 | 70 | #include "unsubscribejobtest.moc" 71 | -------------------------------------------------------------------------------- /metainfo.yaml: -------------------------------------------------------------------------------- 1 | fancyname: KIMAP 2 | maintainer: dvratil 3 | description: A job-based API for interacting with IMAP servers 4 | tier: 3 5 | type: functional 6 | platforms: 7 | - name: Linux 8 | - name: FreeBSD 9 | - name: Windows 10 | - name: macOS 11 | portingAid: false 12 | deprecated: false 13 | release: false 14 | libraries: 15 | - cmake: "KPim6::Imap" 16 | cmakename: KPim6Imap 17 | 18 | public_lib: true 19 | group: kdepim 20 | -------------------------------------------------------------------------------- /metainfo.yaml.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: none 2 | SPDX-License-Identifier: CC0-1.0 3 | -------------------------------------------------------------------------------- /readme-build-ftime.txt: -------------------------------------------------------------------------------- 1 | # Analyzing Build Performance 2 | 3 | For debug build time: 4 | We need ClangBuildAnalyzer 5 | ` 6 | git clone https://github.com/aras-p/ClangBuildAnalyzer 7 | mkdir build 8 | cd build 9 | cmake -DCMAKE_INSTALL_PREFIX= ../ 10 | make install 11 | ` 12 | 13 | ## Command line 14 | 15 | cmake -preset ftime-trace 16 | 17 | ClangBuildAnalyzer --start $PWD/build-ftime-trace 18 | cmake --build --preset ftime-trace 19 | 20 | ClangBuildAnalyzer --stop $PWD/build-ftime-trace build-ftime.txt 21 | 22 | ClangBuildAnalyzer --analyze build-ftime.txt > analyze-build-ftime.txt 23 | 24 | 25 | see https://aras-p.info/blog/2019/09/28/Clang-Build-Analyzer/ 26 | 27 | -------------------------------------------------------------------------------- /sanitizers.supp: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021-2025 Laurent Montel 2 | # SPDX-License-Identifier: CC0-1.0 3 | # Suppression file for ASAN/LSAN 4 | 5 | leak:libspeechd 6 | leak:getdelim 7 | leak:g_malloc 8 | leak:libfontconfig 9 | leak:libdbus 10 | leak:QEasingCurve:: 11 | leak:QtSharedPointer::ExternalRefCountData::getAndRef 12 | leak:QArrayData::allocate 13 | leak:QObject::QObject 14 | leak:QObjectPrivate::addConnection 15 | leak:QObjectPrivate::connectImpl 16 | leak:QPropertyAnimation::QPropertyAnimation 17 | -------------------------------------------------------------------------------- /src/Messages.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # SPDX-FileCopyrightText: none 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | $XGETTEXT `find . -name "*.cpp" -o -name "*.h"` -o $podir/libkimap6.pot 5 | -------------------------------------------------------------------------------- /src/acl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "acl.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace KIMAP 13 | { 14 | namespace Acl 15 | { 16 | class RightsMap 17 | { 18 | public: 19 | RightsMap() 20 | { 21 | map['l'] = Lookup; 22 | map['r'] = Read; 23 | map['s'] = KeepSeen; 24 | map['w'] = Write; 25 | map['i'] = Insert; 26 | map['p'] = Post; 27 | map['c'] = Create; // TODO: obsolete, keep it? 28 | map['d'] = Delete; // TODO: obsolete, keep it? 29 | map['k'] = CreateMailbox; 30 | map['x'] = DeleteMailbox; 31 | map['t'] = DeleteMessage; 32 | map['e'] = Expunge; 33 | map['a'] = Admin; 34 | map['n'] = WriteShared; 35 | map['0'] = Custom0; 36 | map['1'] = Custom1; 37 | map['2'] = Custom2; 38 | map['3'] = Custom3; 39 | map['4'] = Custom4; 40 | map['5'] = Custom5; 41 | map['6'] = Custom6; 42 | map['7'] = Custom7; 43 | map['8'] = Custom8; 44 | map['9'] = Custom9; 45 | } 46 | 47 | QMap map; 48 | }; 49 | 50 | Q_GLOBAL_STATIC(RightsMap, globalRights) 51 | 52 | } 53 | } 54 | 55 | KIMAP::Acl::Rights KIMAP::Acl::rightsFromString(const QByteArray &string) 56 | { 57 | Rights result; 58 | 59 | if (string.isEmpty()) { 60 | return result; 61 | } 62 | 63 | int pos = 0; 64 | if (string[0] == '+' || string[0] == '-') { // Skip modifier if any 65 | pos++; 66 | } 67 | 68 | for (int i = pos; i < string.size(); i++) { 69 | if (globalRights->map.contains(string[i])) { 70 | result |= globalRights->map[string[i]]; 71 | } 72 | } 73 | 74 | return result; 75 | } 76 | 77 | QByteArray KIMAP::Acl::rightsToString(Rights rights) 78 | { 79 | QByteArray result; 80 | 81 | for (int right = Lookup; right <= Custom9; right <<= 1) { 82 | if (rights & right) { 83 | result += globalRights->map.key(static_cast(right)); 84 | } 85 | } 86 | 87 | return result; 88 | } 89 | 90 | KIMAP::Acl::Rights KIMAP::Acl::normalizedRights(KIMAP::Acl::Rights rights) 91 | { 92 | Rights normalized = rights; 93 | if (normalized & Create) { 94 | normalized |= (CreateMailbox | DeleteMailbox); 95 | normalized &= ~Create; 96 | } 97 | if (normalized & Delete) { 98 | normalized |= (DeleteMessage | Expunge); 99 | normalized &= ~Delete; 100 | } 101 | return normalized; 102 | } 103 | 104 | KIMAP::Acl::Rights KIMAP::Acl::denormalizedRights(KIMAP::Acl::Rights rights) 105 | { 106 | Rights denormalized = normalizedRights(rights); 107 | if (denormalized & (CreateMailbox | DeleteMailbox)) { 108 | denormalized |= Create; 109 | } 110 | if (denormalized & (DeleteMessage | Expunge)) { 111 | denormalized |= Delete; 112 | } 113 | return denormalized; 114 | } 115 | -------------------------------------------------------------------------------- /src/acljobbase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "acljobbase.h" 8 | #include "acljobbase_p.h" 9 | #include "response_p.h" 10 | #include "session_p.h" 11 | 12 | #include 13 | 14 | using namespace KIMAP; 15 | 16 | void AclJobBasePrivate::setIdentifier(const QByteArray &identifier) 17 | { 18 | id = identifier; 19 | } 20 | 21 | QByteArray AclJobBasePrivate::identifier() const 22 | { 23 | return id; 24 | } 25 | 26 | bool AclJobBasePrivate::hasRightEnabled(Acl::Right right) const 27 | { 28 | return rightList & right; 29 | } 30 | 31 | void AclJobBasePrivate::setRights(const QByteArray &rights) 32 | { 33 | switch (rights[0]) { 34 | case '+': 35 | modifier = AclJobBase::Add; 36 | break; 37 | case '-': 38 | modifier = AclJobBase::Remove; 39 | break; 40 | default: 41 | modifier = AclJobBase::Change; 42 | break; 43 | } 44 | 45 | rightList = Acl::rightsFromString(rights); 46 | } 47 | 48 | void AclJobBasePrivate::setRights(AclJobBase::AclModifier _modifier, Acl::Rights rights) 49 | { 50 | modifier = _modifier; 51 | // XXX: [alexmerry, 2010-07-24]: this is REALLY unintuitive behaviour 52 | rightList |= rights; 53 | } 54 | 55 | AclJobBase::AclJobBase(Session *session) 56 | : Job(*new AclJobBasePrivate(session, i18n("AclJobBase"))) 57 | { 58 | } 59 | 60 | AclJobBase::AclJobBase(JobPrivate &dd) 61 | : Job(dd) 62 | { 63 | } 64 | 65 | AclJobBase::~AclJobBase() 66 | { 67 | } 68 | 69 | void AclJobBase::setMailBox(const QString &mailBox) 70 | { 71 | Q_D(AclJobBase); 72 | d->mailBox = mailBox; 73 | } 74 | 75 | QString AclJobBase::mailBox() const 76 | { 77 | Q_D(const AclJobBase); 78 | return d->mailBox; 79 | } 80 | 81 | #include "moc_acljobbase.cpp" 82 | -------------------------------------------------------------------------------- /src/acljobbase.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acl.h" 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Response; 18 | class AclJobBasePrivate; 19 | 20 | /** 21 | * Base class for jobs that operate on mailbox ACLs 22 | * 23 | * Provides support for the IMAP ACL extension, as defined by 24 | * RFC 4314. 25 | * 26 | * This class cannot be used directly, you must subclass it and reimplement 27 | * at least the doStart() method. 28 | */ 29 | class KIMAP_EXPORT AclJobBase : public Job 30 | { 31 | Q_OBJECT 32 | Q_DECLARE_PRIVATE(AclJobBase) 33 | 34 | friend class SessionPrivate; 35 | 36 | public: 37 | AclJobBase(Session *session); 38 | ~AclJobBase() override; 39 | 40 | /** 41 | * Used when subclassing to specify how the ACL will be modified. 42 | */ 43 | enum AclModifier { 44 | Add = 0, 45 | Remove, 46 | Change 47 | }; 48 | 49 | /** 50 | * Set the mailbox to act on 51 | * 52 | * @param mailBox the name of an existing mailbox 53 | */ 54 | void setMailBox(const QString &mailBox); 55 | /** 56 | * The mailbox that will be acted upon. 57 | */ 58 | [[nodiscard]] QString mailBox() const; 59 | 60 | protected: 61 | explicit AclJobBase(JobPrivate &dd); 62 | }; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/acljobbase_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "acljobbase.h" 10 | #include "job_p.h" 11 | #include "session.h" 12 | 13 | namespace KIMAP 14 | { 15 | class AclJobBasePrivate : public JobPrivate 16 | { 17 | public: 18 | AclJobBasePrivate(Session *session, const QString &name) 19 | : JobPrivate(session, name) 20 | , rightList(Acl::None) 21 | , modifier(AclJobBase::Change) 22 | { 23 | } 24 | ~AclJobBasePrivate() 25 | { 26 | } 27 | 28 | void setIdentifier(const QByteArray &identifier); 29 | [[nodiscard]] QByteArray identifier() const; 30 | 31 | [[nodiscard]] bool hasRightEnabled(Acl::Right right) const; 32 | 33 | void setRights(const QByteArray &rights); 34 | void setRights(AclJobBase::AclModifier modifier, Acl::Rights rights); 35 | 36 | QString mailBox; 37 | QByteArray id; 38 | Acl::Rights rightList; 39 | AclJobBase::AclModifier modifier; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/appendjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "appendjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class AppendJobPrivate : public JobPrivate 19 | { 20 | public: 21 | AppendJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~AppendJobPrivate() 26 | { 27 | } 28 | 29 | QString mailBox; 30 | QList flags; 31 | QDateTime internalDate; 32 | QByteArray content; 33 | qint64 uid = 0; 34 | }; 35 | } 36 | 37 | using namespace KIMAP; 38 | 39 | AppendJob::AppendJob(Session *session) 40 | : Job(*new AppendJobPrivate(session, i18n("Append"))) 41 | { 42 | } 43 | 44 | AppendJob::~AppendJob() 45 | { 46 | } 47 | 48 | void AppendJob::setMailBox(const QString &mailBox) 49 | { 50 | Q_D(AppendJob); 51 | d->mailBox = mailBox; 52 | } 53 | 54 | QString AppendJob::mailBox() const 55 | { 56 | Q_D(const AppendJob); 57 | return d->mailBox; 58 | } 59 | 60 | void AppendJob::setFlags(const QList &flags) 61 | { 62 | Q_D(AppendJob); 63 | d->flags = flags; 64 | } 65 | 66 | QList AppendJob::flags() const 67 | { 68 | Q_D(const AppendJob); 69 | return d->flags; 70 | } 71 | 72 | void AppendJob::setInternalDate(const QDateTime &internalDate) 73 | { 74 | Q_D(AppendJob); 75 | d->internalDate = internalDate; 76 | } 77 | 78 | QDateTime AppendJob::internalDate() const 79 | { 80 | Q_D(const AppendJob); 81 | return d->internalDate; 82 | } 83 | 84 | void AppendJob::setContent(const QByteArray &content) 85 | { 86 | Q_D(AppendJob); 87 | d->content = content; 88 | } 89 | 90 | QByteArray AppendJob::content() const 91 | { 92 | Q_D(const AppendJob); 93 | return d->content; 94 | } 95 | 96 | qint64 AppendJob::uid() const 97 | { 98 | Q_D(const AppendJob); 99 | return d->uid; 100 | } 101 | 102 | void AppendJob::doStart() 103 | { 104 | Q_D(AppendJob); 105 | 106 | QByteArray parameters = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'; 107 | 108 | if (!d->flags.isEmpty()) { 109 | parameters += " ("; 110 | for (const QByteArray &flag : std::as_const(d->flags)) { 111 | parameters += flag + ' '; 112 | } 113 | parameters.chop(1); 114 | parameters += ')'; 115 | } 116 | 117 | if (!d->internalDate.isNull()) { 118 | const QDateTime utcDateTime = d->internalDate.toUTC(); 119 | parameters += " \"" + QLocale::c().toString(utcDateTime, QStringLiteral("dd-MMM-yyyy hh:mm:ss")).toLatin1() + " +0000" + '\"'; 120 | } 121 | 122 | parameters += " {" + QByteArray::number(d->content.size()) + '}'; 123 | 124 | d->tags << d->sessionInternal()->sendCommand("APPEND", parameters); 125 | } 126 | 127 | void AppendJob::handleResponse(const Response &response) 128 | { 129 | Q_D(AppendJob); 130 | const QList::ConstIterator end(response.responseCode.end()); 131 | for (QList::ConstIterator it = response.responseCode.begin(); it != end; ++it) { 132 | if (it->toString() == "APPENDUID") { 133 | it = it + 2; 134 | if (it != end) { 135 | d->uid = it->toString().toLongLong(); 136 | } 137 | break; 138 | } 139 | } 140 | 141 | if (handleErrorReplies(response) == NotHandled) { 142 | if (!response.content.isEmpty() && response.content[0].toString() == "+") { 143 | d->sessionInternal()->sendData(d->content); 144 | } 145 | } 146 | } 147 | 148 | #include "moc_appendjob.cpp" 149 | -------------------------------------------------------------------------------- /src/appendjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | #include 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Response; 18 | class AppendJobPrivate; 19 | 20 | /** 21 | * Appends a message to a mailbox. 22 | * 23 | * This job can only be run when the session is in the 24 | * authenticated (or selected) state. 25 | * 26 | * If the server supports ACLs, the user will need the 27 | * Acl::Insert right on the mailbox. 28 | */ 29 | class KIMAP_EXPORT AppendJob : public Job 30 | { 31 | Q_OBJECT 32 | Q_DECLARE_PRIVATE(AppendJob) 33 | 34 | friend class SessionPrivate; 35 | 36 | public: 37 | explicit AppendJob(Session *session); 38 | ~AppendJob() override; 39 | 40 | /** 41 | * Set the mailbox to append the message to. 42 | * 43 | * If the mailbox does not exist, it will not automatically 44 | * be created and the command will fail. 45 | * 46 | * @param mailBox the (unquoted) name of the mailbox 47 | */ 48 | void setMailBox(const QString &mailBox); 49 | /** 50 | * The mailbox that the message will be appended to. 51 | */ 52 | [[nodiscard]] QString mailBox() const; 53 | 54 | /** 55 | * Set the flags that should be applied to the appended message. 56 | * 57 | * @param flags a list of flags 58 | */ 59 | void setFlags(const QList &flags); 60 | /** 61 | * The flags that will be set on the appended message. 62 | */ 63 | [[nodiscard]] QList flags() const; 64 | 65 | /** 66 | * Set the internal date that should be applied to the appended message. 67 | * 68 | * This is the date/time the IMAP server should set internally for the appended message. 69 | * See https://tools.ietf.org/html/rfc3501#section-6.3.11 70 | * 71 | * If this is not set, the server will use the current date/time. 72 | * 73 | * @param internalDate the internal date 74 | * 75 | * @since 4.13 76 | */ 77 | void setInternalDate(const QDateTime &internalDate); 78 | 79 | /** 80 | * The internal date that will be set on the appended message. 81 | * 82 | * @since 4.13 83 | */ 84 | [[nodiscard]] QDateTime internalDate() const; 85 | 86 | /** 87 | * The content of the message. 88 | * 89 | * This should be in RFC-2822 format, although some required header 90 | * lines may be omitted in certain cases, for example when appending 91 | * to a Drafts folder. 92 | * 93 | * @param content usually an RFC-2822 message 94 | */ 95 | void setContent(const QByteArray &content); 96 | /** 97 | * The content that the message will have. 98 | */ 99 | [[nodiscard]] QByteArray content() const; 100 | 101 | /** 102 | * The UID of the new message. 103 | * 104 | * This will be zero if it is unknown. 105 | * 106 | * The UID will not be known until the job has been successfully 107 | * executed, and it will only be known at all if the server 108 | * supports the UIDPLUS extension (RFC 4315). 109 | */ 110 | [[nodiscard]] qint64 uid() const; 111 | 112 | protected: 113 | void doStart() override; 114 | void handleResponse(const Response &response) override; 115 | }; 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/capabilitiesjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "capabilitiesjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "session_p.h" 14 | 15 | namespace KIMAP 16 | { 17 | class CapabilitiesJobPrivate : public JobPrivate 18 | { 19 | public: 20 | CapabilitiesJobPrivate(Session *session, const QString &name) 21 | : JobPrivate(session, name) 22 | { 23 | } 24 | ~CapabilitiesJobPrivate() 25 | { 26 | } 27 | 28 | QStringList capabilities; 29 | }; 30 | } 31 | 32 | using namespace KIMAP; 33 | 34 | CapabilitiesJob::CapabilitiesJob(Session *session) 35 | : Job(*new CapabilitiesJobPrivate(session, i18n("Capabilities"))) 36 | { 37 | } 38 | 39 | CapabilitiesJob::~CapabilitiesJob() 40 | { 41 | } 42 | 43 | QStringList CapabilitiesJob::capabilities() const 44 | { 45 | Q_D(const CapabilitiesJob); 46 | return d->capabilities; 47 | } 48 | 49 | void CapabilitiesJob::doStart() 50 | { 51 | Q_D(CapabilitiesJob); 52 | d->tags << d->sessionInternal()->sendCommand("CAPABILITY"); 53 | } 54 | 55 | void CapabilitiesJob::handleResponse(const Response &response) 56 | { 57 | Q_D(CapabilitiesJob); 58 | if (handleErrorReplies(response) == NotHandled) { 59 | const int responseSize(response.content.size()); 60 | if (responseSize >= 2 && response.content[1].toString() == "CAPABILITY") { 61 | for (int i = 2; i < responseSize; ++i) { 62 | d->capabilities << QLatin1StringView(response.content[i].toString().toUpper()); 63 | } 64 | Q_EMIT capabilitiesReceived(d->capabilities); 65 | } 66 | } 67 | } 68 | 69 | #include "moc_capabilitiesjob.cpp" 70 | -------------------------------------------------------------------------------- /src/capabilitiesjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class CapabilitiesJobPrivate; 18 | 19 | /** 20 | * Checks server capabilities. 21 | * 22 | * This job can be run in any open session. 23 | * 24 | * This simply asks the server what capabilities it supports 25 | * (using the CAPABILITY command) and returns the list 26 | * provided by the server. The list may, therefore, be 27 | * inaccurate: the server may claim to support something 28 | * it does not implement properly, or it may omit a feature 29 | * that it does, in reality, support. 30 | */ 31 | class KIMAP_EXPORT CapabilitiesJob : public Job 32 | { 33 | Q_OBJECT 34 | Q_DECLARE_PRIVATE(CapabilitiesJob) 35 | 36 | friend class SessionPrivate; 37 | 38 | public: 39 | CapabilitiesJob(Session *session); 40 | ~CapabilitiesJob() override; 41 | 42 | /** 43 | * The capabilities the server claims to support. 44 | * 45 | * This will return an empty list until the job has completed. 46 | */ 47 | [[nodiscard]] QStringList capabilities() const; 48 | 49 | Q_SIGNALS: 50 | /** 51 | * Notifies listeners that the capabilities have been fetched. 52 | * 53 | * @param capabilities The capabilities the server claims to support. 54 | */ 55 | void capabilitiesReceived(const QStringList &capabilities); 56 | 57 | protected: 58 | void doStart() override; 59 | void handleResponse(const Response &response) override; 60 | }; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/closejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "closejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "session_p.h" 14 | 15 | namespace KIMAP 16 | { 17 | class CloseJobPrivate : public JobPrivate 18 | { 19 | public: 20 | CloseJobPrivate(Session *session, const QString &name) 21 | : JobPrivate(session, name) 22 | { 23 | } 24 | 25 | quint64 highestModSeq = 0; 26 | }; 27 | } 28 | 29 | using namespace KIMAP; 30 | 31 | CloseJob::CloseJob(Session *session) 32 | : Job(*new CloseJobPrivate(session, i18n("Close"))) 33 | { 34 | } 35 | 36 | void CloseJob::doStart() 37 | { 38 | Q_D(CloseJob); 39 | d->tags << d->sessionInternal()->sendCommand("CLOSE"); 40 | } 41 | 42 | quint64 CloseJob::newHighestModSeq() const 43 | { 44 | Q_D(const CloseJob); 45 | return d->highestModSeq; 46 | } 47 | 48 | void CloseJob::handleResponse(const Response &response) 49 | { 50 | Q_D(CloseJob); 51 | 52 | if (response.responseCode.size() >= 2 && response.responseCode[0].toString() == "HIGHESTMODSEQ") { 53 | d->highestModSeq = response.responseCode[1].toString().toULongLong(); 54 | } 55 | 56 | Job::handleErrorReplies(response); 57 | } 58 | 59 | #include "moc_closejob.cpp" 60 | -------------------------------------------------------------------------------- /src/closejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class CloseJobPrivate; 18 | 19 | /** 20 | * Closes the current mailbox. 21 | * 22 | * This job can only be run when the session is in the selected state. 23 | * 24 | * Permanently removes all messages that have the \\Deleted 25 | * flag set from the currently selected mailbox, and returns 26 | * to the authenticated state from the selected state. 27 | * 28 | * The server will not provide any notifications of which 29 | * messages were expunged, so this is quicker than doing 30 | * an expunge and then implicitly closing the mailbox 31 | * (by selecting or examining another mailbox or logging 32 | * out). If the QRESYNC extension (RFC5162) is available on the 33 | * server and has been enabled, the job will provide a new 34 | * modification sequence after expunging the deleted messages. 35 | * 36 | * No messages are removed if the mailbox is open in a read-only 37 | * state, or if the server supports ACLs and the user does not 38 | * have the Acl::Expunge right on the mailbox. 39 | */ 40 | class KIMAP_EXPORT CloseJob : public Job 41 | { 42 | Q_OBJECT 43 | Q_DECLARE_PRIVATE(CloseJob) 44 | 45 | friend class SessionPrivate; 46 | 47 | public: 48 | explicit CloseJob(Session *session); 49 | ~CloseJob() override = default; 50 | 51 | /** 52 | * Returns new modification sequence number after expunging messages. 53 | * 54 | * This value is only valid when server supports the QRESYNC extension 55 | * (RFC5162) and it has been explicitly enabled on this session. 56 | * 57 | * @see KIMAP::EnableJob 58 | * @since 5.16 59 | */ 60 | [[nodiscard]] quint64 newHighestModSeq() const; 61 | 62 | protected: 63 | void doStart() override; 64 | void handleResponse(const Response &response) override; 65 | }; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2008 Jarosław Staniek 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | extern "C" { 15 | #include 16 | } 17 | 18 | inline bool initSASL() 19 | { 20 | #ifdef Q_OS_WIN // krazy:exclude=cpp 21 | for (const auto &path : QCoreApplication::libraryPaths()) { 22 | QDir dir(path); 23 | if (dir.exists(QStringLiteral("sasl2"))) { 24 | auto libInstallPath = QFile::encodeName(dir.absoluteFilePath(QStringLiteral("sasl2"))); 25 | if (sasl_set_path(SASL_PATH_TYPE_PLUGIN, libInstallPath.data()) != SASL_OK) { 26 | fprintf(stderr, "SASL path initialization failed!\n"); 27 | return false; 28 | } 29 | break; 30 | } 31 | } 32 | #endif 33 | 34 | if (sasl_client_init(nullptr) != SASL_OK) { 35 | fprintf(stderr, "SASL library initialization failed!\n"); 36 | return false; 37 | } 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /src/copyjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "copyjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | // TODO: when custom error codes are introduced, handle the NO [TRYCREATE] response 17 | 18 | namespace KIMAP 19 | { 20 | class CopyJobPrivate : public JobPrivate 21 | { 22 | public: 23 | CopyJobPrivate(Session *session, const QString &name) 24 | : JobPrivate(session, name) 25 | { 26 | } 27 | ~CopyJobPrivate() 28 | { 29 | } 30 | 31 | QString mailBox; 32 | ImapSet set; 33 | bool uidBased = false; 34 | ImapSet resultingUids; 35 | }; 36 | } 37 | 38 | using namespace KIMAP; 39 | 40 | CopyJob::CopyJob(Session *session) 41 | : Job(*new CopyJobPrivate(session, i18n("Copy"))) 42 | { 43 | Q_D(CopyJob); 44 | d->uidBased = false; 45 | } 46 | 47 | CopyJob::~CopyJob() 48 | { 49 | } 50 | 51 | void CopyJob::setMailBox(const QString &mailBox) 52 | { 53 | Q_D(CopyJob); 54 | d->mailBox = mailBox; 55 | } 56 | 57 | QString CopyJob::mailBox() const 58 | { 59 | Q_D(const CopyJob); 60 | return d->mailBox; 61 | } 62 | 63 | void CopyJob::setSequenceSet(const ImapSet &set) 64 | { 65 | Q_D(CopyJob); 66 | d->set = set; 67 | } 68 | 69 | ImapSet CopyJob::sequenceSet() const 70 | { 71 | Q_D(const CopyJob); 72 | return d->set; 73 | } 74 | 75 | void CopyJob::setUidBased(bool uidBased) 76 | { 77 | Q_D(CopyJob); 78 | d->uidBased = uidBased; 79 | } 80 | 81 | bool CopyJob::isUidBased() const 82 | { 83 | Q_D(const CopyJob); 84 | return d->uidBased; 85 | } 86 | 87 | ImapSet CopyJob::resultingUids() const 88 | { 89 | Q_D(const CopyJob); 90 | return d->resultingUids; 91 | } 92 | 93 | void CopyJob::doStart() 94 | { 95 | Q_D(CopyJob); 96 | 97 | d->set.optimize(); 98 | QByteArray parameters = d->set.toImapSequenceSet() + ' '; 99 | parameters += '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'; 100 | 101 | QByteArray command = "COPY"; 102 | if (d->uidBased) { 103 | command = "UID " + command; 104 | } 105 | 106 | d->tags << d->sessionInternal()->sendCommand(command, parameters); 107 | } 108 | 109 | void CopyJob::handleResponse(const Response &response) 110 | { 111 | Q_D(CopyJob); 112 | for (auto it = response.responseCode.cbegin(), end = response.responseCode.cend(); it != end; ++it) { 113 | if (it->toString() == "COPYUID") { 114 | it = it + 3; 115 | if (it < end) { 116 | d->resultingUids = ImapSet::fromImapSequenceSet(it->toString()); 117 | } 118 | break; 119 | } 120 | } 121 | 122 | handleErrorReplies(response); 123 | } 124 | 125 | #include "moc_copyjob.cpp" 126 | -------------------------------------------------------------------------------- /src/copyjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "imapset.h" 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Message; 18 | class CopyJobPrivate; 19 | 20 | /** 21 | * Copies one or more messages to another mailbox. 22 | * 23 | * This job can only be run when the session is in the selected state. 24 | * 25 | * If the server supports ACLs, the user will need the 26 | * Acl::Insert right on the target mailbox. 27 | * In order to preserve message flags, the user may also need 28 | * some combination of Acl::DeleteMessage, 29 | * Acl::KeepSeen and Acl::Write on the 30 | * target mailbox. 31 | */ 32 | class KIMAP_EXPORT CopyJob : public Job 33 | { 34 | Q_OBJECT 35 | Q_DECLARE_PRIVATE(CopyJob) 36 | 37 | friend class SessionPrivate; 38 | 39 | public: 40 | explicit CopyJob(Session *session); 41 | ~CopyJob() override; 42 | 43 | /** 44 | * Sets the destination mailbox. 45 | * 46 | * If the mailbox does not exist, the server should not create 47 | * it automatically and the job should fail. Note, however, 48 | * that a conforming server may create the mailbox automatically. 49 | * 50 | * @param mailBox the (unquoted) name of the mailbox where the 51 | * messages should be copied to 52 | */ 53 | void setMailBox(const QString &mailBox); 54 | /** 55 | * The destination mailbox 56 | */ 57 | [[nodiscard]] QString mailBox() const; 58 | 59 | /** 60 | * Sets the messages to be copied 61 | * 62 | * If sequence numbers are given, isUidBased() should be false. If UIDs 63 | * are given, isUidBased() should be true. 64 | * 65 | * RFC 3501 is unclear as to what should happen if invalid sequence numbers 66 | * are passed. If non-existent UIDs are passed, they will be ignored. 67 | * 68 | * @param set the sequence numbers or UIDs of the messages to be copied 69 | */ 70 | void setSequenceSet(const ImapSet &set); 71 | /** 72 | * The messages that will be copied. 73 | * 74 | * isUidBased() can be used to check whether the ImapSet contains 75 | * sequence numbers or UIDs. 76 | * 77 | * @return the sequence numbers or UIDs of the messages to be copied 78 | */ 79 | [[nodiscard]] ImapSet sequenceSet() const; 80 | 81 | /** 82 | * Set how the sequence set should be interpreted. 83 | * 84 | * @param uidBased if @c true the argument to setSequenceSet will be 85 | * interpreted as UIDs, if @c false it will be interpreted 86 | * as sequence numbers 87 | */ 88 | void setUidBased(bool uidBased); 89 | /** 90 | * How to interpret the sequence set. 91 | * 92 | * @return if @c true the result of sequenceSet() should be 93 | * interpreted as UIDs, if @c false it should be interpreted 94 | * as sequence numbers 95 | */ 96 | [[nodiscard]] bool isUidBased() const; 97 | 98 | /** 99 | * The UIDs of the new copies of the messages 100 | * 101 | * This will be an empty set if no messages have been copied yet 102 | * or if the server does not support the UIDPLUS extension. 103 | */ 104 | [[nodiscard]] ImapSet resultingUids() const; 105 | 106 | protected: 107 | void doStart() override; 108 | void handleResponse(const Response &response) override; 109 | }; 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/createjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "createjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class CreateJobPrivate : public JobPrivate 19 | { 20 | public: 21 | CreateJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~CreateJobPrivate() 26 | { 27 | } 28 | 29 | QString mailBox; 30 | }; 31 | } 32 | 33 | using namespace KIMAP; 34 | 35 | CreateJob::CreateJob(Session *session) 36 | : Job(*new CreateJobPrivate(session, i18n("Create"))) 37 | { 38 | } 39 | 40 | CreateJob::~CreateJob() 41 | { 42 | } 43 | 44 | void CreateJob::doStart() 45 | { 46 | Q_D(CreateJob); 47 | d->tags << d->sessionInternal()->sendCommand("CREATE", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 48 | } 49 | 50 | void CreateJob::handleResponse(const Response &response) 51 | { 52 | Q_D(CreateJob); 53 | 54 | if (!response.content.isEmpty() && d->tags.contains(response.content.first().toString())) { 55 | if (response.content.size() >= 2 && response.content[1].toString() == "NO") { 56 | for (auto it = response.responseCode.cbegin(), end = response.responseCode.cend(); it != end; ++it) { 57 | // ALREADYEXISTS can be considered a success during CREATE 58 | // cf. https://tools.ietf.org/html/rfc5530#section-3 59 | if (it->toString() == "ALREADYEXISTS") { 60 | // Code copied from handleErrorReplies: 61 | d->tags.removeAll(response.content.first().toString()); 62 | if (d->tags.isEmpty()) { // Only emit result when the last command returned 63 | emitResult(); 64 | } 65 | return; 66 | } 67 | } 68 | } 69 | } 70 | 71 | handleErrorReplies(response); 72 | } 73 | 74 | void CreateJob::setMailBox(const QString &mailBox) 75 | { 76 | Q_D(CreateJob); 77 | d->mailBox = mailBox; 78 | } 79 | 80 | QString CreateJob::mailBox() const 81 | { 82 | Q_D(const CreateJob); 83 | return d->mailBox; 84 | } 85 | 86 | #include "moc_createjob.cpp" 87 | -------------------------------------------------------------------------------- /src/createjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class CreateJobPrivate; 18 | 19 | /** 20 | * Creates a new mailbox 21 | * 22 | * This job can only be run when the session is in the 23 | * authenticated (or selected) state. 24 | * 25 | * This job will fail if the mailbox already exists. 26 | * 27 | * If the server supports ACLs, the user must have the 28 | * Acl::CreateMailbox permission on the parent 29 | * mailbox. Note that what is meant by "parent mailbox" 30 | * depends on the server: . and / are typical hierarchy 31 | * delimiters. 32 | */ 33 | class KIMAP_EXPORT CreateJob : public Job 34 | { 35 | Q_OBJECT 36 | Q_DECLARE_PRIVATE(CreateJob) 37 | 38 | friend class SessionPrivate; 39 | 40 | public: 41 | explicit CreateJob(Session *session); 42 | ~CreateJob() override; 43 | 44 | /** 45 | * Set the name of the new mailbox 46 | * 47 | * @param mailBox an (unquoted) identifier that does not correspond 48 | * to an existing mailbox name 49 | */ 50 | void setMailBox(const QString &mailBox); 51 | /** 52 | * The name of the mailbox that will be created 53 | */ 54 | [[nodiscard]] QString mailBox() const; 55 | 56 | protected: 57 | void doStart() override; 58 | void handleResponse(const Response &response) override; 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/deleteacljob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "deleteacljob.h" 8 | 9 | #include 10 | 11 | #include "acljobbase_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class DeleteAclJobPrivate : public AclJobBasePrivate 19 | { 20 | public: 21 | DeleteAclJobPrivate(Session *session, const QString &name) 22 | : AclJobBasePrivate(session, name) 23 | { 24 | } 25 | ~DeleteAclJobPrivate() 26 | { 27 | } 28 | }; 29 | } 30 | 31 | using namespace KIMAP; 32 | 33 | DeleteAclJob::DeleteAclJob(Session *session) 34 | : AclJobBase(session) 35 | { 36 | Q_D(DeleteAclJob); 37 | d->m_name = i18n("DeleteAclJob"); 38 | } 39 | 40 | DeleteAclJob::~DeleteAclJob() 41 | { 42 | } 43 | 44 | void DeleteAclJob::doStart() 45 | { 46 | Q_D(DeleteAclJob); 47 | 48 | d->tags << d->sessionInternal()->sendCommand("DELETEACL", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" \"" + d->id); 49 | } 50 | 51 | void DeleteAclJob::setIdentifier(const QByteArray &identifier) 52 | { 53 | Q_D(DeleteAclJob); 54 | d->setIdentifier(identifier); 55 | } 56 | 57 | QByteArray DeleteAclJob::identifier() 58 | { 59 | Q_D(DeleteAclJob); 60 | return d->identifier(); 61 | } 62 | 63 | #include "moc_deleteacljob.cpp" 64 | -------------------------------------------------------------------------------- /src/deleteacljob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acljobbase.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class DeleteAclJobPrivate; 18 | 19 | /** 20 | * Removes an identifier from the ACL of a mailbox. 21 | * 22 | * This job can only be run when the session is in the 23 | * authenticated (or selected) state. 24 | * 25 | * The user must have the Acl::Admin permission 26 | * on the mailbox for this job to succeed (see 27 | * MyRightsJob). 28 | * 29 | * This job requires that the server supports the ACL 30 | * capability, defined in 31 | * RFC 4314. 32 | */ 33 | class KIMAP_EXPORT DeleteAclJob : public AclJobBase 34 | { 35 | Q_OBJECT 36 | Q_DECLARE_PRIVATE(DeleteAclJob) 37 | 38 | friend class SessionPrivate; 39 | 40 | public: 41 | explicit DeleteAclJob(Session *session); 42 | ~DeleteAclJob() override; 43 | 44 | /** 45 | * Sets the identifier to remove 46 | */ 47 | void setIdentifier(const QByteArray &identifier); 48 | /** 49 | * The identifier that will be removed 50 | */ 51 | [[nodiscard]] QByteArray identifier(); 52 | 53 | protected: 54 | void doStart() override; 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/deletejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "deletejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class DeleteJobPrivate : public JobPrivate 19 | { 20 | public: 21 | DeleteJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~DeleteJobPrivate() 26 | { 27 | } 28 | 29 | QString mailBox; 30 | }; 31 | } 32 | 33 | using namespace KIMAP; 34 | 35 | DeleteJob::DeleteJob(Session *session) 36 | : Job(*new DeleteJobPrivate(session, i18n("Delete"))) 37 | { 38 | } 39 | 40 | DeleteJob::~DeleteJob() 41 | { 42 | } 43 | 44 | void DeleteJob::doStart() 45 | { 46 | Q_D(DeleteJob); 47 | d->tags << d->sessionInternal()->sendCommand("DELETE", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 48 | } 49 | 50 | void DeleteJob::handleResponse(const Response &response) 51 | { 52 | Q_D(DeleteJob); 53 | 54 | if (!response.content.isEmpty() && d->tags.contains(response.content.first().toString())) { 55 | if (response.content.size() >= 2 && response.content[1].toString() == "NO") { 56 | for (auto it = response.responseCode.cbegin(), end = response.responseCode.cend(); it != end; ++it) { 57 | // NONEXISTENT can be considered a success during DELETE 58 | // cf. https://tools.ietf.org/html/rfc5530#section-3 59 | if (it->toString() == "NONEXISTENT") { 60 | // Code copied from handleErrorReplies: 61 | d->tags.removeAll(response.content.first().toString()); 62 | if (d->tags.isEmpty()) { // Only emit result when the last command returned 63 | emitResult(); 64 | } 65 | return; 66 | } 67 | } 68 | } 69 | } 70 | 71 | handleErrorReplies(response); 72 | } 73 | 74 | void DeleteJob::setMailBox(const QString &mailBox) 75 | { 76 | Q_D(DeleteJob); 77 | d->mailBox = mailBox; 78 | } 79 | 80 | QString DeleteJob::mailBox() const 81 | { 82 | Q_D(const DeleteJob); 83 | return d->mailBox; 84 | } 85 | 86 | #include "moc_deletejob.cpp" 87 | -------------------------------------------------------------------------------- /src/deletejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class DeleteJobPrivate; 17 | 18 | /** 19 | * Delete a mailbox 20 | * 21 | * Note that some servers will refuse to delete a 22 | * mailbox unless it is empty (ie: all mails have 23 | * had their \Deleted flag set, and then the 24 | * mailbox has been expunged). 25 | * 26 | * This job can only be run when the session is in the 27 | * authenticated (or selected) state. 28 | * 29 | * If the server supports ACLs, you will need the 30 | * Acl::DeleteMailbox right on the mailbox. 31 | */ 32 | class KIMAP_EXPORT DeleteJob : public Job 33 | { 34 | Q_OBJECT 35 | Q_DECLARE_PRIVATE(DeleteJob) 36 | 37 | friend class SessionPrivate; 38 | 39 | public: 40 | explicit DeleteJob(Session *session); 41 | ~DeleteJob() override; 42 | 43 | /** 44 | * Set the mailbox to delete. 45 | */ 46 | void setMailBox(const QString &mailBox); 47 | /** 48 | * The mailbox that will be deleted. 49 | */ 50 | [[nodiscard]] QString mailBox() const; 51 | 52 | protected: 53 | void doStart() override; 54 | void handleResponse(const Response &response) override; 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/enablejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "enablejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "kimap_debug.h" 13 | #include "response_p.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class EnableJobPrivate : public JobPrivate 19 | { 20 | public: 21 | using JobPrivate::JobPrivate; 22 | 23 | QStringList reqCapabilities; 24 | QStringList enabledCapabilities; 25 | }; 26 | } 27 | 28 | using namespace KIMAP; 29 | 30 | EnableJob::EnableJob(Session *session) 31 | : Job(*new EnableJobPrivate(session, i18n("Enable"))) 32 | { 33 | } 34 | 35 | EnableJob::~EnableJob() = default; 36 | 37 | void EnableJob::setCapabilities(const QStringList &capabilities) 38 | { 39 | Q_D(EnableJob); 40 | d->reqCapabilities = capabilities; 41 | } 42 | 43 | QStringList EnableJob::enabledCapabilities() const 44 | { 45 | Q_D(const EnableJob); 46 | return d->enabledCapabilities; 47 | } 48 | 49 | void EnableJob::doStart() 50 | { 51 | Q_D(EnableJob); 52 | d->tags << d->sessionInternal()->sendCommand("ENABLE", d->reqCapabilities.join(QLatin1Char{' '}).toLatin1()); 53 | } 54 | 55 | void EnableJob::handleResponse(const Response &response) 56 | { 57 | Q_D(EnableJob); 58 | 59 | if (handleErrorReplies(response) == NotHandled) { 60 | if (response.content.size() >= 2) { 61 | for (int i = 2; i < response.content.size(); ++i) { 62 | d->enabledCapabilities.push_back(QString::fromLatin1(response.content[i].toString())); 63 | } 64 | } else { 65 | qCDebug(KIMAP_LOG) << response.toString(); 66 | } 67 | } 68 | } 69 | 70 | #include "moc_enablejob.cpp" 71 | -------------------------------------------------------------------------------- /src/enablejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | #include 14 | 15 | namespace KIMAP 16 | { 17 | class Session; 18 | struct Response; 19 | class EnableJobPrivate; 20 | 21 | /** 22 | * Job to enable additional IMAP capabilities. 23 | * 24 | * Requires server to implement the IMAP ENABLE Extension (RFC5161). The 25 | * new capabilities to enable will be specified by the user. The user is 26 | * responsible for making sure the capabilities are supported by the server. 27 | * 28 | * The example usecase for this job is to enable support for the QRESYNC 29 | * extension (RFC5162) on the server. 30 | * 31 | * @since 5.16 32 | */ 33 | class KIMAP_EXPORT EnableJob : public Job 34 | { 35 | Q_OBJECT 36 | Q_DECLARE_PRIVATE(EnableJob) 37 | 38 | friend class SessionPrivate; 39 | 40 | public: 41 | explicit EnableJob(Session *session); 42 | ~EnableJob() override; 43 | 44 | /** 45 | * List of server capabilities to enable. 46 | */ 47 | void setCapabilities(const QStringList &capabilities); 48 | 49 | /** 50 | * List of capabilities that were successfully enabled on the server. 51 | */ 52 | [[nodiscard]] QStringList enabledCapabilities() const; 53 | 54 | protected: 55 | void doStart() override; 56 | void handleResponse(const Response &response) override; 57 | }; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/expungejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "expungejob.h" 8 | 9 | #include "kimap_debug.h" 10 | #include 11 | 12 | #include "imapset.h" 13 | #include "job_p.h" 14 | #include "response_p.h" 15 | #include "session_p.h" 16 | 17 | namespace KIMAP 18 | { 19 | class ExpungeJobPrivate : public JobPrivate 20 | { 21 | public: 22 | ExpungeJobPrivate(Session *session, const QString &name) 23 | : JobPrivate(session, name) 24 | { 25 | } 26 | #if 0 27 | QList< int > items; 28 | #endif 29 | KIMAP::ImapSet vanished; 30 | quint64 highestModSeq = 0; 31 | }; 32 | } 33 | 34 | using namespace KIMAP; 35 | 36 | ExpungeJob::ExpungeJob(Session *session) 37 | : Job(*new ExpungeJobPrivate(session, i18n("Expunge"))) 38 | { 39 | } 40 | 41 | KIMAP::ImapSet ExpungeJob::vanishedMessages() const 42 | { 43 | Q_D(const ExpungeJob); 44 | return d->vanished; 45 | } 46 | 47 | quint64 ExpungeJob::newHighestModSeq() const 48 | { 49 | Q_D(const ExpungeJob); 50 | return d->highestModSeq; 51 | } 52 | 53 | void ExpungeJob::doStart() 54 | { 55 | Q_D(ExpungeJob); 56 | d->tags << d->sessionInternal()->sendCommand("EXPUNGE"); 57 | } 58 | 59 | void ExpungeJob::handleResponse(const Response &response) 60 | { 61 | Q_D(ExpungeJob); 62 | 63 | // Must be handler before handleErrorReplies(), so the value is available 64 | // before the result is emitted. 65 | if (response.responseCode.size() >= 2) { 66 | if (response.responseCode[0].toString() == "HIGHESTMODSEQ") { 67 | d->highestModSeq = response.responseCode[1].toString().toULongLong(); 68 | } 69 | } 70 | 71 | if (handleErrorReplies(response) == NotHandled) { 72 | if (response.content.size() >= 3) { 73 | if (response.content[1].toString() == "VANISHED") { 74 | d->vanished = KIMAP::ImapSet::fromImapSequenceSet(response.content[2].toString()); 75 | return; 76 | } else if (response.content[2].toString() == "EXPUNGE") { 77 | #if 0 78 | QByteArray s = response.content[1].toString(); 79 | bool ok = true; 80 | int id = s.toInt(&ok); 81 | if (ok) { 82 | d->items.append(id); 83 | } 84 | //TODO error handling 85 | #endif 86 | return; 87 | } 88 | } 89 | qCDebug(KIMAP_LOG) << "Unhandled response: " << response.toString().constData(); 90 | } 91 | } 92 | 93 | #include "moc_expungejob.cpp" 94 | -------------------------------------------------------------------------------- /src/expungejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class ImapSet; 18 | class ExpungeJobPrivate; 19 | 20 | /** 21 | * Expunges the deleted messages in the selected mailbox. 22 | * 23 | * This permanently removes any messages that have the 24 | * \Deleted flag set in the selected mailbox. 25 | * 26 | * This job can only be run when the session is in the 27 | * selected state. 28 | * 29 | * If the server supports ACLs, the user will need the 30 | * Acl::Expunge right on the mailbox. 31 | */ 32 | class KIMAP_EXPORT ExpungeJob : public Job 33 | { 34 | Q_OBJECT 35 | Q_DECLARE_PRIVATE(ExpungeJob) 36 | 37 | friend class SessionPrivate; 38 | 39 | public: 40 | explicit ExpungeJob(Session *session); 41 | ~ExpungeJob() override = default; 42 | 43 | /** 44 | * Returns UIDs of messages that have been expunged. 45 | * 46 | * This feature is only available when QRESYNC capability (RFC5162) is 47 | * supported by the server and have been enabled on the current session. 48 | * 49 | * @see KIMAP::EnableJob 50 | * @since 5.16 51 | */ 52 | [[nodiscard]] KIMAP::ImapSet vanishedMessages() const; 53 | 54 | /** 55 | * Returns new highest modification sequence number. 56 | * 57 | * This feature is only available when QRESYNC capability (RFC5162) is 58 | * supported by the server and have been enabled on the current session. 59 | * 60 | * @see KIMAP::EnableJob 61 | * @since 5.16 62 | */ 63 | [[nodiscard]] quint64 newHighestModSeq() const; 64 | 65 | protected: 66 | void doStart() override; 67 | void handleResponse(const Response &response) override; 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/getacljob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "getacljob.h" 8 | 9 | #include "kimap_debug.h" 10 | #include 11 | 12 | #include "acljobbase_p.h" 13 | #include "response_p.h" 14 | #include "rfccodecs.h" 15 | #include "session_p.h" 16 | 17 | namespace KIMAP 18 | { 19 | class GetAclJobPrivate : public AclJobBasePrivate 20 | { 21 | public: 22 | GetAclJobPrivate(Session *session, const QString &name) 23 | : AclJobBasePrivate(session, name) 24 | { 25 | } 26 | ~GetAclJobPrivate() 27 | { 28 | } 29 | 30 | QMap userRights; 31 | }; 32 | } 33 | 34 | using namespace KIMAP; 35 | 36 | GetAclJob::GetAclJob(Session *session) 37 | : AclJobBase(*new GetAclJobPrivate(session, i18n("GetAcl"))) 38 | { 39 | } 40 | 41 | GetAclJob::~GetAclJob() 42 | { 43 | } 44 | 45 | void GetAclJob::doStart() 46 | { 47 | Q_D(GetAclJob); 48 | 49 | d->tags << d->sessionInternal()->sendCommand("GETACL", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 50 | } 51 | 52 | void GetAclJob::handleResponse(const Response &response) 53 | { 54 | Q_D(GetAclJob); 55 | // qCDebug(KIMAP_LOG) << response.toString(); 56 | 57 | if (handleErrorReplies(response) == NotHandled) { 58 | if (response.content.size() >= 4 && response.content[1].toString() == "ACL") { 59 | int i = 3; 60 | while (i < response.content.size() - 1) { 61 | QByteArray id = response.content[i].toString(); 62 | QByteArray rights = response.content[i + 1].toString(); 63 | d->userRights[id] = Acl::rightsFromString(rights); 64 | i += 2; 65 | } 66 | } 67 | } 68 | } 69 | 70 | QList GetAclJob::identifiers() const 71 | { 72 | Q_D(const GetAclJob); 73 | return d->userRights.keys(); 74 | } 75 | 76 | bool GetAclJob::hasRightEnabled(const QByteArray &identifier, Acl::Right right) const 77 | { 78 | Q_D(const GetAclJob); 79 | if (d->userRights.contains(identifier)) { 80 | Acl::Rights rights = d->userRights[identifier]; 81 | return rights & right; 82 | } 83 | 84 | return false; 85 | } 86 | 87 | Acl::Rights GetAclJob::rights(const QByteArray &identifier) const 88 | { 89 | Q_D(const GetAclJob); 90 | Acl::Rights result; 91 | if (d->userRights.contains(identifier)) { 92 | result = d->userRights[identifier]; 93 | } 94 | return result; 95 | } 96 | 97 | QMap GetAclJob::allRights() const 98 | { 99 | Q_D(const GetAclJob); 100 | return d->userRights; 101 | } 102 | 103 | #include "moc_getacljob.cpp" 104 | -------------------------------------------------------------------------------- /src/getacljob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acljobbase.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class GetAclJobPrivate; 18 | 19 | /** 20 | * Gets the ACL for a mailbox 21 | * 22 | * This job can only be run when the session is in the 23 | * authenticated (or selected) state. 24 | * 25 | * The user must have the Acl::Admin permission 26 | * on the mailbox for this job to succeed (see 27 | * MyRightsJob). 28 | * 29 | * This job requires that the server supports the ACL 30 | * capability, defined in 31 | * RFC 4314. 32 | * 33 | * The meaning of identifiers depends on the server implementation, 34 | * with the following restrictions: 35 | * 36 | * - "anyone" means any authenticated user, including anonymous 37 | * - an identifier starting with a minus sign ('-') indicates 38 | * "negative rights": rights that should be taken away from 39 | * matching users 40 | * 41 | * Other than the above restrictions, ACL identifiers are usually 42 | * IMAP usernames, but could potentially be group names as well. 43 | * 44 | * Note that negative rights override positive rights: if 45 | * "fred" and "-fred" are both assigned the 'w' right, the 46 | * user "fred" will not have the 'w' right. 47 | */ 48 | class KIMAP_EXPORT GetAclJob : public AclJobBase 49 | { 50 | Q_OBJECT 51 | Q_DECLARE_PRIVATE(GetAclJob) 52 | 53 | friend class SessionPrivate; 54 | 55 | public: 56 | explicit GetAclJob(Session *session); 57 | ~GetAclJob() override; 58 | 59 | /** 60 | * The identifiers present in the ACL. 61 | * 62 | * This method will return an empty list if the job has 63 | * not yet been run. 64 | * 65 | * See the GetAclJob documentation for an explanation of 66 | * identifiers; in particular, identifiers starting with 67 | * '-' specify negative rights. 68 | */ 69 | [[nodiscard]] QList identifiers() const; 70 | /** 71 | * Check whether an identifier has a given right set 72 | * 73 | * The result of this method is undefined if the job has 74 | * not yet completed. 75 | * 76 | * See the GetAclJob documentation for an explanation of 77 | * identifiers; in particular, identifiers starting with 78 | * '-' specify negative rights. 79 | * 80 | * Note that this will not tell you whether the net result 81 | * of all the ACL entries means that a given user has 82 | * a certain right. 83 | * 84 | * @param identifier the identifier to check the rights for 85 | * @param right the right to check for 86 | */ 87 | [[nodiscard]] bool hasRightEnabled(const QByteArray &identifier, Acl::Right right) const; 88 | /** 89 | * Get the rights associated with an identifier. 90 | * 91 | * The result of this method is undefined if the job has 92 | * not yet completed. 93 | * 94 | * See the GetAclJob documentation for an explanation of 95 | * identifiers; in particular, identifiers starting with 96 | * '-' specify negative rights. 97 | * 98 | * Note that this will not tell you the rights that a 99 | * given user will have once all the ACL entries have 100 | * been taken into account. 101 | * 102 | * @param identifier the identifier to check the rights for 103 | */ 104 | [[nodiscard]] Acl::Rights rights(const QByteArray &identifier) const; 105 | 106 | /** 107 | * Gets the full access control list. 108 | * 109 | * The result of this method is undefined if the job has 110 | * not yet completed. 111 | * 112 | * See the GetAclJob documentation for an explanation of 113 | * identifiers; in particular, identifiers starting with 114 | * '-' specify negative rights. 115 | */ 116 | [[nodiscard]] QMap allRights() const; 117 | 118 | protected: 119 | void doStart() override; 120 | void handleResponse(const Response &response) override; 121 | }; 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/getquotajob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "getquotajob.h" 8 | 9 | #include 10 | 11 | #include "quotajobbase_p.h" 12 | #include "response_p.h" 13 | #include "session_p.h" 14 | 15 | namespace KIMAP 16 | { 17 | class GetQuotaJobPrivate : public QuotaJobBasePrivate 18 | { 19 | public: 20 | GetQuotaJobPrivate(Session *session, const QString &name) 21 | : QuotaJobBasePrivate(session, name) 22 | { 23 | } 24 | ~GetQuotaJobPrivate() 25 | { 26 | } 27 | 28 | QByteArray root; 29 | }; 30 | } 31 | 32 | using namespace KIMAP; 33 | 34 | GetQuotaJob::GetQuotaJob(Session *session) 35 | : QuotaJobBase(*new GetQuotaJobPrivate(session, i18n("GetQuota"))) 36 | { 37 | } 38 | 39 | GetQuotaJob::~GetQuotaJob() 40 | { 41 | } 42 | 43 | void GetQuotaJob::doStart() 44 | { 45 | Q_D(GetQuotaJob); 46 | // XXX: [alexmerry, 2010-07-24]: should d->root be quoted properly? 47 | d->tags << d->sessionInternal()->sendCommand("GETQUOTA", '\"' + d->root + '\"'); 48 | } 49 | 50 | void GetQuotaJob::handleResponse(const Response &response) 51 | { 52 | Q_D(GetQuotaJob); 53 | if (handleErrorReplies(response) == NotHandled) { 54 | if (response.content.size() >= 4 && response.content[1].toString() == "QUOTA") { 55 | d->quota = d->readQuota(response.content[3]); 56 | } 57 | } 58 | } 59 | 60 | void GetQuotaJob::setRoot(const QByteArray &root) 61 | { 62 | Q_D(GetQuotaJob); 63 | d->root = root; 64 | } 65 | 66 | QByteArray GetQuotaJob::root() const 67 | { 68 | Q_D(const GetQuotaJob); 69 | return d->root; 70 | } 71 | 72 | #include "moc_getquotajob.cpp" 73 | -------------------------------------------------------------------------------- /src/getquotajob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "quotajobbase.h" 10 | 11 | namespace KIMAP 12 | { 13 | class Session; 14 | struct Message; 15 | class GetQuotaJobPrivate; 16 | 17 | /** 18 | * Gets resource limits for a quota root. 19 | * 20 | * Quotas are defined with respect to "resources" and "quota roots". 21 | * A resource is a numerical property that can be limited, such 22 | * as the octet size of all the messages in a mailbox, or the 23 | * number of messages in a mailbox. Each mailbox has one or more 24 | * quota roots, which are where the resource limits are defined. 25 | * A quota root may or may not be a mailbox name, and an empty 26 | * string is a valid quota root. All mailboxes with the same quota 27 | * root share the resource limits of the quota root. 28 | * 29 | * This job can only be run when the session is in the 30 | * authenticated (or selected) state. 31 | * 32 | * This job requires that the server supports the QUOTA 33 | * capability, defined in 34 | * RFC 2087. 35 | */ 36 | class KIMAP_EXPORT GetQuotaJob : public QuotaJobBase 37 | { 38 | Q_OBJECT 39 | Q_DECLARE_PRIVATE(GetQuotaJob) 40 | 41 | friend class SessionPrivate; 42 | 43 | public: 44 | explicit GetQuotaJob(Session *session); 45 | ~GetQuotaJob() override; 46 | 47 | /** 48 | * Set the quota root to get the resource limits for. 49 | * @param root the quota root to set 50 | * @see GetQuotaRootJob 51 | */ 52 | void setRoot(const QByteArray &root); 53 | /** 54 | * The quota root that resource limit information will be fetched for. 55 | */ 56 | [[nodiscard]] QByteArray root() const; 57 | 58 | protected: 59 | void doStart() override; 60 | void handleResponse(const Response &response) override; 61 | }; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/getquotarootjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "quotajobbase.h" 10 | 11 | namespace KIMAP 12 | { 13 | class Session; 14 | struct Message; 15 | class GetQuotaRootJobPrivate; 16 | 17 | /** 18 | * Gets the quota root and resource limits for a mailbox. 19 | * 20 | * Quotas are defined with respect to "resources" and "quota roots". 21 | * A resource is a numerical property that can be limited, such 22 | * as the octet size of all the messages in a mailbox, or the 23 | * number of messages in a mailbox. Each mailbox has one or more 24 | * quota roots, which are where the resource limits are defined. 25 | * A quota root may or may not be a mailbox name, and an empty 26 | * string is a valid quota root. All mailboxes with the same quota 27 | * root share the resource limits of the quota root. 28 | * 29 | * This job can only be run when the session is in the 30 | * authenticated (or selected) state. 31 | * 32 | * This job requires that the server supports the QUOTA 33 | * capability, defined in 34 | * RFC 2087. 35 | */ 36 | class KIMAP_EXPORT GetQuotaRootJob : public QuotaJobBase 37 | { 38 | Q_OBJECT 39 | Q_DECLARE_PRIVATE(GetQuotaRootJob) 40 | 41 | friend class SessionPrivate; 42 | 43 | public: 44 | explicit GetQuotaRootJob(Session *session); 45 | ~GetQuotaRootJob() override; 46 | 47 | /** 48 | * Set the mailbox to get the quota roots for. 49 | * 50 | * @param mailBox the name of an existing mailbox 51 | */ 52 | void setMailBox(const QString &mailBox); 53 | /** 54 | * The mailbox that the quota roots will be fetched for. 55 | */ 56 | [[nodiscard]] QString mailBox() const; 57 | 58 | /** 59 | * The quota roots for the mailbox. 60 | */ 61 | [[nodiscard]] QList roots() const; 62 | /** 63 | * Get the current usage for a resource. 64 | * 65 | * Note that if there is no limit for a resource, the 66 | * server will not provide information about resource 67 | * usage. 68 | * 69 | * @param root the quota root to get the resource usage for 70 | * @param resource the resource to get the usage for 71 | * @return the resource usage in appropriate units, or -1 72 | * if the usage is unknown or there is no 73 | * limit on the resource 74 | */ 75 | [[nodiscard]] qint64 usage(const QByteArray &root, const QByteArray &resource) const; 76 | /** 77 | * Get the current limit for a resource. 78 | * 79 | * @param root the quota root to get the resource limit for 80 | * @param resource the resource to get the limit for 81 | * @return the resource limit in appropriate units, or -1 82 | * if the limit is unknown or there is no 83 | * limit on the resource 84 | */ 85 | [[nodiscard]] qint64 limit(const QByteArray &root, const QByteArray &resource) const; 86 | 87 | /** 88 | * Get a map containing all resource usage figures for a quota root. 89 | * 90 | * @param root the quota root to get resource usage figures for 91 | * @return a map from resource names to usage figures 92 | */ 93 | [[nodiscard]] QMap allUsages(const QByteArray &root) const; 94 | /** 95 | * Get a map containing all resource limits for a quota root. 96 | * 97 | * @param root the quota root to get resource limits for 98 | * @return a map from resource names to limits 99 | */ 100 | [[nodiscard]] QMap allLimits(const QByteArray &root) const; 101 | 102 | protected: 103 | void doStart() override; 104 | void handleResponse(const Response &response) override; 105 | }; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/idjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2015 Christian Mollekopf 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "idjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "session_p.h" 14 | 15 | namespace KIMAP 16 | { 17 | class IdJobPrivate : public JobPrivate 18 | { 19 | public: 20 | IdJobPrivate(Session *session, const QString &name) 21 | : JobPrivate(session, name) 22 | { 23 | } 24 | ~IdJobPrivate() 25 | { 26 | } 27 | 28 | QMap fields; 29 | }; 30 | } 31 | 32 | using namespace KIMAP; 33 | 34 | IdJob::IdJob(Session *session) 35 | : Job(*new IdJobPrivate(session, i18n("Id"))) 36 | { 37 | } 38 | 39 | IdJob::~IdJob() 40 | { 41 | } 42 | 43 | void IdJob::setField(const QByteArray &name, const QByteArray &value) 44 | { 45 | Q_D(IdJob); 46 | d->fields.insert(name, value); 47 | } 48 | 49 | void IdJob::doStart() 50 | { 51 | Q_D(IdJob); 52 | QByteArray command = "ID"; 53 | command += " ("; 54 | 55 | QMapIterator i(d->fields); 56 | while (i.hasNext()) { 57 | i.next(); 58 | command += "\"" + i.key() + "\" \"" + i.value() + "\" "; 59 | } 60 | command.chop(1); 61 | command += ")"; 62 | d->tags << d->sessionInternal()->sendCommand(command); 63 | } 64 | 65 | void IdJob::handleResponse(const Response &response) 66 | { 67 | // Q_D(IdJob); 68 | if (handleErrorReplies(response) == NotHandled) { 69 | // Ignore the response 70 | } 71 | } 72 | 73 | #include "moc_idjob.cpp" 74 | -------------------------------------------------------------------------------- /src/idjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2015 Christian Mollekopf 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Message; 17 | class IdJobPrivate; 18 | 19 | /** 20 | * Reports client id. 21 | * 22 | * This job can be run in any open session. 23 | */ 24 | class KIMAP_EXPORT IdJob : public Job 25 | { 26 | Q_OBJECT 27 | Q_DECLARE_PRIVATE(IdJob) 28 | 29 | friend class SessionPrivate; 30 | 31 | public: 32 | IdJob(Session *session); 33 | ~IdJob() override; 34 | 35 | void setField(const QByteArray &name, const QByteArray &field); 36 | 37 | protected: 38 | void doStart() override; 39 | void handleResponse(const Response &response) override; 40 | }; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/idlejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "imapset.h" 12 | #include "job.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace KIMAP 18 | { 19 | class Session; 20 | struct Response; 21 | class IdleJobPrivate; 22 | 23 | /** 24 | * Idles the connection to the IMAP server. 25 | * 26 | * This job can be run while the client has no other use 27 | * for the connection, and the server will send updates 28 | * about the selected mailbox. 29 | * 30 | * Note that although the server may send a variety of 31 | * responses while the job is running (including EXPUNGE, 32 | * for example), only RECENT and EXISTS responses are 33 | * actually reported by this job. 34 | * 35 | * The job also processes updates in pairs - if the server 36 | * sends an EXISTS update but not a RECENT one (because 37 | * another client is changing the mailbox contents), this 38 | * job will not report the update. 39 | * 40 | * It only makes sense to run this job when the session is 41 | * in the selected state. 42 | * 43 | * This job requires that the server supports the IDLE 44 | * capability, defined in 45 | * RFC 2177. 46 | */ 47 | class KIMAP_EXPORT IdleJob : public Job 48 | { 49 | Q_OBJECT 50 | Q_DECLARE_PRIVATE(IdleJob) 51 | 52 | public: 53 | explicit IdleJob(Session *session); 54 | ~IdleJob() override; 55 | 56 | /** 57 | * The last mailbox status that was reported. 58 | * 59 | * This is just the session's selected mailbox. 60 | */ 61 | [[nodiscard]] QString lastMailBox() const; 62 | /** 63 | * The last message count that was reported. 64 | * 65 | * The server will send updates about the number of 66 | * messages in the mailbox when that number changes. 67 | * This is the last number it reported. 68 | * 69 | * @return the last message count the server reported, 70 | * or -1 if it has not reported a message count 71 | * since the job started. 72 | */ 73 | [[nodiscard]] int lastMessageCount() const; 74 | /** 75 | * The last recent message count that was reported. 76 | * 77 | * The server will send updates about the number of 78 | * messages in the mailbox that are tagged with \Recent 79 | * when that number changes. This is the last number it 80 | * reported. 81 | * 82 | * @return the last recent message count the server reported, 83 | * or -1 if it has not reported a recent message count 84 | * since the job started. 85 | */ 86 | [[nodiscard]] int lastRecentCount() const; 87 | 88 | public Q_SLOTS: 89 | /** 90 | * Stops the idle job. 91 | */ 92 | void stop(); 93 | 94 | Q_SIGNALS: 95 | /** 96 | * Signals that the server has notified that the total and 97 | * recent message counts have changed. 98 | * 99 | * @param job this object 100 | * @param mailBox the selected mailbox 101 | * @param messageCount the new total message count reported by the server 102 | * @param recentCount the new "recent message" count reported by the server 103 | */ 104 | void mailBoxStats(KIMAP::IdleJob *job, const QString &mailBox, int messageCount, int recentCount); 105 | 106 | /** 107 | * Signals that the server has notified that the some messages flags 108 | * have changed 109 | * 110 | * @param job this object 111 | * @param uid UID of message that has changed 112 | * @since 4.12 113 | */ 114 | void mailBoxMessageFlagsChanged(KIMAP::IdleJob *job, qint64 uid); 115 | 116 | protected: 117 | void doStart() override; 118 | void handleResponse(const Response &response) override; 119 | 120 | private: 121 | Q_PRIVATE_SLOT(d_func(), void emitStats()) 122 | Q_PRIVATE_SLOT(d_func(), void resetTimeout()) 123 | }; 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/job.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "job.h" 8 | #include "job_p.h" 9 | #include "response_p.h" 10 | #include "session_p.h" 11 | 12 | #include "kimap_debug.h" 13 | #include 14 | 15 | using namespace KIMAP; 16 | 17 | Job::Job(Session *session) 18 | : KJob(session) 19 | , d_ptr(new JobPrivate(session, i18n("Job"))) 20 | { 21 | } 22 | 23 | Job::Job(JobPrivate &dd) 24 | : KJob(dd.m_session) 25 | , d_ptr(&dd) 26 | { 27 | } 28 | 29 | Job::~Job() 30 | { 31 | delete d_ptr; 32 | } 33 | 34 | Session *Job::session() const 35 | { 36 | Q_D(const Job); 37 | return d->m_session; 38 | } 39 | 40 | void Job::start() 41 | { 42 | Q_D(Job); 43 | d->sessionInternal()->addJob(this); 44 | } 45 | 46 | void Job::handleResponse(const Response &response) 47 | { 48 | handleErrorReplies(response); 49 | } 50 | 51 | void Job::connectionLost() 52 | { 53 | setError(KJob::UserDefinedError); 54 | setErrorText(i18n("Connection to server lost.")); 55 | emitResult(); 56 | } 57 | 58 | Job::HandlerResponse Job::handleErrorReplies(const Response &response) 59 | { 60 | Q_D(Job); 61 | // qCDebug(KIMAP_LOG) << response.toString(); 62 | 63 | if (!response.content.isEmpty() && d->tags.contains(response.content.first().toString())) { 64 | if (response.content.size() < 2) { 65 | setErrorText(i18n("%1 failed, malformed reply from the server.", d->m_name)); 66 | } else if (response.content[1].toString() != "OK") { 67 | setError(UserDefinedError); 68 | setErrorText(i18n("%1 failed, server replied: %2", d->m_name, QLatin1StringView(response.toString().constData()))); 69 | } 70 | d->tags.removeAll(response.content.first().toString()); 71 | if (d->tags.isEmpty()) { // Only emit result when the last command returned 72 | emitResult(); 73 | } 74 | return Handled; 75 | } 76 | 77 | return NotHandled; 78 | } 79 | 80 | #include "moc_job.cpp" 81 | -------------------------------------------------------------------------------- /src/job.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class SessionPrivate; 17 | class JobPrivate; 18 | struct Response; 19 | 20 | class KIMAP_EXPORT Job : public KJob 21 | { 22 | Q_OBJECT 23 | Q_DECLARE_PRIVATE(Job) 24 | 25 | friend class SessionPrivate; 26 | 27 | public: 28 | ~Job() override; 29 | 30 | Session *session() const; 31 | 32 | void start() override; 33 | 34 | private: 35 | virtual void doStart() = 0; 36 | virtual void handleResponse(const Response &response); 37 | virtual void connectionLost(); 38 | 39 | protected: 40 | enum HandlerResponse { 41 | Handled = 0, 42 | NotHandled 43 | }; 44 | 45 | HandlerResponse handleErrorReplies(const Response &response); 46 | 47 | explicit Job(Session *session); 48 | explicit Job(JobPrivate &dd); 49 | 50 | JobPrivate *const d_ptr; 51 | }; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/job_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "session.h" 10 | #include 11 | 12 | namespace KIMAP 13 | { 14 | class SessionPrivate; 15 | 16 | class JobPrivate 17 | { 18 | public: 19 | JobPrivate(Session *session, const QString &name) 20 | : m_session(session) 21 | , m_name(name) 22 | { 23 | } 24 | virtual ~JobPrivate() 25 | { 26 | } 27 | 28 | inline SessionPrivate *sessionInternal() 29 | { 30 | return m_session->d; 31 | } 32 | 33 | inline const SessionPrivate *sessionInternal() const 34 | { 35 | return m_session->d; 36 | } 37 | 38 | void setSocketError(QAbstractSocket::SocketError error) 39 | { 40 | m_socketError = error; 41 | } 42 | 43 | QList tags; 44 | Session *m_session = nullptr; 45 | QString m_name; 46 | QAbstractSocket::SocketError m_socketError = QAbstractSocket::UnknownSocketError; 47 | }; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/listjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class ListJobPrivate; 18 | 19 | struct KIMAP_EXPORT MailBoxDescriptor { 20 | QString name; 21 | QChar separator; 22 | 23 | inline bool operator==(const MailBoxDescriptor &other) const 24 | { 25 | return other.name == name && other.separator == separator; 26 | } 27 | 28 | inline bool operator<(const MailBoxDescriptor &other) const 29 | { 30 | return other.name < name || (other.name == name && other.separator < separator); 31 | } 32 | }; 33 | 34 | class KIMAP_EXPORT ListJob : public Job 35 | { 36 | Q_OBJECT 37 | Q_DECLARE_PRIVATE(ListJob) 38 | 39 | friend class SessionPrivate; 40 | 41 | public: 42 | enum Option { 43 | NoOption = 0x0, /**< List only subscribed mailboxes. (Uses the LSUB IMAP command.) */ 44 | IncludeUnsubscribed, /**< List subscribed and unsubscribed mailboxes. (Uses the LIST IMAP command.) */ 45 | IncludeFolderRoleFlags /**< List subscribed and unsubscribed mailboxes with flags to identify standard mailboxes whose name may be localized. 46 | The server must support the XLIST extension. */ 47 | }; 48 | 49 | explicit ListJob(Session *session); 50 | ~ListJob() override; 51 | 52 | KIMAP_DEPRECATED void setIncludeUnsubscribed(bool include); 53 | KIMAP_DEPRECATED bool isIncludeUnsubscribed() const; 54 | 55 | void setOption(Option option); 56 | [[nodiscard]] Option option() const; 57 | 58 | void setQueriedNamespaces(const QList &namespaces); 59 | [[nodiscard]] QList queriedNamespaces() const; 60 | 61 | KIMAP_DEPRECATED QList mailBoxes() const; 62 | KIMAP_DEPRECATED QMap> flags() const; 63 | 64 | Q_SIGNALS: 65 | void mailBoxesReceived(const QList &descriptors, const QList> &flags); 66 | 67 | protected: 68 | void doStart() override; 69 | void handleResponse(const Response &response) override; 70 | 71 | private: 72 | Q_PRIVATE_SLOT(d_func(), void emitPendings()) 73 | 74 | /** 75 | * @brief Converts a mailbox descriptor's name to uppercase if it is the Inbox or an Inbox subfolder. 76 | * This is according to the RFC3501, 5.1. Mailbox Naming section. 77 | * 78 | * @param descriptor the descriptor to convert, conversion happens in place 79 | **/ 80 | void convertInboxName(KIMAP::MailBoxDescriptor &descriptor); 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/listrightsjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "listrightsjob.h" 8 | 9 | #include 10 | 11 | #include "acljobbase_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class ListRightsJobPrivate : public AclJobBasePrivate 19 | { 20 | public: 21 | ListRightsJobPrivate(Session *session, const QString &name) 22 | : AclJobBasePrivate(session, name) 23 | , defaultRights(Acl::None) 24 | { 25 | } 26 | ~ListRightsJobPrivate() 27 | { 28 | } 29 | 30 | QList possibleRights; 31 | Acl::Rights defaultRights; 32 | }; 33 | } 34 | 35 | using namespace KIMAP; 36 | 37 | ListRightsJob::ListRightsJob(Session *session) 38 | : AclJobBase(*new ListRightsJobPrivate(session, i18n("ListRights"))) 39 | { 40 | } 41 | 42 | ListRightsJob::~ListRightsJob() 43 | { 44 | } 45 | 46 | void ListRightsJob::doStart() 47 | { 48 | Q_D(ListRightsJob); 49 | 50 | d->tags << d->sessionInternal()->sendCommand("LISTRIGHTS", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" \"" + d->id + "\""); 51 | } 52 | 53 | void ListRightsJob::handleResponse(const Response &response) 54 | { 55 | Q_D(ListRightsJob); 56 | 57 | if (handleErrorReplies(response) == NotHandled) { 58 | if (response.content.size() >= 4 && response.content[1].toString() == "LISTRIGHTS") { 59 | QByteArray s = response.content[4].toString(); 60 | d->defaultRights = Acl::rightsFromString(s); 61 | int i = 5; 62 | while (i < response.content.size()) { 63 | s = response.content[i].toString(); 64 | d->possibleRights.append(Acl::rightsFromString(s)); 65 | i++; 66 | } 67 | } 68 | } 69 | } 70 | 71 | void ListRightsJob::setIdentifier(const QByteArray &identifier) 72 | { 73 | Q_D(ListRightsJob); 74 | d->setIdentifier(identifier); 75 | } 76 | 77 | QByteArray ListRightsJob::identifier() 78 | { 79 | Q_D(ListRightsJob); 80 | return d->identifier(); 81 | } 82 | 83 | Acl::Rights ListRightsJob::defaultRights() 84 | { 85 | Q_D(ListRightsJob); 86 | return d->defaultRights; 87 | } 88 | 89 | QList ListRightsJob::possibleRights() 90 | { 91 | Q_D(ListRightsJob); 92 | return d->possibleRights; 93 | } 94 | 95 | #include "moc_listrightsjob.cpp" 96 | -------------------------------------------------------------------------------- /src/listrightsjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acljobbase.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class ListRightsJobPrivate; 18 | 19 | /** 20 | * Lists the possible and automatic rights for 21 | * an identifier on a mailbox 22 | * 23 | * This job can only be run when the session is in the 24 | * authenticated (or selected) state. 25 | * 26 | * The user must have the Acl::Admin permission 27 | * on the mailbox for this job to succeed (see 28 | * MyRightsJob). 29 | * 30 | * This job requires that the server supports the ACL 31 | * capability, defined in 32 | * RFC 4314. 33 | */ 34 | class KIMAP_EXPORT ListRightsJob : public AclJobBase 35 | { 36 | Q_OBJECT 37 | Q_DECLARE_PRIVATE(ListRightsJob) 38 | 39 | friend class SessionPrivate; 40 | 41 | public: 42 | explicit ListRightsJob(Session *session); 43 | ~ListRightsJob() override; 44 | 45 | /** 46 | * Sets the identifier that should be looked up 47 | * 48 | * The meaning of identifiers depends on the server implementation, 49 | * with the following restrictions: 50 | * 51 | * - "anyone" means any authenticated user, including anonymous 52 | * - an identifier starting with a minus sign ('-') indicates 53 | * "negative rights": rights that should be taken away from 54 | * matching users 55 | * 56 | * Other than the above restrictions, ACL identifiers are usually 57 | * IMAP usernames, but could potentially be group names as well. 58 | * 59 | * Note that negative rights override positive rights: if 60 | * "fred" and "-fred" are both assigned the 'w' right, the 61 | * user "fred" will not have the 'w' right. 62 | * 63 | * @param identifier the identifier to list the rights for 64 | */ 65 | void setIdentifier(const QByteArray &identifier); 66 | /** 67 | * The identifier that will be looked up 68 | */ 69 | [[nodiscard]] QByteArray identifier(); 70 | 71 | /** 72 | * The rights that will always be assigned to the identifier, 73 | * regardless of the access control list. 74 | * 75 | * For example, under the UNIX permission model, the owner 76 | * of a mailbox will always have the Acl::Admin right. 77 | */ 78 | [[nodiscard]] Acl::Rights defaultRights(); 79 | 80 | /** 81 | * The rights it is possible to assign to the identifier. 82 | * 83 | * The rights are grouped by those that are tied together. 84 | * For each set of rights in the returned list, either all 85 | * or none of those rights may be set, but not only some of 86 | * them. 87 | * 88 | * For example, under the UNIX permission model, the following 89 | * rights are all controlled by the "write" flag, and hence 90 | * must either all be set or all be not set: 91 | * - Acl::KeepSeen 92 | * - Acl::Write 93 | * - Acl::Insert 94 | * - Acl::DeleteMessage 95 | * - Acl::Expunge 96 | */ 97 | [[nodiscard]] QList possibleRights(); 98 | 99 | protected: 100 | void doStart() override; 101 | void handleResponse(const Response &response) override; 102 | }; 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/loginjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | SPDX-FileCopyrightText: 2009 Andras Mantia 4 | 5 | SPDX-License-Identifier: LGPL-2.0-or-later 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "kimap_export.h" 11 | 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Response; 18 | class LoginJobPrivate; 19 | 20 | class KIMAP_EXPORT LoginJob : public Job 21 | { 22 | Q_OBJECT 23 | Q_DECLARE_PRIVATE(LoginJob) 24 | 25 | friend class SessionPrivate; 26 | 27 | public: 28 | enum EncryptionMode { 29 | Unencrypted = 0, 30 | SSLorTLS, /*!< Use SSL/TLS encryption, KIMAP will automatically negotiate 31 | the best supported encryption protocol. */ 32 | STARTTLS /*!< Use STARTTLS to upgrade an initially plaintext connection to 33 | encrypted connection. KIMAP will automatically negotiate 34 | the best supported encryption protocol. */ 35 | }; 36 | Q_ENUM(EncryptionMode) 37 | 38 | enum AuthenticationMode { 39 | ClearText = 0, 40 | Login, 41 | Plain, 42 | CramMD5, 43 | DigestMD5, 44 | NTLM, 45 | GSSAPI, 46 | Anonymous, 47 | XOAuth2, 48 | }; 49 | Q_ENUM(AuthenticationMode) 50 | 51 | enum ErrorCode { 52 | ERR_COULD_NOT_CONNECT = KJob::UserDefinedError + 23 // same as in kio 53 | }; 54 | 55 | explicit LoginJob(Session *session); 56 | ~LoginJob() override; 57 | 58 | [[nodiscard]] QString userName() const; 59 | void setUserName(const QString &userName); 60 | 61 | /** 62 | * Get the authorization identity. 63 | * @since 4.10 64 | */ 65 | [[nodiscard]] QString authorizationName() const; 66 | 67 | /** 68 | * Set the authorization identity. 69 | * 70 | * If set, proxy-authentication according to RFC4616 will be used. 71 | * 72 | * Note that this feature only works with the "PLAIN" AuthenticationMode. 73 | * 74 | * The @param authorizationName will be used together with the password() to get authenticated as userName() by the authorization of the provided 75 | * credentials. This allows to login as a user using the admin credentials and the users name. 76 | * @since 4.10 77 | */ 78 | void setAuthorizationName(const QString &authorizationName); 79 | 80 | [[nodiscard]] QString password() const; 81 | void setPassword(const QString &password); 82 | 83 | /** 84 | * Returns the server greeting, in case of a successful login. 85 | * If the login wasn't successful, this method returns an empty string. Use errorString() to 86 | * get the error message in this case. 87 | * 88 | * Note that the content of this response is not defined by the IMAP protocol and is 89 | * implementation-dependent. 90 | * @since 4.7 91 | */ 92 | [[nodiscard]] QString serverGreeting() const; 93 | 94 | /** 95 | * Set the encryption mode for the connection. In case an encryption mode is set, the caller 96 | * MUST check the encryptionMode() result after executing the job, to see if the connection is 97 | * encrypted or not (e.g handshaking failed). 98 | * @param mode the encryption mode, see EncryptionModes 99 | */ 100 | void setEncryptionMode(EncryptionMode mode); 101 | 102 | /** 103 | Get the encryption mode. 104 | @return the currently active encryption mode 105 | */ 106 | [[nodiscard]] EncryptionMode encryptionMode(); 107 | 108 | void setAuthenticationMode(AuthenticationMode mode); 109 | 110 | protected: 111 | void doStart() override; 112 | void handleResponse(const Response &response) override; 113 | void connectionLost() override; 114 | 115 | private: 116 | Q_PRIVATE_SLOT(d_func(), void sslResponse(bool)) 117 | }; 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/logoutjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "logoutjob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "session_p.h" 14 | 15 | namespace KIMAP 16 | { 17 | class LogoutJobPrivate : public JobPrivate 18 | { 19 | public: 20 | LogoutJobPrivate(Session *session, const QString &name) 21 | : JobPrivate(session, name) 22 | { 23 | } 24 | ~LogoutJobPrivate() 25 | { 26 | } 27 | }; 28 | } 29 | 30 | using namespace KIMAP; 31 | 32 | LogoutJob::LogoutJob(Session *session) 33 | : Job(*new LogoutJobPrivate(session, i18n("Logout"))) 34 | { 35 | } 36 | 37 | LogoutJob::~LogoutJob() 38 | { 39 | } 40 | 41 | void LogoutJob::doStart() 42 | { 43 | Q_D(LogoutJob); 44 | d->tags << d->sessionInternal()->sendCommand("LOGOUT"); 45 | } 46 | 47 | void LogoutJob::connectionLost() 48 | { 49 | emitResult(); 50 | } 51 | 52 | #include "moc_logoutjob.cpp" 53 | -------------------------------------------------------------------------------- /src/logoutjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class LogoutJobPrivate; 17 | 18 | class KIMAP_EXPORT LogoutJob : public Job 19 | { 20 | Q_OBJECT 21 | Q_DECLARE_PRIVATE(LogoutJob) 22 | 23 | friend class SessionPrivate; 24 | 25 | public: 26 | explicit LogoutJob(Session *session); 27 | ~LogoutJob() override; 28 | 29 | protected: 30 | void doStart() override; 31 | void connectionLost() override; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/metadatajobbase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "metadatajobbase.h" 8 | #include "metadatajobbase_p.h" 9 | #include "response_p.h" 10 | #include "session_p.h" 11 | 12 | #include 13 | 14 | using namespace KIMAP; 15 | 16 | QByteArray MetaDataJobBasePrivate::addPrefix(const QByteArray &entry, const QByteArray &attribute) const 17 | { 18 | if (serverCapability == MetaDataJobBase::Annotatemore) { 19 | if (attribute == "value.shared") { 20 | return QByteArray("/shared").append(entry); 21 | } else if (attribute == "value.priv") { 22 | return QByteArray("/private").append(entry); 23 | } 24 | } 25 | return entry; 26 | } 27 | 28 | QByteArray MetaDataJobBasePrivate::removePrefix(const QByteArray &entry) const 29 | { 30 | if (serverCapability == MetaDataJobBase::Annotatemore) { 31 | if (entry.startsWith("/shared")) { 32 | return entry.mid(QByteArray("/shared").size()); 33 | } else if (entry.startsWith("/private")) { 34 | return entry.mid(QByteArray("/private").size()); 35 | } 36 | } 37 | return entry; 38 | } 39 | 40 | QByteArray MetaDataJobBasePrivate::getAttribute(const QByteArray &entry) const 41 | { 42 | if (serverCapability == MetaDataJobBase::Annotatemore) { 43 | if (entry.startsWith("/shared")) { 44 | return QByteArray("value.shared"); 45 | } else if (entry.startsWith("/private")) { 46 | return QByteArray("value.priv"); 47 | } 48 | } 49 | return QByteArray(); 50 | } 51 | 52 | MetaDataJobBase::MetaDataJobBase(Session *session) 53 | : Job(*new MetaDataJobBasePrivate(session, i18n("MetaDataJobBase"))) 54 | { 55 | } 56 | 57 | MetaDataJobBase::MetaDataJobBase(JobPrivate &dd) 58 | : Job(dd) 59 | { 60 | } 61 | 62 | MetaDataJobBase::~MetaDataJobBase() 63 | { 64 | } 65 | 66 | void MetaDataJobBase::setMailBox(const QString &mailBox) 67 | { 68 | Q_D(MetaDataJobBase); 69 | d->mailBox = mailBox; 70 | } 71 | 72 | QString MetaDataJobBase::mailBox() const 73 | { 74 | Q_D(const MetaDataJobBase); 75 | return d->mailBox; 76 | } 77 | 78 | void MetaDataJobBase::setServerCapability(ServerCapability capability) 79 | { 80 | Q_D(MetaDataJobBase); 81 | d->serverCapability = capability; 82 | } 83 | 84 | MetaDataJobBase::ServerCapability MetaDataJobBase::serverCapability() const 85 | { 86 | Q_D(const MetaDataJobBase); 87 | return d->serverCapability; 88 | } 89 | 90 | #include "moc_metadatajobbase.cpp" 91 | -------------------------------------------------------------------------------- /src/metadatajobbase.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class MetaDataJobBasePrivate; 18 | 19 | /** 20 | * Base class for jobs that operate on mailbox metadata 21 | * 22 | * Provides support for the IMAP METADATA extension; both the 23 | * final RFC version 24 | * (RFC 5464) 25 | * and the older, incompatible draft version (known as ANNOTATEMORE) 26 | * (draft-daboo-imap-annotatemore-07). 29 | * 30 | * This class cannot be used directly, you must subclass it and reimplement 31 | * at least the doStart() method. 32 | */ 33 | class KIMAP_EXPORT MetaDataJobBase : public Job 34 | { 35 | Q_OBJECT 36 | Q_DECLARE_PRIVATE(MetaDataJobBase) 37 | 38 | friend class SessionPrivate; 39 | 40 | public: 41 | explicit MetaDataJobBase(Session *session); 42 | ~MetaDataJobBase() override; 43 | 44 | /** 45 | * Represents the capability level of the server. 46 | */ 47 | enum ServerCapability { 48 | /** 49 | * Used to indicate that the server supports the RFC 5464 version 50 | * of the extension. 51 | * 52 | * This corresponds to the METADATA server capability. 53 | */ 54 | Metadata = 0, 55 | /** 56 | * Used to indicate that the server supports the 57 | * draft-daboo-imap-annotatemore-07 version of the extension. 58 | * 59 | * This corresponds to the ANNOTATEMORE server capability. 60 | */ 61 | Annotatemore 62 | }; 63 | 64 | /** 65 | * Set the mailbox to act on 66 | * 67 | * This may be an empty string, in which case metadata for the 68 | * server (rather than a specific mailbox) will be retrieved. 69 | * 70 | * @param mailBox the name of an existing mailbox, or an empty string 71 | */ 72 | void setMailBox(const QString &mailBox); 73 | /** 74 | * The mailbox that will be acted upon. 75 | * 76 | * If this is an empty string, server metadata will be retrieved. 77 | * 78 | * @return a mailbox name, or an empty string 79 | */ 80 | [[nodiscard]] QString mailBox() const; 81 | 82 | /** 83 | * Set what version of the metadata extension to be compatible with. 84 | * 85 | * This will determine the commands that will be sent to the server. 86 | * 87 | * The draft for the metadata extension changed in an incompatible 88 | * way between versions 7 and 8, and some servers support version 7. 89 | * It should be possible to check which version the server supports 90 | * using CapabilityJob: servers implementing 91 | * draft-daboo-imap-annotatemore-07 should advertise the 92 | * ANNOTATEMORE capability, whereas servers implementing the final 93 | * RFC 5464 should advertise the METADATA capability. 94 | * 95 | * The default mode is Metadata. 96 | * 97 | * @param capability the version of the extension implemented by the server 98 | */ 99 | void setServerCapability(ServerCapability capability); 100 | /** 101 | * The version of the metadata extension that will be used. 102 | */ 103 | [[nodiscard]] ServerCapability serverCapability() const; 104 | 105 | protected: 106 | MetaDataJobBase(JobPrivate &dd); 107 | }; 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/metadatajobbase_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "job_p.h" 10 | #include "metadatajobbase.h" 11 | #include "response_p.h" 12 | #include "session.h" 13 | 14 | namespace KIMAP 15 | { 16 | class MetaDataJobBasePrivate : public JobPrivate 17 | { 18 | public: 19 | MetaDataJobBasePrivate(Session *session, const QString &name) 20 | : JobPrivate(session, name) 21 | , serverCapability(MetaDataJobBase::Metadata) 22 | { 23 | } 24 | 25 | ~MetaDataJobBasePrivate() 26 | { 27 | } 28 | 29 | QByteArray addPrefix(const QByteArray &entry, const QByteArray &attribute) const; 30 | QByteArray removePrefix(const QByteArray &) const; 31 | 32 | QByteArray getAttribute(const QByteArray &entry) const; 33 | 34 | MetaDataJobBase::ServerCapability serverCapability; 35 | QString mailBox; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/movejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "movejob.h" 8 | 9 | #include "job_p.h" 10 | #include "response_p.h" 11 | #include "rfccodecs.h" 12 | #include "session_p.h" 13 | 14 | #include 15 | 16 | // TODO: when custom error codes are introduced, handle the NO [TRYCREATE] response 17 | 18 | namespace KIMAP 19 | { 20 | class MoveJobPrivate : public JobPrivate 21 | { 22 | public: 23 | MoveJobPrivate(Session *session, const QString &name) 24 | : JobPrivate(session, name) 25 | { 26 | } 27 | 28 | ~MoveJobPrivate() 29 | { 30 | } 31 | 32 | QString mailBox; 33 | ImapSet set; 34 | ImapSet resultingUids; 35 | bool uidBased = false; 36 | }; 37 | } 38 | 39 | using namespace KIMAP; 40 | 41 | MoveJob::MoveJob(Session *session) 42 | : Job(*new MoveJobPrivate(session, i18n("Move"))) 43 | { 44 | Q_D(MoveJob); 45 | d->uidBased = false; 46 | } 47 | 48 | MoveJob::~MoveJob() 49 | { 50 | } 51 | 52 | void MoveJob::setMailBox(const QString &mailBox) 53 | { 54 | Q_D(MoveJob); 55 | d->mailBox = mailBox; 56 | } 57 | 58 | QString MoveJob::mailBox() const 59 | { 60 | Q_D(const MoveJob); 61 | return d->mailBox; 62 | } 63 | 64 | void MoveJob::setSequenceSet(const ImapSet &set) 65 | { 66 | Q_D(MoveJob); 67 | d->set = set; 68 | } 69 | 70 | ImapSet MoveJob::sequenceSet() const 71 | { 72 | Q_D(const MoveJob); 73 | return d->set; 74 | } 75 | 76 | void MoveJob::setUidBased(bool uidBased) 77 | { 78 | Q_D(MoveJob); 79 | d->uidBased = uidBased; 80 | } 81 | 82 | bool MoveJob::isUidBased() const 83 | { 84 | Q_D(const MoveJob); 85 | return d->uidBased; 86 | } 87 | 88 | ImapSet MoveJob::resultingUids() const 89 | { 90 | Q_D(const MoveJob); 91 | return d->resultingUids; 92 | } 93 | 94 | void MoveJob::doStart() 95 | { 96 | Q_D(MoveJob); 97 | 98 | d->set.optimize(); 99 | QByteArray parameters = d->set.toImapSequenceSet() + ' '; 100 | parameters += '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'; 101 | 102 | QByteArray command = "MOVE"; 103 | if (d->uidBased) { 104 | command = "UID " + command; 105 | } 106 | 107 | d->tags << d->sessionInternal()->sendCommand(command, parameters); 108 | } 109 | 110 | void MoveJob::handleResponse(const Response &response) 111 | { 112 | Q_D(MoveJob); 113 | 114 | for (auto it = response.responseCode.cbegin(), end = response.responseCode.cend(); it != end; ++it) { 115 | if (it->toString() == "COPYUID") { 116 | it = it + 3; 117 | if (it < end) { 118 | d->resultingUids = ImapSet::fromImapSequenceSet(it->toString()); 119 | } 120 | break; 121 | } 122 | } 123 | 124 | handleErrorReplies(response); 125 | } 126 | 127 | #include "moc_movejob.cpp" 128 | -------------------------------------------------------------------------------- /src/movejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "imapset.h" 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class MoveJobPrivate; 17 | 18 | /** 19 | * Moves messages from current mailbox to another 20 | * 21 | * Note that move functionality is not specified in the base IMAP 22 | * protocol and is defined as an extension in RFC6851. That means 23 | * that the MoveJob can only be used when the server lists "MOVE" 24 | * in response to CAPABILITY command. 25 | * 26 | * Unlike the traditional emulation of moving messages, i.e. COPY + STORE + EXPUNGE, 27 | * MOVE guarantees the transaction to be atomic on the server. 28 | * 29 | * @since 5.4 30 | */ 31 | class KIMAP_EXPORT MoveJob : public Job 32 | { 33 | Q_OBJECT 34 | Q_DECLARE_PRIVATE(MoveJob) 35 | 36 | friend class SessionPrivate; 37 | 38 | public: 39 | explicit MoveJob(Session *session); 40 | ~MoveJob() override; 41 | 42 | /** 43 | * Set the destination mailbox 44 | * 45 | * If the mailbox does not exist, the server should not create 46 | * it automatically and the job should fail. Note, however, 47 | * that a conforming server may create the mailbox automatically. 48 | * 49 | * @param mailBox the (unquoted) name of the mailbox where the 50 | * messages should be moved to 51 | */ 52 | void setMailBox(const QString &mailbox); 53 | /** 54 | * The destination mailbox 55 | */ 56 | [[nodiscard]] QString mailBox() const; 57 | 58 | /** 59 | * Sets the messages to be moved, 60 | * 61 | * If sequence numbers are given, isUidBased() should be false. If UIDs 62 | * are given, isUidBased() should be true. 63 | * 64 | * @param set the sequence numbers or UIDs of the messages to be moved 65 | */ 66 | void setSequenceSet(const ImapSet &set); 67 | /** 68 | * The messages that will be moved. 69 | * 70 | * isUidBased() can be used to check whether the ImapSet contains 71 | * sequence numbers or UIDs. 72 | * 73 | * @return the sequence numbers or UIDs of the messages to be moved 74 | */ 75 | [[nodiscard]] ImapSet sequenceSet() const; 76 | 77 | /** 78 | * Set how the sequence set should be interpreted. 79 | * 80 | * @param uidBased if @c true the argument to setSequenceSet will be 81 | * interpreted as UIDs, if @c false it will be interpreted 82 | * as sequence numbers 83 | */ 84 | void setUidBased(bool uidBased); 85 | /** 86 | * How to interpret the sequence set. 87 | * 88 | * @return if @c true the result of sequenceSet() should be 89 | * interpreted as UIDs, if @c false it should be interpreted 90 | * as sequence numbers 91 | */ 92 | [[nodiscard]] bool isUidBased() const; 93 | 94 | /** 95 | * The UIDs of the moved messages in the destination mailbox. 96 | * 97 | * This will be an empty set if no messages have been moved yet 98 | * or if the server does not support the UIDPLUS extension. 99 | */ 100 | [[nodiscard]] ImapSet resultingUids() const; 101 | 102 | protected: 103 | void doStart() override; 104 | void handleResponse(const Response &response) override; 105 | }; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/myrightsjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "myrightsjob.h" 8 | 9 | #include 10 | 11 | #include "acljobbase_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class MyRightsJobPrivate : public AclJobBasePrivate 19 | { 20 | public: 21 | MyRightsJobPrivate(Session *session, const QString &name) 22 | : AclJobBasePrivate(session, name) 23 | , myRights(Acl::None) 24 | { 25 | } 26 | ~MyRightsJobPrivate() 27 | { 28 | } 29 | 30 | Acl::Rights myRights; 31 | }; 32 | } 33 | 34 | using namespace KIMAP; 35 | 36 | MyRightsJob::MyRightsJob(Session *session) 37 | : AclJobBase(*new MyRightsJobPrivate(session, i18n("MyRights"))) 38 | { 39 | } 40 | 41 | MyRightsJob::~MyRightsJob() 42 | { 43 | } 44 | 45 | void MyRightsJob::doStart() 46 | { 47 | Q_D(MyRightsJob); 48 | 49 | d->tags << d->sessionInternal()->sendCommand("MYRIGHTS", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 50 | } 51 | 52 | void MyRightsJob::handleResponse(const Response &response) 53 | { 54 | Q_D(MyRightsJob); 55 | 56 | if (handleErrorReplies(response) == NotHandled) { 57 | if (response.content.size() == 4 && response.content[1].toString() == "MYRIGHTS") { 58 | d->myRights = Acl::rightsFromString(response.content[3].toString()); 59 | } 60 | } 61 | } 62 | 63 | bool MyRightsJob::hasRightEnabled(Acl::Right right) 64 | { 65 | Q_D(MyRightsJob); 66 | return d->myRights & right; 67 | } 68 | 69 | Acl::Rights MyRightsJob::rights() 70 | { 71 | Q_D(MyRightsJob); 72 | return d->myRights; 73 | } 74 | 75 | #include "moc_myrightsjob.cpp" 76 | -------------------------------------------------------------------------------- /src/myrightsjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acljobbase.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class MyRightsJobPrivate; 18 | 19 | /** 20 | * Determine the rights the currently-logged-in user 21 | * has on the current mailbox. 22 | * 23 | * This should take into account the full access control 24 | * list. 25 | * 26 | * This job can only be run when the session is in the 27 | * authenticated (or selected) state. 28 | * 29 | * The current user must have one of the following rights 30 | * on the mailbox for this job to succeed: 31 | * - Acl::Lookup 32 | * - Acl::Read 33 | * - Acl::Insert 34 | * - Acl::CreateMailbox 35 | * - Acl::DeleteMailbox 36 | * - Acl::Admin 37 | * 38 | * This job requires that the server supports the ACL 39 | * capability, defined in 40 | * RFC 4314. 41 | */ 42 | class KIMAP_EXPORT MyRightsJob : public AclJobBase 43 | { 44 | Q_OBJECT 45 | Q_DECLARE_PRIVATE(MyRightsJob) 46 | 47 | friend class SessionPrivate; 48 | 49 | public: 50 | explicit MyRightsJob(Session *session); 51 | ~MyRightsJob() override; 52 | 53 | /** 54 | * Check whether the current user has the a particular right 55 | * on the mailbox. 56 | * 57 | * The result of this method is undefined if the job has 58 | * not yet completed. 59 | * 60 | * @param right the right to check for 61 | */ 62 | [[nodiscard]] bool hasRightEnabled(Acl::Right right); 63 | /** 64 | * Get the rights for the current user on the mailbox. 65 | * 66 | * The result of this method is undefined if the job has 67 | * not yet completed. 68 | */ 69 | [[nodiscard]] Acl::Rights rights(); 70 | 71 | protected: 72 | void doStart() override; 73 | void handleResponse(const Response &response) override; 74 | }; 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/namespacejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "namespacejob.h" 8 | 9 | #include "kimap_debug.h" 10 | #include 11 | 12 | #include "imapstreamparser.h" 13 | #include "job_p.h" 14 | #include "listjob.h" 15 | #include "response_p.h" 16 | #include "rfccodecs.h" 17 | #include "session_p.h" 18 | 19 | namespace KIMAP 20 | { 21 | class NamespaceJobPrivate : public JobPrivate 22 | { 23 | public: 24 | NamespaceJobPrivate(Session *session, const QString &name) 25 | : JobPrivate(session, name) 26 | { 27 | } 28 | ~NamespaceJobPrivate() 29 | { 30 | } 31 | 32 | QList processNamespaceList(const QList &namespaceList) 33 | { 34 | QList result; 35 | 36 | for (const QByteArray &namespaceItem : namespaceList) { 37 | ImapStreamParser parser(nullptr); 38 | parser.setData(namespaceItem); 39 | 40 | try { 41 | QList parts = parser.readParenthesizedList(); 42 | if (parts.size() < 2) { 43 | continue; 44 | } 45 | MailBoxDescriptor descriptor; 46 | descriptor.name = QString::fromUtf8(decodeImapFolderName(parts[0])); 47 | descriptor.separator = QLatin1Char(parts[1][0]); 48 | 49 | result << descriptor; 50 | } catch (const KIMAP::ImapParserException &e) { 51 | qCWarning(KIMAP_LOG) << "The stream parser raised an exception during namespace list parsing:" << e.what(); 52 | qCWarning(KIMAP_LOG) << "namespacelist:" << namespaceList; 53 | } 54 | } 55 | 56 | return result; 57 | } 58 | 59 | QList personalNamespaces; 60 | QList userNamespaces; 61 | QList sharedNamespaces; 62 | }; 63 | } 64 | 65 | using namespace KIMAP; 66 | 67 | NamespaceJob::NamespaceJob(Session *session) 68 | : Job(*new NamespaceJobPrivate(session, i18n("Namespace"))) 69 | { 70 | } 71 | 72 | NamespaceJob::~NamespaceJob() 73 | { 74 | } 75 | 76 | QList NamespaceJob::personalNamespaces() const 77 | { 78 | Q_D(const NamespaceJob); 79 | return d->personalNamespaces; 80 | } 81 | 82 | QList NamespaceJob::userNamespaces() const 83 | { 84 | Q_D(const NamespaceJob); 85 | return d->userNamespaces; 86 | } 87 | 88 | QList NamespaceJob::sharedNamespaces() const 89 | { 90 | Q_D(const NamespaceJob); 91 | return d->sharedNamespaces; 92 | } 93 | 94 | bool NamespaceJob::containsEmptyNamespace() const 95 | { 96 | Q_D(const NamespaceJob); 97 | const QList completeList = d->personalNamespaces + d->userNamespaces + d->sharedNamespaces; 98 | 99 | for (const MailBoxDescriptor &descriptor : completeList) { 100 | if (descriptor.name.isEmpty()) { 101 | return true; 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | 108 | void NamespaceJob::doStart() 109 | { 110 | Q_D(NamespaceJob); 111 | d->tags << d->sessionInternal()->sendCommand("NAMESPACE"); 112 | } 113 | 114 | void NamespaceJob::handleResponse(const Response &response) 115 | { 116 | Q_D(NamespaceJob); 117 | if (handleErrorReplies(response) == NotHandled) { 118 | if (response.content.size() >= 5 && response.content[1].toString() == "NAMESPACE") { 119 | // Personal namespaces 120 | d->personalNamespaces = d->processNamespaceList(response.content[2].toList()); 121 | 122 | // User namespaces 123 | d->userNamespaces = d->processNamespaceList(response.content[3].toList()); 124 | 125 | // Shared namespaces 126 | d->sharedNamespaces = d->processNamespaceList(response.content[4].toList()); 127 | } 128 | } 129 | } 130 | 131 | #include "moc_namespacejob.cpp" 132 | -------------------------------------------------------------------------------- /src/namespacejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | struct MailBoxDescriptor; 18 | class NamespaceJobPrivate; 19 | 20 | class KIMAP_EXPORT NamespaceJob : public Job 21 | { 22 | Q_OBJECT 23 | Q_DECLARE_PRIVATE(NamespaceJob) 24 | 25 | friend class SessionPrivate; 26 | 27 | public: 28 | NamespaceJob(Session *session); 29 | ~NamespaceJob() override; 30 | 31 | [[nodiscard]] QList personalNamespaces() const; 32 | [[nodiscard]] QList userNamespaces() const; 33 | [[nodiscard]] QList sharedNamespaces() const; 34 | 35 | [[nodiscard]] bool containsEmptyNamespace() const; 36 | 37 | protected: 38 | void doStart() override; 39 | void handleResponse(const Response &response) override; 40 | }; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/quotajobbase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "quotajobbase.h" 8 | #include "quotajobbase_p.h" 9 | #include "response_p.h" 10 | #include "session_p.h" 11 | 12 | #include 13 | 14 | using namespace KIMAP; 15 | 16 | QMap> QuotaJobBasePrivate::readQuota(const Response::Part &content) 17 | { 18 | QMap> quotaMap; 19 | QList quotas = content.toList(); 20 | 21 | int i = 0; 22 | while (i < quotas.size() - 2) { 23 | QByteArray resource = quotas[i].toUpper(); 24 | qint64 usage = quotas[i + 1].toInt(); 25 | qint64 limit = quotas[i + 2].toInt(); 26 | quotaMap[resource] = qMakePair(usage, limit); 27 | i += 3; 28 | } 29 | 30 | return quotaMap; 31 | } 32 | 33 | QuotaJobBase::QuotaJobBase(Session *session) 34 | : Job(*new QuotaJobBasePrivate(session, i18n("QuotaJobBase"))) 35 | { 36 | } 37 | 38 | QuotaJobBase::QuotaJobBase(JobPrivate &dd) 39 | : Job(dd) 40 | { 41 | } 42 | 43 | QuotaJobBase::~QuotaJobBase() 44 | { 45 | } 46 | 47 | qint64 QuotaJobBase::usage(const QByteArray &resource) 48 | { 49 | Q_D(QuotaJobBase); 50 | 51 | QByteArray r = resource.toUpper(); 52 | 53 | if (d->quota.contains(r)) { 54 | return d->quota[r].first; 55 | } 56 | return -1; 57 | } 58 | 59 | qint64 QuotaJobBase::limit(const QByteArray &resource) 60 | { 61 | Q_D(QuotaJobBase); 62 | 63 | QByteArray r = resource.toUpper(); 64 | 65 | if (d->quota.contains(r)) { 66 | return d->quota[r].second; 67 | } 68 | return -1; 69 | } 70 | 71 | #include "moc_quotajobbase.cpp" 72 | -------------------------------------------------------------------------------- /src/quotajobbase.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class QuotaJobBasePrivate; 18 | 19 | /** 20 | * Base class for jobs that operate on mailbox quotas 21 | * 22 | * Provides support for the IMAP QUOTA extension, as defined by 23 | * RFC 2087. 24 | * 25 | * This class cannot be used directly, you must subclass it and reimplement 26 | * at least the doStart() method. 27 | */ 28 | class KIMAP_EXPORT QuotaJobBase : public Job 29 | { 30 | Q_OBJECT 31 | Q_DECLARE_PRIVATE(QuotaJobBase) 32 | 33 | friend class SessionPrivate; 34 | 35 | public: 36 | explicit QuotaJobBase(Session *session); 37 | ~QuotaJobBase() override; 38 | 39 | /** 40 | * Get the current usage for a resource. 41 | * 42 | * All quota jobs will normally cause the server to return 43 | * details of resource usage for all resources that were 44 | * queried or modified by the job. 45 | * 46 | * Note that RFC 2087 is slightly ambiguous about whether 47 | * SETQUOTA will cause this information to be sent by the 48 | * server. 49 | * 50 | * Note that if there is no limit for a resource, the 51 | * server will not provide information about resource 52 | * usage. 53 | * 54 | * @param resource the resource to get the usage for 55 | * @return the resource usage in appropriate units, or -1 56 | * if the usage is unknown or there is no 57 | * limit on the resource 58 | */ 59 | [[nodiscard]] qint64 usage(const QByteArray &resource); 60 | /** 61 | * Get the current limit for a resource. 62 | * 63 | * All quota jobs will normally cause the server to return 64 | * details of resource limits for all resources that were 65 | * queried or modified by the job. 66 | * 67 | * Note that RFC 2087 is slightly ambiguous about whether 68 | * SETQUOTA will cause this information to be sent by the 69 | * server. 70 | * 71 | * @param resource the resource to get the limit for 72 | * @return the resource limit in appropriate units, or -1 73 | * if the limit is unknown or there is no limit 74 | * on the resource 75 | */ 76 | [[nodiscard]] qint64 limit(const QByteArray &resource); 77 | 78 | protected: 79 | QuotaJobBase(JobPrivate &dd); 80 | }; 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/quotajobbase_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "job_p.h" 10 | #include "response_p.h" 11 | #include "session.h" 12 | 13 | #include 14 | 15 | namespace KIMAP 16 | { 17 | class QuotaJobBasePrivate : public JobPrivate 18 | { 19 | public: 20 | QuotaJobBasePrivate(Session *session, const QString &name) 21 | : JobPrivate(session, name) 22 | { 23 | } 24 | 25 | ~QuotaJobBasePrivate() 26 | { 27 | } 28 | static QMap> readQuota(const Response::Part &content); 29 | 30 | QMap> quota; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/renamejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "renamejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class RenameJobPrivate : public JobPrivate 19 | { 20 | public: 21 | RenameJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~RenameJobPrivate() 26 | { 27 | } 28 | 29 | QString sourceMailBox; 30 | QString destinationMailBox; 31 | }; 32 | } 33 | 34 | using namespace KIMAP; 35 | 36 | RenameJob::RenameJob(Session *session) 37 | : Job(*new RenameJobPrivate(session, i18n("Rename"))) 38 | { 39 | } 40 | 41 | RenameJob::~RenameJob() 42 | { 43 | } 44 | 45 | void RenameJob::doStart() 46 | { 47 | Q_D(RenameJob); 48 | d->tags << d->sessionInternal()->sendCommand("RENAME", 49 | '\"' + KIMAP::encodeImapFolderName(d->sourceMailBox.toUtf8()) + "\" \"" 50 | + KIMAP::encodeImapFolderName(d->destinationMailBox.toUtf8()) + '\"'); 51 | } 52 | 53 | void RenameJob::setSourceMailBox(const QString &mailBox) 54 | { 55 | Q_D(RenameJob); 56 | d->sourceMailBox = mailBox; 57 | } 58 | 59 | QString RenameJob::sourceMailBox() const 60 | { 61 | Q_D(const RenameJob); 62 | return d->sourceMailBox; 63 | } 64 | 65 | void RenameJob::setDestinationMailBox(const QString &mailBox) 66 | { 67 | Q_D(RenameJob); 68 | d->destinationMailBox = mailBox; 69 | } 70 | 71 | QString RenameJob::destinationMailBox() const 72 | { 73 | Q_D(const RenameJob); 74 | return d->destinationMailBox; 75 | } 76 | 77 | #include "moc_renamejob.cpp" 78 | -------------------------------------------------------------------------------- /src/renamejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class RenameJobPrivate; 17 | 18 | class KIMAP_EXPORT RenameJob : public Job 19 | { 20 | Q_OBJECT 21 | Q_DECLARE_PRIVATE(RenameJob) 22 | 23 | friend class SessionPrivate; 24 | 25 | public: 26 | explicit RenameJob(Session *session); 27 | ~RenameJob() override; 28 | 29 | /** 30 | * Set the name of the mailbox that will be renamed. 31 | * @param mailBox the original name of the mailbox 32 | */ 33 | void setSourceMailBox(const QString &mailBox); 34 | [[nodiscard]] QString sourceMailBox() const; 35 | 36 | /** 37 | * The new name of the mailbox, see setMailBox. 38 | * @param mailBox the new mailbox name 39 | */ 40 | void setDestinationMailBox(const QString &mailBox); 41 | [[nodiscard]] QString destinationMailBox() const; 42 | 43 | protected: 44 | void doStart() override; 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/response_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace KIMAP 14 | { 15 | struct Response { 16 | class Part 17 | { 18 | public: 19 | enum Type { 20 | String = 0, 21 | List 22 | }; 23 | 24 | explicit Part(const QByteArray &string) 25 | : m_type(String) 26 | , m_string(string) 27 | { 28 | } 29 | explicit Part(const QList &list) 30 | : m_type(List) 31 | , m_list(list) 32 | { 33 | } 34 | 35 | inline Type type() const 36 | { 37 | return m_type; 38 | } 39 | inline QByteArray toString() const 40 | { 41 | return m_string; 42 | } 43 | inline QList toList() const 44 | { 45 | return m_list; 46 | } 47 | 48 | private: 49 | Type m_type; 50 | QByteArray m_string; 51 | QList m_list; 52 | }; 53 | 54 | inline QByteArray toString() const 55 | { 56 | QByteArray result; 57 | 58 | for (const Part &part : std::as_const(content)) { 59 | if (part.type() == Part::List) { 60 | result += '('; 61 | const QList lstBa = part.toList(); 62 | for (const QByteArray &item : lstBa) { 63 | result += ' '; 64 | result += item; 65 | } 66 | result += " ) "; 67 | } else { 68 | result += part.toString() + ' '; 69 | } 70 | } 71 | 72 | if (!responseCode.isEmpty()) { 73 | result += "[ "; 74 | for (const Part &part : std::as_const(responseCode)) { 75 | if (part.type() == Part::List) { 76 | result += '('; 77 | const QList lstBa = part.toList(); 78 | for (const QByteArray &item : lstBa) { 79 | result += ' '; 80 | result += item; 81 | } 82 | result += " ) "; 83 | } else { 84 | result += part.toString() + ' '; 85 | } 86 | } 87 | result += " ]"; 88 | } 89 | 90 | return result; 91 | } 92 | 93 | QList content; 94 | QList responseCode; 95 | }; 96 | 97 | } 98 | 99 | Q_DECLARE_METATYPE(KIMAP::Response) 100 | static const int _kimap_messageTypeId = qRegisterMetaType(); 101 | -------------------------------------------------------------------------------- /src/rfccodecs.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * 3 | * rfccodecs - handler for various rfc/mime encodings 4 | * SPDX-FileCopyrightText: 2000 s .carstens@gmx.de 5 | * 6 | * SPDX-License-Identifier: LGPL-2.0-or-later 7 | * 8 | *********************************************************************/ 9 | /** 10 | * @file 11 | * This file is part of the IMAP support library and defines the 12 | * RfcCodecs class. 13 | * 14 | * @brief 15 | * Provides handlers for various RFC/MIME encodings. 16 | * 17 | * @author Sven Carstens 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "kimap_export.h" 25 | 26 | namespace KIMAP 27 | { 28 | /** 29 | Converts an Unicode IMAP mailbox to a QByteArray which can be used in 30 | IMAP communication. 31 | @param src is the QByteArray containing the IMAP mailbox. 32 | @since 4.3 33 | */ 34 | [[nodiscard]] KIMAP_EXPORT QByteArray encodeImapFolderName(const QByteArray &src); 35 | 36 | /** 37 | Converts an UTF-7 encoded IMAP mailbox to a QByteArray 38 | @param inSrc is the QByteArray containing the Unicode path. 39 | @since 4.3 40 | */ 41 | [[nodiscard]] KIMAP_EXPORT QByteArray decodeImapFolderName(const QByteArray &inSrc); 42 | /** 43 | Converts an Unicode IMAP mailbox to a QString which can be used in 44 | IMAP communication. 45 | @param src is the QString containing the IMAP mailbox. 46 | */ 47 | [[nodiscard]] KIMAP_EXPORT QString encodeImapFolderName(const QString &src); 48 | 49 | /** 50 | Converts an UTF-7 encoded IMAP mailbox to a Unicode QString. 51 | @param inSrc is the QString containing the Unicode path. 52 | */ 53 | [[nodiscard]] KIMAP_EXPORT QString decodeImapFolderName(const QString &inSrc); 54 | 55 | /** 56 | Replaces " with \" and \ with \\ " and \ characters. 57 | @param src is the QString to quote. 58 | */ 59 | [[nodiscard]] KIMAP_EXPORT QString quoteIMAP(const QString &src); 60 | 61 | /** 62 | Replaces " with \" and \ with \\ " and \ characters. 63 | @param src is the QString to quote. 64 | @since 4.3 65 | */ 66 | [[nodiscard]] KIMAP_EXPORT QByteArray quoteIMAP(const QByteArray &src); 67 | } 68 | -------------------------------------------------------------------------------- /src/selectjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "fetchjob.h" 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Response; 18 | class SelectJobPrivate; 19 | class ImapSet; 20 | 21 | class KIMAP_EXPORT SelectJob : public Job 22 | { 23 | Q_OBJECT 24 | Q_DECLARE_PRIVATE(SelectJob) 25 | 26 | friend class SessionPrivate; 27 | 28 | public: 29 | explicit SelectJob(Session *session); 30 | ~SelectJob() override; 31 | 32 | void setMailBox(const QString &mailBox); 33 | [[nodiscard]] QString mailBox() const; 34 | 35 | void setOpenReadOnly(bool readOnly); 36 | /** 37 | * @return Returns whether the mailbox is opened in read-only mode. Note 38 | * that this can return true even if setOpenReadOnly() was set to false, 39 | * as the mailbox may be read-only on the server. 40 | */ 41 | [[nodiscard]] bool isOpenReadOnly() const; 42 | 43 | [[nodiscard]] QList flags() const; 44 | [[nodiscard]] QList permanentFlags() const; 45 | 46 | [[nodiscard]] int messageCount() const; 47 | [[nodiscard]] int recentCount() const; 48 | [[nodiscard]] int firstUnseenIndex() const; 49 | 50 | [[nodiscard]] qint64 uidValidity() const; 51 | [[nodiscard]] qint64 nextUid() const; 52 | 53 | /** 54 | * @return Highest mod-sequence value of all messages in the mailbox or 0 55 | * if the server does not have CONDSTORE capability (RFC4551) or does not 56 | * support persistent storage of mod-sequences. 57 | * 58 | * @since 4.12 59 | */ 60 | [[nodiscard]] quint64 highestModSequence() const; 61 | 62 | /** 63 | * Whether to append CONDSTORE parameter to the SELECT command. 64 | * 65 | * This option is false by default and can be enabled only when server 66 | * has CONDSTORE capability (RFC4551), otherwise the SELECT command will 67 | * fail. 68 | * 69 | * @since 4.12 70 | */ 71 | void setCondstoreEnabled(bool enable); 72 | 73 | /** 74 | * Returns whether the CONDSTORE parameter will be appended to SELECT command 75 | * 76 | * @since 4.12 77 | */ 78 | [[nodiscard]] bool condstoreEnabled() const; 79 | 80 | /** 81 | * Set Quick Resynchronization parameters. 82 | * 83 | * Requires that the server supports the QRESYNC extension as defined in RFC5162 84 | * and the QRESYNC extension has been enabled via EnableJob. 85 | * 86 | * Using this option implies enabling CONDSTORE. 87 | * 88 | * @param lastUidvalidity Last UIDValidity value known to the client 89 | * @param lastModseq Last modification sequence number known to the client 90 | * @param knownUids List of all UIDs known to the client (optional). 91 | * 92 | * @see KIMAP::EnableJob 93 | */ 94 | void setQResync(qint64 lastUidvalidity, quint64 lastModseq, const ImapSet &knownUids = ImapSet{}); 95 | 96 | Q_SIGNALS: 97 | /** 98 | * Emitted when the server provides a list of UIDs that have vanished since last sync. 99 | * 100 | * This feature requires that the QRESYNC parameters have been provided 101 | * to the SELECT command. This signal may not be emitted if no messages 102 | * have been expunged since the last check. 103 | * 104 | * @see setQResync() 105 | * @since 5.16 106 | */ 107 | void vanished(const KIMAP::ImapSet &set); 108 | 109 | /** 110 | * Emitted when the server provides a list of messages that have changed or appeared 111 | * in the mailbox since the last sync. 112 | * 113 | * This feature requires that the QRESYNC parameters have been provided 114 | * to the SELECT command. The signal may not be emitted if no messages 115 | * have been modified or appended to the mailbox. 116 | * 117 | * @see setQResync() 118 | * @since 5.16 119 | */ 120 | void modified(const QMap &messages); 121 | 122 | protected: 123 | void doStart() override; 124 | void handleResponse(const Response &response) override; 125 | }; 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/session_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "session.h" 10 | #include "sessionuiproxy.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class KJob; 19 | 20 | namespace KIMAP 21 | { 22 | class Job; 23 | struct Response; 24 | class SessionLogger; 25 | class SessionThread; 26 | 27 | class KIMAP_EXPORT SessionPrivate : public QObject 28 | { 29 | Q_OBJECT 30 | 31 | friend class Session; 32 | 33 | public: 34 | explicit SessionPrivate(Session *session); 35 | ~SessionPrivate() override; 36 | 37 | void addJob(Job *job); 38 | QByteArray sendCommand(const QByteArray &command, const QByteArray &args = QByteArray()); 39 | void startSsl(QSsl::SslProtocol protocol); 40 | void sendData(const QByteArray &data); 41 | 42 | QSsl::SslProtocol negotiatedEncryption() const; 43 | 44 | void setSocketTimeout(int ms); 45 | int socketTimeout() const; 46 | 47 | Q_SIGNALS: 48 | void encryptionNegotiationResult(bool); 49 | 50 | private Q_SLOTS: 51 | void onEncryptionNegotiationResult(bool isEncrypted, QSsl::SslProtocol sslVersion); 52 | void onSocketTimeout(); 53 | 54 | void doStartNext(); 55 | void jobDone(KJob *); 56 | void jobDestroyed(QObject *); 57 | void responseReceived(const KIMAP::Response &); 58 | 59 | void socketConnected(); 60 | void socketDisconnected(); 61 | void socketError(QAbstractSocket::SocketError error); 62 | void socketActivity(); 63 | 64 | void handleSslError(const KSslErrorUiData &errorData); 65 | 66 | private: 67 | void startNext(); 68 | void clearJobQueue(); 69 | void setState(Session::State state); 70 | 71 | void startSocketTimer(); 72 | void stopSocketTimer(); 73 | void restartSocketTimer(); 74 | bool isConnected() const; 75 | 76 | Session *const q; 77 | 78 | bool isSocketConnected = false; 79 | Session::State state; 80 | 81 | SessionLogger *logger = nullptr; 82 | SessionThread *thread = nullptr; 83 | SessionUiProxy::Ptr uiProxy; 84 | 85 | bool jobRunning = false; 86 | Job *currentJob = nullptr; 87 | QQueue queue; 88 | 89 | QByteArray authTag; 90 | QByteArray selectTag; 91 | QByteArray closeTag; 92 | 93 | QString userName; 94 | QByteArray greeting; 95 | QByteArray currentMailBox; 96 | QByteArray upcomingMailBox; 97 | quint16 tagCount; 98 | 99 | QSsl::SslProtocol sslVersion; 100 | 101 | int socketTimerInterval = 0; 102 | QTimer socketTimer; 103 | }; 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/sessionlogger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 3 | SPDX-FileContributor: Kevin Ottens 4 | 5 | SPDX-License-Identifier: LGPL-2.0-or-later 6 | */ 7 | 8 | #include "sessionlogger_p.h" 9 | 10 | #include "kimap_debug.h" 11 | #include 12 | 13 | using namespace KIMAP; 14 | 15 | SessionLogger::SessionLogger() 16 | { 17 | static qint64 nextId = 0; 18 | m_id = ++nextId; 19 | 20 | m_file.setFileName(QLatin1StringView(qgetenv("KIMAP_LOGFILE")) + QLatin1Char('.') + QString::number(QCoreApplication::applicationPid()) + QLatin1Char('.') 21 | + QString::number(m_id)); 22 | if (!m_file.open(QFile::WriteOnly)) { 23 | qCWarning(KIMAP_LOG) << "Could not open log file for writing:" << m_file.fileName(); 24 | } 25 | } 26 | 27 | SessionLogger::~SessionLogger() 28 | { 29 | m_file.close(); 30 | } 31 | 32 | void SessionLogger::dataSent(const QByteArray &data) 33 | { 34 | m_file.write("C: " + data.trimmed() + '\n'); 35 | m_file.flush(); 36 | } 37 | 38 | void SessionLogger::dataReceived(const QByteArray &data) 39 | { 40 | m_file.write("S: " + data.trimmed() + '\n'); 41 | m_file.flush(); 42 | } 43 | 44 | void SessionLogger::disconnectionOccured() 45 | { 46 | m_file.write("X\n"); 47 | } 48 | -------------------------------------------------------------------------------- /src/sessionlogger_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company 3 | SPDX-FileContributor: Kevin Ottens 4 | 5 | SPDX-License-Identifier: LGPL-2.0-or-later 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace KIMAP 13 | { 14 | class SessionLoggerPrivate; 15 | 16 | class SessionLogger 17 | { 18 | public: 19 | SessionLogger(); 20 | ~SessionLogger(); 21 | 22 | void dataSent(const QByteArray &data); 23 | void dataReceived(const QByteArray &data); 24 | void disconnectionOccured(); 25 | 26 | private: 27 | Q_DISABLE_COPY(SessionLogger) 28 | qint64 m_id = 0; 29 | QFile m_file; 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/sessionthread_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | class KSslErrorUiData; 17 | 18 | namespace KIMAP 19 | { 20 | class ImapStreamParser; 21 | struct Response; 22 | 23 | class SessionThread : public QObject 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit SessionThread(const QString &hostName, quint16 port); 29 | ~SessionThread(); 30 | 31 | inline QString hostName() 32 | { 33 | return m_hostName; 34 | } 35 | inline quint16 port() 36 | { 37 | return m_port; 38 | } 39 | 40 | void setUseNetworkProxy(bool useProxy); 41 | 42 | void sendData(const QByteArray &payload); 43 | 44 | public Q_SLOTS: 45 | void closeSocket(); 46 | void startSsl(QSsl::SslProtocol protocol); 47 | void sslErrorHandlerResponse(bool result); 48 | 49 | Q_SIGNALS: 50 | void socketConnected(); 51 | void socketDisconnected(); 52 | void socketActivity(); 53 | void socketError(QAbstractSocket::SocketError); 54 | void responseReceived(const KIMAP::Response &response); 55 | void encryptionNegotiationResult(bool, QSsl::SslProtocol); 56 | void sslError(const KSslErrorUiData &); 57 | 58 | private Q_SLOTS: 59 | void reconnect(); 60 | void threadInit(); 61 | void threadQuit(); 62 | void readMessage(); 63 | void writeDataQueue(); 64 | void sslConnected(); 65 | void doCloseSocket(); 66 | void slotSocketError(QAbstractSocket::SocketError); 67 | void slotSocketDisconnected(); 68 | void doStartSsl(QSsl::SslProtocol); 69 | void doSslErrorHandlerResponse(bool result); 70 | void setUseProxyInternal(bool useProxy); 71 | 72 | private: 73 | QString m_hostName; 74 | quint16 m_port; 75 | 76 | std::unique_ptr m_socket; 77 | std::unique_ptr m_stream; 78 | 79 | QQueue m_dataQueue; 80 | 81 | // Protects m_dataQueue 82 | QMutex m_mutex; 83 | 84 | bool m_encryptedMode = false; 85 | bool m_useProxy = false; 86 | }; 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/sessionuiproxy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "sessionuiproxy.h" 8 | 9 | KIMAP::SessionUiProxy::~SessionUiProxy() 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /src/sessionuiproxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | #include 14 | 15 | class KSslErrorUiData; 16 | 17 | namespace KIMAP 18 | { 19 | /** @short Interface to display communication errors and wait for user feedback. */ 20 | class KIMAP_EXPORT SessionUiProxy 21 | { 22 | public: 23 | using Ptr = QSharedPointer; 24 | 25 | virtual ~SessionUiProxy(); 26 | /** 27 | * Show an SSL error and ask the user whether it should be ignored or not. 28 | * The recommended KDE UI is the following: 29 | * @code 30 | * #include 31 | * class UiProxy: public SessionUiProxy { 32 | * public: 33 | * bool ignoreSslError(const KSslErrorUiData& errorData) { 34 | * if (KIO::SslUi::askIgnoreSslErrors(errorData)) { 35 | * return true; 36 | * } else { 37 | * return false; 38 | * } 39 | * } 40 | * }; 41 | * [...] 42 | * Session session(server, port); 43 | * UiProxy *proxy = new UiProxy(); 44 | * session.setUiProxy(proxy); 45 | * @endcode 46 | * @param errorData contains details about the error. 47 | * @return true if the error can be ignored 48 | */ 49 | virtual bool ignoreSslError(const KSslErrorUiData &errorData) = 0; 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/setacljob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "setacljob.h" 8 | 9 | #include 10 | 11 | #include "acljobbase_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class SetAclJobPrivate : public AclJobBasePrivate 19 | { 20 | public: 21 | SetAclJobPrivate(Session *session, const QString &name) 22 | : AclJobBasePrivate(session, name) 23 | { 24 | } 25 | ~SetAclJobPrivate() 26 | { 27 | } 28 | }; 29 | } 30 | 31 | using namespace KIMAP; 32 | 33 | SetAclJob::SetAclJob(Session *session) 34 | : AclJobBase(*new SetAclJobPrivate(session, i18n("SetAcl"))) 35 | { 36 | } 37 | 38 | SetAclJob::~SetAclJob() 39 | { 40 | } 41 | 42 | void SetAclJob::doStart() 43 | { 44 | Q_D(SetAclJob); 45 | QByteArray r = Acl::rightsToString(d->rightList); 46 | if (d->modifier == Add) { 47 | r.prepend('+'); 48 | } else if (d->modifier == Remove) { 49 | r.prepend('-'); 50 | } 51 | d->tags << d->sessionInternal()->sendCommand("SETACL", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" \"" + d->id + "\" \"" + r + '\"'); 52 | } 53 | 54 | void SetAclJob::setRights(AclModifier modifier, Acl::Rights rights) 55 | { 56 | Q_D(SetAclJob); 57 | d->setRights(modifier, rights); 58 | } 59 | 60 | void SetAclJob::setIdentifier(const QByteArray &identifier) 61 | { 62 | Q_D(SetAclJob); 63 | d->setIdentifier(identifier); 64 | } 65 | 66 | QByteArray SetAclJob::identifier() 67 | { 68 | Q_D(SetAclJob); 69 | return d->identifier(); 70 | } 71 | 72 | #include "moc_setacljob.cpp" 73 | -------------------------------------------------------------------------------- /src/setacljob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "acljobbase.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | struct Response; 17 | class SetAclJobPrivate; 18 | 19 | /** 20 | * Sets the rights that correspond to an identifier on a mailbox 21 | * 22 | * This job can only be run when the session is in the 23 | * authenticated (or selected) state. 24 | * 25 | * This job requires that the server supports the ACL 26 | * capability, defined in 27 | * RFC 4314. 28 | */ 29 | class KIMAP_EXPORT SetAclJob : public AclJobBase 30 | { 31 | Q_OBJECT 32 | Q_DECLARE_PRIVATE(SetAclJob) 33 | 34 | friend class SessionPrivate; 35 | 36 | public: 37 | explicit SetAclJob(Session *session); 38 | ~SetAclJob() override; 39 | 40 | /** 41 | * Sets the rights that will be changed for the identifier 42 | * 43 | * Note that multiple calls to this method will have a 44 | * non-intuitive effect: the @p modifier value of the most 45 | * recent call will be used, but the OR'd-together values 46 | * of all calls to setRights() will be used. 47 | * 48 | * If the server does not recognise any of the rights, 49 | * the job will fail and the ACL for the mailbox will 50 | * remain unchanged. 51 | * 52 | * Note that some rights may be tied together, and must be set 53 | * or removed as a group. See ListRightsJob::possibleRights() 54 | * for more details. The server will only set a tied group 55 | * of rights if you have requested that all the rights in that 56 | * group should be set. 57 | * 58 | * @param modifier determines whether the rights will be 59 | * added to the identifier, removed from 60 | * the identifier or will replace any 61 | * existing rights assigned to the 62 | * identifier 63 | * @param rights the rights to be added, removed or set 64 | */ 65 | void setRights(AclModifier modifier, Acl::Rights rights); 66 | 67 | /** 68 | * Sets the identifier the rights will be modified for 69 | * 70 | * The meaning of identifiers depends on the server implementation, 71 | * with the following restrictions: 72 | * 73 | * - "anyone" means any authenticated user, including anonymous 74 | * - an identifier starting with a minus sign ('-') indicates 75 | * "negative rights": rights that should be taken away from 76 | * matching users 77 | * 78 | * Other than the above restrictions, ACL identifiers are usually 79 | * IMAP usernames, but could potentially be group names as well. 80 | * 81 | * Note that negative rights override positive rights: if 82 | * "fred" and "-fred" are both assigned the 'w' right, the 83 | * user "fred" will not have the 'w' right. 84 | * @param identifier the identifier to set 85 | */ 86 | void setIdentifier(const QByteArray &identifier); 87 | /** 88 | * The identifier that rights will be associated with 89 | */ 90 | [[nodiscard]] QByteArray identifier(); 91 | 92 | protected: 93 | void doStart() override; 94 | }; 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/setquotajob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "setquotajob.h" 8 | 9 | #include "kimap_debug.h" 10 | #include 11 | 12 | #include "quotajobbase_p.h" 13 | #include "response_p.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class SetQuotaJobPrivate : public QuotaJobBasePrivate 19 | { 20 | public: 21 | SetQuotaJobPrivate(Session *session, const QString &name) 22 | : QuotaJobBasePrivate(session, name) 23 | { 24 | } 25 | ~SetQuotaJobPrivate() 26 | { 27 | } 28 | 29 | QMap setList; 30 | QByteArray root; 31 | }; 32 | } 33 | 34 | using namespace KIMAP; 35 | 36 | SetQuotaJob::SetQuotaJob(Session *session) 37 | : QuotaJobBase(*new SetQuotaJobPrivate(session, i18n("SetQuota"))) 38 | { 39 | } 40 | 41 | SetQuotaJob::~SetQuotaJob() 42 | { 43 | } 44 | 45 | void SetQuotaJob::doStart() 46 | { 47 | Q_D(SetQuotaJob); 48 | QByteArray s; 49 | s += '('; 50 | for (QMap::ConstIterator it = d->setList.constBegin(), end = d->setList.constEnd(); it != end; ++it) { 51 | s += it.key() + ' ' + QByteArray::number(it.value()) + ' '; 52 | } 53 | if (d->setList.isEmpty()) { 54 | s += ')'; 55 | } else { 56 | s[s.length() - 1] = ')'; 57 | } 58 | 59 | qCDebug(KIMAP_LOG) << "SETQUOTA " << '\"' + d->root + "\" " + s; 60 | // XXX: [alexmerry, 2010-07-24]: should d->root be quoted properly? 61 | d->tags << d->sessionInternal()->sendCommand("SETQUOTA", '\"' + d->root + "\" " + s); 62 | } 63 | 64 | void SetQuotaJob::handleResponse(const Response &response) 65 | { 66 | Q_D(SetQuotaJob); 67 | if (handleErrorReplies(response) == NotHandled) { 68 | if (response.content.size() >= 4 && response.content[1].toString() == "QUOTA") { 69 | d->quota = d->readQuota(response.content[3]); 70 | } 71 | } 72 | } 73 | 74 | void SetQuotaJob::setQuota(const QByteArray &resource, qint64 limit) 75 | { 76 | Q_D(SetQuotaJob); 77 | 78 | d->setList[resource.toUpper()] = limit; 79 | } 80 | 81 | void SetQuotaJob::setRoot(const QByteArray &root) 82 | { 83 | Q_D(SetQuotaJob); 84 | 85 | d->root = root; 86 | } 87 | 88 | QByteArray SetQuotaJob::root() const 89 | { 90 | Q_D(const SetQuotaJob); 91 | 92 | return d->root; 93 | } 94 | 95 | #include "moc_setquotajob.cpp" 96 | -------------------------------------------------------------------------------- /src/setquotajob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "quotajobbase.h" 10 | 11 | namespace KIMAP 12 | { 13 | class Session; 14 | struct Response; 15 | class SetQuotaJobPrivate; 16 | 17 | /** 18 | * Sets resource limits on a quota root. 19 | * 20 | * Quotas are defined with respect to "resources" and "quota roots". 21 | * A resource is a numerical property that can be limited, such 22 | * as the octet size of all the messages in a mailbox, or the 23 | * number of messages in a mailbox. Each mailbox has one or more 24 | * quota roots, which are where the resource limits are defined. 25 | * A quota root may or may not be a mailbox name, and an empty 26 | * string is a valid quota root. All mailboxes with the same quota 27 | * root share the resource limits of the quota root. 28 | * 29 | * This job can only be run when the session is in the 30 | * authenticated (or selected) state. 31 | * 32 | * This job requires that the server supports the QUOTA 33 | * capability, defined in 34 | * RFC 2087. 35 | */ 36 | class KIMAP_EXPORT SetQuotaJob : public QuotaJobBase 37 | { 38 | Q_OBJECT 39 | Q_DECLARE_PRIVATE(SetQuotaJob) 40 | 41 | friend class SessionPrivate; 42 | 43 | public: 44 | explicit SetQuotaJob(Session *session); 45 | ~SetQuotaJob() override; 46 | 47 | /** 48 | * Set a limit for a quota resource. 49 | * 50 | * For example, you might set the limit for "STORAGE" to 51 | * 512 to limit the sum of the messages' RFC822.SIZE to 52 | * 512*1024 octets (ie: 512 kb), or the limit for "MESSAGE" 53 | * to 100 to limit the number of messages to 100. 54 | * 55 | * Note that although RFC 2087 allows a resource name to 56 | * be any string, this API actually limits resource names 57 | * to upper-case atoms. In practice, resource names will 58 | * almost certainly be composed entirely of upper-case latin 59 | * letters (A-Z). 60 | * 61 | * @param resource the resource name 62 | * @param limit the maximum value the resource may take 63 | */ 64 | void setQuota(const QByteArray &resource, qint64 limit); 65 | 66 | /** 67 | * Set the quota root the resource limits should be set for. 68 | * 69 | * Note: if the quota root does not already exist, the server 70 | * may create it and change the quota roots for any number of 71 | * existing mailboxes in an implementation-defined manner. 72 | * 73 | * @param root the quota root to set, in bytes 74 | * @see GetQuotaRootJob 75 | */ 76 | void setRoot(const QByteArray &root); 77 | /** 78 | * The quota root that will be modified. 79 | */ 80 | [[nodiscard]] QByteArray root() const; 81 | 82 | protected: 83 | void doStart() override; 84 | void handleResponse(const Response &response) override; 85 | }; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/statusjob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "statusjob.h" 8 | #include "job_p.h" 9 | #include "kimap_debug.h" 10 | #include "response_p.h" 11 | #include "rfccodecs.h" 12 | #include "session_p.h" 13 | 14 | #include 15 | 16 | namespace KIMAP 17 | { 18 | class StatusJobPrivate : public JobPrivate 19 | { 20 | public: 21 | explicit StatusJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | 26 | ~StatusJobPrivate() 27 | { 28 | } 29 | 30 | QString mailBox; 31 | QList dataItems; 32 | QList> status; 33 | }; 34 | 35 | } 36 | 37 | using namespace KIMAP; 38 | 39 | StatusJob::StatusJob(Session *session) 40 | : Job(*new StatusJobPrivate(session, i18nc("name of the status job", "Status"))) 41 | { 42 | } 43 | 44 | StatusJob::~StatusJob() 45 | { 46 | } 47 | 48 | void StatusJob::setMailBox(const QString &mailBox) 49 | { 50 | Q_D(StatusJob); 51 | d->mailBox = mailBox; 52 | } 53 | 54 | QString StatusJob::mailBox() const 55 | { 56 | Q_D(const StatusJob); 57 | return d->mailBox; 58 | } 59 | 60 | void StatusJob::setDataItems(const QList &dataItems) 61 | { 62 | Q_D(StatusJob); 63 | d->dataItems = dataItems; 64 | } 65 | 66 | QList StatusJob::dataItems() const 67 | { 68 | Q_D(const StatusJob); 69 | return d->dataItems; 70 | } 71 | 72 | QList> StatusJob::status() const 73 | { 74 | Q_D(const StatusJob); 75 | return d->status; 76 | } 77 | 78 | void StatusJob::doStart() 79 | { 80 | Q_D(StatusJob); 81 | 82 | const QByteArray params = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" (" + d->dataItems.join(' ') + ')'; 83 | 84 | d->tags << d->sessionInternal()->sendCommand("STATUS", params); 85 | } 86 | 87 | void StatusJob::handleResponse(const Response &response) 88 | { 89 | Q_D(StatusJob); 90 | 91 | if (handleErrorReplies(response) == NotHandled) { 92 | if (response.content.size() >= 3) { 93 | const QByteArray code = response.content[1].toString(); 94 | if (code == "STATUS") { 95 | const QList resp = response.content[3].toList(); 96 | for (int i = 0; i < resp.size(); i += 2) { 97 | d->status << (qMakePair(resp[i], resp[i + 1].toLongLong())); 98 | } 99 | 100 | } else if (code == "OK") { 101 | return; 102 | } else { 103 | qCDebug(KIMAP_LOG) << response.toString(); 104 | } 105 | } 106 | } 107 | } 108 | 109 | #include "moc_statusjob.cpp" 110 | -------------------------------------------------------------------------------- /src/statusjob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016 Daniel Vrátil 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | #include 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | class StatusJobPrivate; 18 | 19 | class KIMAP_EXPORT StatusJob : public Job 20 | { 21 | Q_OBJECT 22 | Q_DECLARE_PRIVATE(StatusJob) 23 | 24 | friend class StatusJobPrivate; 25 | 26 | public: 27 | explicit StatusJob(Session *session); 28 | ~StatusJob() override; 29 | 30 | void setMailBox(const QString &mailBox); 31 | [[nodiscard]] QString mailBox() const; 32 | 33 | void setDataItems(const QList &dataItems); 34 | [[nodiscard]] QList dataItems() const; 35 | 36 | [[nodiscard]] QList> status() const; 37 | 38 | protected: 39 | void doStart() override; 40 | void handleResponse(const Response &response) override; 41 | }; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/storejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Kevin Ottens 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "imapset.h" 12 | #include "job.h" 13 | 14 | namespace KIMAP 15 | { 16 | class Session; 17 | struct Response; 18 | class StoreJobPrivate; 19 | 20 | using MessageFlags = QList; 21 | 22 | class KIMAP_EXPORT StoreJob : public Job 23 | { 24 | Q_OBJECT 25 | Q_DECLARE_PRIVATE(StoreJob) 26 | 27 | friend class SessionPrivate; 28 | 29 | public: 30 | enum StoreMode { 31 | SetFlags, 32 | AppendFlags, 33 | RemoveFlags 34 | }; 35 | 36 | explicit StoreJob(Session *session); 37 | ~StoreJob() override; 38 | 39 | void setSequenceSet(const ImapSet &set); 40 | [[nodiscard]] ImapSet sequenceSet() const; 41 | 42 | void setUidBased(bool uidBased); 43 | [[nodiscard]] bool isUidBased() const; 44 | 45 | void setFlags(const MessageFlags &flags); 46 | [[nodiscard]] MessageFlags flags() const; 47 | 48 | void setGMLabels(const MessageFlags &gmLabels); 49 | [[nodiscard]] MessageFlags gmLabels() const; 50 | 51 | void setMode(StoreMode mode); 52 | [[nodiscard]] StoreMode mode() const; 53 | 54 | [[nodiscard]] QMap resultingFlags() const; 55 | 56 | protected: 57 | void doStart() override; 58 | void handleResponse(const Response &response) override; 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/subscribejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "subscribejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class SubscribeJobPrivate : public JobPrivate 19 | { 20 | public: 21 | SubscribeJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~SubscribeJobPrivate() 26 | { 27 | } 28 | 29 | QString mailBox; 30 | }; 31 | } 32 | 33 | using namespace KIMAP; 34 | 35 | SubscribeJob::SubscribeJob(Session *session) 36 | : Job(*new SubscribeJobPrivate(session, i18n("Subscribe"))) 37 | { 38 | } 39 | 40 | SubscribeJob::~SubscribeJob() 41 | { 42 | } 43 | 44 | void SubscribeJob::doStart() 45 | { 46 | Q_D(SubscribeJob); 47 | d->tags << d->sessionInternal()->sendCommand("SUBSCRIBE", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 48 | } 49 | 50 | void SubscribeJob::setMailBox(const QString &mailBox) 51 | { 52 | Q_D(SubscribeJob); 53 | d->mailBox = mailBox; 54 | } 55 | 56 | QString SubscribeJob::mailBox() const 57 | { 58 | Q_D(const SubscribeJob); 59 | return d->mailBox; 60 | } 61 | 62 | #include "moc_subscribejob.cpp" 63 | -------------------------------------------------------------------------------- /src/subscribejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class SubscribeJobPrivate; 17 | 18 | class KIMAP_EXPORT SubscribeJob : public Job 19 | { 20 | Q_OBJECT 21 | Q_DECLARE_PRIVATE(SubscribeJob) 22 | 23 | friend class SessionPrivate; 24 | 25 | public: 26 | explicit SubscribeJob(Session *session); 27 | ~SubscribeJob() override; 28 | 29 | void setMailBox(const QString &mailBox); 30 | [[nodiscard]] QString mailBox() const; 31 | 32 | protected: 33 | void doStart() override; 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/unsubscribejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #include "unsubscribejob.h" 8 | 9 | #include 10 | 11 | #include "job_p.h" 12 | #include "response_p.h" 13 | #include "rfccodecs.h" 14 | #include "session_p.h" 15 | 16 | namespace KIMAP 17 | { 18 | class UnsubscribeJobPrivate : public JobPrivate 19 | { 20 | public: 21 | UnsubscribeJobPrivate(Session *session, const QString &name) 22 | : JobPrivate(session, name) 23 | { 24 | } 25 | ~UnsubscribeJobPrivate() 26 | { 27 | } 28 | 29 | QString mailBox; 30 | }; 31 | } 32 | 33 | using namespace KIMAP; 34 | 35 | UnsubscribeJob::UnsubscribeJob(Session *session) 36 | : Job(*new UnsubscribeJobPrivate(session, i18n("Unsubscribe"))) 37 | { 38 | } 39 | 40 | UnsubscribeJob::~UnsubscribeJob() 41 | { 42 | } 43 | 44 | void UnsubscribeJob::doStart() 45 | { 46 | Q_D(UnsubscribeJob); 47 | d->tags << d->sessionInternal()->sendCommand("UNSUBSCRIBE", '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + '\"'); 48 | } 49 | 50 | void UnsubscribeJob::setMailBox(const QString &mailBox) 51 | { 52 | Q_D(UnsubscribeJob); 53 | d->mailBox = mailBox; 54 | } 55 | 56 | QString UnsubscribeJob::mailBox() const 57 | { 58 | Q_D(const UnsubscribeJob); 59 | return d->mailBox; 60 | } 61 | 62 | #include "moc_unsubscribejob.cpp" 63 | -------------------------------------------------------------------------------- /src/unsubscribejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009 Andras Mantia 3 | 4 | SPDX-License-Identifier: LGPL-2.0-or-later 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "kimap_export.h" 10 | 11 | #include "job.h" 12 | 13 | namespace KIMAP 14 | { 15 | class Session; 16 | class UnsubscribeJobPrivate; 17 | 18 | class KIMAP_EXPORT UnsubscribeJob : public Job 19 | { 20 | Q_OBJECT 21 | Q_DECLARE_PRIVATE(UnsubscribeJob) 22 | 23 | friend class SessionPrivate; 24 | 25 | public: 26 | explicit UnsubscribeJob(Session *session); 27 | ~UnsubscribeJob() override; 28 | 29 | void setMailBox(const QString &mailBox); 30 | [[nodiscard]] QString mailBox() const; 31 | 32 | protected: 33 | void doStart() override; 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: none 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | kde_enable_exceptions() 4 | 5 | add_executable(testimapidle testimapidle.cpp) 6 | target_link_libraries(testimapidle KPim6IMAP Qt::Test KF6::KIOCore Qt::Network) 7 | 8 | add_executable(testimapserver testimapserver.cpp) 9 | target_link_libraries(testimapserver KPim6IMAP Qt::Test KF6::KIOCore Qt::Network) 10 | -------------------------------------------------------------------------------- /tests/testimapidle.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of the KDE project 3 | * SPDX-FileCopyrightText: 2009 Kevin Ottens 4 | * 5 | * SPDX-License-Identifier: LGPL-2.0-or-later 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "capabilitiesjob.h" 12 | #include "closejob.h" 13 | #include "idlejob.h" 14 | #include "loginjob.h" 15 | #include "logoutjob.h" 16 | #include "selectjob.h" 17 | #include "session.h" 18 | #include "sessionuiproxy.h" 19 | 20 | using namespace KIMAP; 21 | 22 | class UiProxy : public SessionUiProxy 23 | { 24 | public: 25 | bool ignoreSslError(const KSslErrorUiData &errorData) override 26 | { 27 | Q_UNUSED(errorData) 28 | return true; 29 | } 30 | }; 31 | 32 | int main(int argc, char **argv) 33 | { 34 | QCoreApplication::setApplicationName(QStringLiteral("TestImapIdle")); 35 | 36 | if (argc < 4) { 37 | qCritical() << "Not enough parameters, expecting: "; 38 | } 39 | 40 | QString server = QString::fromLocal8Bit(argv[1]); 41 | int port = 143; 42 | if (server.count(QLatin1Char(':')) == 1) { 43 | const QStringList lstSplit = server.split(QLatin1Char(':')); 44 | port = lstSplit.last().toInt(); 45 | server = lstSplit.first(); 46 | } 47 | QString user = QString::fromLocal8Bit(argv[2]); 48 | QString password = QString::fromLocal8Bit(argv[3]); 49 | 50 | qDebug() << "Listening:" << server << port << user << password; 51 | qDebug(); 52 | 53 | QCoreApplication app(argc, argv); 54 | Session session(server, port); 55 | auto proxy = new UiProxy(); 56 | session.setUiProxy(UiProxy::Ptr(proxy)); 57 | 58 | qDebug() << "Logging in..."; 59 | auto login = new LoginJob(&session); 60 | login->setUserName(user); 61 | login->setPassword(password); 62 | login->exec(); 63 | Q_ASSERT_X(login->error() == 0, "LoginJob", login->errorString().toLocal8Bit().constData()); 64 | Q_ASSERT(session.state() == Session::Authenticated); 65 | qDebug(); 66 | 67 | qDebug() << "Asking for capabilities:"; 68 | auto capabilities = new CapabilitiesJob(&session); 69 | capabilities->exec(); 70 | Q_ASSERT_X(capabilities->error() == 0, "CapabilitiesJob", capabilities->errorString().toLocal8Bit().constData()); 71 | Q_ASSERT(session.state() == Session::Authenticated); 72 | qDebug() << capabilities->capabilities(); 73 | qDebug(); 74 | 75 | Q_ASSERT(capabilities->capabilities().contains(QLatin1StringView("IDLE"))); 76 | 77 | qDebug() << "Selecting INBOX:"; 78 | auto select = new SelectJob(&session); 79 | select->setMailBox(QStringLiteral("INBOX")); 80 | select->exec(); 81 | Q_ASSERT_X(select->error() == 0, "SelectJob", select->errorString().toLocal8Bit().constData()); 82 | Q_ASSERT(session.state() == Session::Selected); 83 | qDebug() << "Flags:" << select->flags(); 84 | qDebug() << "Permanent flags:" << select->permanentFlags(); 85 | qDebug() << "Total Number of Messages:" << select->messageCount(); 86 | qDebug() << "Number of recent Messages:" << select->recentCount(); 87 | qDebug() << "First Unseen Message Index:" << select->firstUnseenIndex(); 88 | qDebug() << "UID validity:" << select->uidValidity(); 89 | qDebug() << "Next UID:" << select->nextUid(); 90 | qDebug(); 91 | 92 | qDebug() << "Start idling..."; 93 | auto idle = new IdleJob(&session); 94 | QObject::connect(idle, &KIMAP::IdleJob::mailBoxStats, idle, &KIMAP::IdleJob::stop); 95 | idle->exec(); 96 | qDebug() << "Idling done for" << idle->lastMailBox() << "message count:" << idle->lastMessageCount() << "recent count:" << idle->lastRecentCount(); 97 | 98 | qDebug() << "Closing INBOX:"; 99 | auto close = new CloseJob(&session); 100 | close->exec(); 101 | Q_ASSERT(session.state() == Session::Authenticated); 102 | qDebug(); 103 | 104 | qDebug() << "Logging out..."; 105 | auto logout = new LogoutJob(&session); 106 | logout->exec(); 107 | Q_ASSERT_X(logout->error() == 0, "LogoutJob", logout->errorString().toLocal8Bit().constData()); 108 | Q_ASSERT(session.state() == Session::Disconnected); 109 | 110 | return 0; 111 | } 112 | --------------------------------------------------------------------------------