service/ImapServiceUnits.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Composition root of ImapService (Sprint 92 S92.1.x): constructs the seven | ||
| 2 | // internal units in the service constructor's initializer order and binds | ||
| 3 | // their Deps — calls into other units, the failure path and the notifiers | ||
| 4 | // that emit the service's signals. Kept apart from ImapService.cpp, which | ||
| 5 | // holds the protocol state machine and the response dispatch. | ||
| 6 | |||
| 7 | #include "ImapService.h" | ||
| 8 | |||
| 9 | #include "ImapAppendStream.h" | ||
| 10 | #include "ImapBodyFetch.h" | ||
| 11 | #include "ImapCommandTable.h" | ||
| 12 | #include "ImapConnectionSetup.h" | ||
| 13 | #include "ImapLineReader.h" | ||
| 14 | #include "ImapMutationCommands.h" | ||
| 15 | #include "ImapPushSession.h" | ||
| 16 | |||
| 17 | // S92.1.2: the command table reaches the push session, mutation tracking, | ||
| 18 | // the failure path and the E2E phase reporting of this service. | ||
| 19 | 1401 | std::unique_ptr<ImapCommandTable> ImapService::createCommandTable() { | |
| 20 | 1401 | ImapCommandTable::Deps deps; | |
| 21 | 2740 | deps.isIdling = [this] { return m_push->isIdling(); }; | |
| 22 | 2675 | deps.isNotifying = [this] { return m_push->isNotifying(); }; | |
| 23 | 1883 | deps.idleStartPending = [this] { return m_push->idleStartPending(); }; | |
| 24 | 1403 | deps.startIdle = [this] { m_push->startIdle(); }; | |
| 25 | 1413 | deps.stopIdle = [this] { m_push->stopIdle(); }; | |
| 26 | 2809 | deps.failConnection = [this](const QString &error, DisconnectReason reason) { | |
| 27 | 7 | failConnection(error, reason); | |
| 28 | 1401 | }; | |
| 29 | 2806 | deps.completeMutation = [this](qint64 token, MutationOutcome outcome, | |
| 30 | const QString &error) { | ||
| 31 |
1/1✓ Branch 4 → 5 taken 4 times.
|
4 | m_mutations->completeMutation(token, outcome, error); |
| 32 | 1405 | }; | |
| 33 | #ifdef MAILJD_E2E_TESTING | ||
| 34 | 1377 | deps.reportE2eTransportPhase = [this](const QString &phase, quint64 requestToken) { | |
| 35 | 393 | reportE2eTransportPhase(phase, requestToken); | |
| 36 | 492 | }; | |
| 37 | 1377 | deps.e2eRequestTokenFor = [this](const ImapPendingCommand &command) { | |
| 38 | 393 | return e2eRequestTokenFor(command); | |
| 39 | 492 | }; | |
| 40 | #endif | ||
| 41 | ✗ | return std::make_unique<ImapCommandTable>(this, m_socket, m_selectedFolder, | |
| 42 |
2/2✓ Branch 11 → 12 taken 909 times.
✓ Branch 13 → 14 taken 492 times.
|
2802 | std::move(deps)); |
| 43 | 1401 | } | |
| 44 | |||
| 45 | // S92.1.3: connection setup changes the service state, fails the session and | ||
| 46 | // checks the reader's buffer before the TLS handshake. | ||
| 47 | 1401 | std::unique_ptr<ImapConnectionSetup> ImapService::createConnectionSetup() { | |
| 48 | 1401 | ImapConnectionSetup::Deps deps; | |
| 49 | 1671 | deps.setState = [this](State state) { setState(state); }; | |
| 50 | 2818 | deps.failConnection = [this](const QString &error, DisconnectReason reason) { | |
| 51 | 16 | failConnection(error, reason); | |
| 52 | 1401 | }; | |
| 53 | 1404 | deps.readBufferEmpty = [this] { return m_reader->readBuffer().isEmpty(); }; | |
| 54 | #ifdef MAILJD_E2E_TESTING | ||
| 55 | 1117 | deps.reportE2eTransportPhase = [this](const QString &phase, quint64 requestToken) { | |
| 56 | 133 | reportE2eTransportPhase(phase, requestToken); | |
| 57 | 492 | }; | |
| 58 | #endif | ||
| 59 | 1401 | return std::make_unique<ImapConnectionSetup>(this, m_socket, *m_commands, m_capabilities, | |
| 60 |
2/2✓ Branch 8 → 9 taken 909 times.
✓ Branch 9 → 10 taken 492 times.
|
4203 | std::move(deps)); |
| 61 | 1401 | } | |
| 62 | |||
| 63 | // S92.1.4: the push session changes the service state, fails the session and | ||
| 64 | // asks the service for the negotiated IDLE/NOTIFY capabilities. | ||
| 65 | 1401 | std::unique_ptr<ImapPushSession> ImapService::createPushSession() { | |
| 66 | 1401 | ImapPushSession::Deps deps; | |
| 67 | 1429 | deps.setState = [this](State state) { setState(state); }; | |
| 68 | 2811 | deps.failConnection = [this](const QString &error, DisconnectReason reason) { | |
| 69 | 9 | failConnection(error, reason); | |
| 70 | 1401 | }; | |
| 71 | 1498 | deps.hasIdleCapability = [this] { return hasIdleCapability(); }; | |
| 72 | 1409 | deps.hasNotifyCapability = [this] { return hasNotifyCapability(); }; | |
| 73 | 1604 | deps.quietMs = [this] { return m_reader->quietMs(); }; | |
| 74 | #ifdef MAILJD_E2E_TESTING | ||
| 75 | 1012 | deps.reportE2eTransportPhase = [this](const QString &phase, quint64 requestToken) { | |
| 76 | 28 | reportE2eTransportPhase(phase, requestToken); | |
| 77 | 492 | }; | |
| 78 | #endif | ||
| 79 | 1401 | return std::make_unique<ImapPushSession>(this, m_socket, *m_commands, m_state, | |
| 80 |
2/2✓ Branch 10 → 11 taken 909 times.
✓ Branch 11 → 12 taken 492 times.
|
4203 | std::move(deps)); |
| 81 | 1401 | } | |
| 82 | |||
| 83 | // S92.1.5: body fetches emit the service's body signals; the selected | ||
| 84 | // mailbox stays with the service. | ||
| 85 | 1401 | std::unique_ptr<ImapBodyFetch> ImapService::createBodyFetch() { | |
| 86 | 1401 | ImapBodyFetch::Deps deps; | |
| 87 | 2824 | deps.bodyRequestCompleted = [this](const BodyResult &result) { | |
| 88 | 22 | emit bodyRequestCompleted(result); | |
| 89 | 1401 | }; | |
| 90 | 2808 | deps.bodyMailboxSelected = [this](quint64 requestId, bool success) { | |
| 91 | 6 | emit bodyMailboxSelected(requestId, success); | |
| 92 | 1401 | }; | |
| 93 | 1401 | deps.errorOccurred = [this](const QString &error) { emit errorOccurred(error); }; | |
| 94 | return std::make_unique<ImapBodyFetch>( | ||
| 95 | 1401 | this, *m_commands, *m_push, m_state, | |
| 96 | ✗ | ImapBodyFetch::SelectedMailbox{m_selectedFolder, | |
| 97 | 1401 | m_selectedMessageCount, m_selectedUidValidity, | |
| 98 | 1401 | m_selectedHighestModseq}, | |
| 99 |
1/1✓ Branch 9 → 10 taken 1401 times.
|
4203 | std::move(deps)); |
| 100 | 1401 | } | |
| 101 | |||
| 102 | // S92.1.6: mutation commands emit the service's mutation and move signals; | ||
| 103 | // the selected mailbox and capabilities stay with the service. | ||
| 104 | 1401 | std::unique_ptr<ImapMutationCommands> ImapService::createMutationCommands() { | |
| 105 | 1401 | ImapMutationCommands::Deps deps; | |
| 106 | 1413 | deps.storeComplete = [this] { emit storeComplete(); }; | |
| 107 | 1457 | deps.mutationDispatched = [this](qint64 token) { emit mutationDispatched(token); }; | |
| 108 | 2881 | deps.mutationCompleted = [this](qint64 token, MutationOutcome outcome, | |
| 109 | const QString &error, const QString &uidPlusEvidence) { | ||
| 110 | 79 | emit mutationCompleted(token, outcome, error, uidPlusEvidence); | |
| 111 | 1401 | }; | |
| 112 | 2836 | deps.messageMoved = [this](qint64 uid, const QString &targetFolder) { | |
| 113 | 34 | emit messageMoved(uid, targetFolder); | |
| 114 | 1401 | }; | |
| 115 | 2822 | deps.messagesMoved = [this](const QList<qint64> &uids, const QString &targetFolder) { | |
| 116 | 20 | emit messagesMoved(uids, targetFolder); | |
| 117 | 1401 | }; | |
| 118 | 2806 | deps.messageCopied = [this](qint64 uid, const QString &targetFolder) { | |
| 119 | 4 | emit messageCopied(uid, targetFolder); | |
| 120 | 1401 | }; | |
| 121 | 1417 | deps.moveError = [this](const QString &error) { emit moveError(error); }; | |
| 122 | 1407 | deps.expungeComplete = [this] { emit expungeComplete(); }; | |
| 123 | 1406 | deps.expungeFailed = [this](const QString &error) { emit expungeFailed(error); }; | |
| 124 | 1406 | deps.errorOccurred = [this](const QString &error) { emit errorOccurred(error); }; | |
| 125 | 1401 | return std::make_unique<ImapMutationCommands>(*m_commands, *m_push, m_state, | |
| 126 | 1401 | m_selectedFolder, m_selectedUidValidity, | |
| 127 |
1/1✓ Branch 16 → 17 taken 1401 times.
|
4203 | m_capabilities, std::move(deps)); |
| 128 | 1401 | } | |
| 129 | |||
| 130 | // S92.1.7: the APPEND stream fails the session and emits the service's | ||
| 131 | // APPEND signals. | ||
| 132 | 1401 | std::unique_ptr<ImapAppendStream> ImapService::createAppendStream() { | |
| 133 | 1401 | ImapAppendStream::Deps deps; | |
| 134 | 1401 | deps.failConnection = [this](const QString &error) { failConnection(error); }; | |
| 135 | 2832 | deps.messageAppended = [this](const QString &folder, qint64 uid) { | |
| 136 | 30 | emit messageAppended(folder, uid); | |
| 137 | 1401 | }; | |
| 138 | 1413 | deps.appendError = [this](const QString &error) { emit appendError(error); }; | |
| 139 | 2832 | deps.appendCompleted = [this](quint64 requestId, const QString &folder, qint64 uid, quint32 uidValidity) { | |
| 140 | 30 | emit appendCompleted(requestId, folder, uid, uidValidity); | |
| 141 | 1401 | }; | |
| 142 | 2814 | deps.appendFailed = [this](quint64 requestId, const QString &error) { | |
| 143 | 12 | emit appendFailed(requestId, error); | |
| 144 | 1401 | }; | |
| 145 | #ifdef MAILJD_E2E_TESTING | ||
| 146 | 1004 | deps.reportE2eTransportPhase = [this](const QString &phase, quint64 requestToken) { | |
| 147 | 20 | reportE2eTransportPhase(phase, requestToken); | |
| 148 | 492 | }; | |
| 149 | #endif | ||
| 150 | 1401 | return std::make_unique<ImapAppendStream>(this, m_socket, *m_commands, *m_push, | |
| 151 |
2/2✓ Branch 12 → 13 taken 909 times.
✓ Branch 13 → 14 taken 492 times.
|
4203 | *m_mutations, m_state, std::move(deps)); |
| 152 | 1401 | } | |
| 153 | |||
| 154 | // S92.1.1: the line reader dispatches complete lines to this service and | ||
| 155 | // completes body requests through it; the active body request stays here. | ||
| 156 | 1401 | std::unique_ptr<ImapLineReader> ImapService::createLineReader() { | |
| 157 | 1401 | ImapLineReader::Deps deps; | |
| 158 | 101788 | deps.handleUntagged = [this](const QString &line) { handleUntagged(line); }; | |
| 159 | 1714 | deps.handleTagged = [this](const QString &line) { handleTagged(line); }; | |
| 160 | 1432 | deps.handleContinuation = [this](const QString &line) { m_append->handleContinuation(line); }; | |
| 161 | 1403 | deps.failConnection = [this](const QString &error) { failConnection(error); }; | |
| 162 | 2843 | deps.completeBodyRequest = [this](BodyOutcome outcome, QByteArray bytes, | |
| 163 | const QString &error, qint64 maxBytes) { | ||
| 164 |
1/1✓ Branch 5 → 6 taken 41 times.
|
41 | m_body->completeBodyRequest(outcome, std::move(bytes), error, maxBytes); |
| 165 | 1442 | }; | |
| 166 | 2838 | deps.rawBodyReceived = [this](qint64 uid, const QByteArray &rawBody) { | |
| 167 | 36 | emit rawBodyReceived(uid, rawBody); | |
| 168 | 1401 | }; | |
| 169 | 2806 | deps.bodyFetchTooLarge = [this](qint64 uid, qint64 maxBytes) { | |
| 170 | 4 | emit bodyFetchTooLarge(uid, maxBytes); | |
| 171 | 1401 | }; | |
| 172 | 4448 | deps.nowMs = [this] { return m_nowMs(); }; | |
| 173 | #ifdef MAILJD_E2E_TESTING | ||
| 174 | 1008 | deps.reportE2eTransportPhase = [this](const QString &phase, quint64 requestToken) { | |
| 175 | 24 | reportE2eTransportPhase(phase, requestToken); | |
| 176 | 492 | }; | |
| 177 | #endif | ||
| 178 | return std::make_unique<ImapLineReader>( | ||
| 179 | 2802 | m_socket, *m_commands, | |
| 180 | 2802 | ImapLineReader::BodyRequest{m_body->activeBodyFetchUid(), m_body->activeBodyFetchLimit(), | |
| 181 | 1401 | m_body->activeBodyFetchRequestBytes(), | |
| 182 | 1401 | m_body->bodyFetchRequiresSelect(), | |
| 183 | 1401 | m_body->activeBodyRequestId()}, | |
| 184 |
2/2✓ Branch 23 → 24 taken 909 times.
✓ Branch 24 → 25 taken 492 times.
|
4203 | std::move(deps)); |
| 185 | 1401 | } | |
| 186 |