/usr/include/KF5/kimaptest/fakeserver.h is in libkf5imap-dev 15.12.3-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | /*
Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Kevin Ottens <kevin@kdab.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FAKESERVER_H
#define FAKESERVER_H
#include <QTcpSocket>
#include <QTcpServer>
#include <QThread>
#include <QMutex>
#include <QSsl>
namespace KIMAP
{
class ImapStreamParser;
}
Q_DECLARE_METATYPE(QList<QByteArray>)
/**
* Pretends to be an IMAP server for the purposes of unit tests.
*
* FakeServer does not really understand the IMAP protocol. Instead,
* you give it a script, or scenario, that lists how an IMAP session
* exchange should go. When it receives the client parts of the
* scenario, it will respond with the following server parts.
*
* The server can be furnished with several scenarios. The first
* scenario will be played out to the first client that connects, the
* second scenario to the second client connection and so on.
*
* The fake server runs as a separate thread in the same process it
* is started from, and listens for connections on port 5989 on the
* local machine.
*
* Scenarios are in the form of protocol messages, with a tag at the
* start to indicate whether it is message that will be sent by the
* client ("C:") or a response that should be sent by the server
* ("S:"). For example:
* @code
* C: A000001 LIST "" *
* S: * LIST ( \HasChildren ) / INBOX
* S: * LIST ( \HasNoChildren ) / INBOX/&AOQ- &APY- &APw- @ &IKw-
* S: * LIST ( \HasChildren ) / INBOX/lost+found
* S: * LIST ( \HasNoChildren ) / "INBOX/lost+found/Calendar Public-20080128"
* S: A000001 OK LIST completed
* @endcode
*
* A line starting with X indicates that the connection should be
* closed by the server. This should be the last line in the
* scenario. For example, the following simulates the server closing
* the connection after receiving too many bad commands:
* @code
* C: A000001 madhatter
* S: A000001 BAD Command madhatter
* X
* @endcode
*
* FakeServer::preauth() and FakeServer::greeting() provide standard
* PREAUTH and OK responses, respectively, that can be used (unmodified)
* as the first line of a scenario.
*
* A typical usage is something like
* @code
* QList<QByteArray> scenario;
* scenario << FakeServer::preauth()
* << "C: A000001 CAPABILITY"
* << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI"
* << "S: A000001 OK CAPABILITY completed";
*
* FakeServer fakeServer;
* fakeServer.setScenario( scenario );
* fakeServer.startAndWait();
*
* KIMAP::Session session( QStringLiteral("127.0.0.1"), 5989 );
* KIMAP::CapabilitiesJob *job = new KIMAP::CapabilitiesJob(&session);
* QVERIFY( job->exec() );
* // check the returned capabilities
*
* fakeServer.quit();
* @endcode
*/
class FakeServer : public QThread
{
Q_OBJECT
public:
/**
* Get the default PREAUTH response
*
* This is the initial PREAUTH message that the server
* sends at the start of a session to indicate that the
* user is already authenticated by some other mechanism.
*
* Can be used as the first line in a scenario where
* you want to skip the LOGIN stage of the protocol.
*/
static QByteArray preauth();
/**
* Get the default greeting
*
* This is the initial OK message that the server sends at the
* start of a session to indicate that a LOGIN is required.
*
* Can be used as the first line in a scenario where
* you want to use the LOGIN command.
*/
static QByteArray greeting();
FakeServer(QObject *parent = Q_NULLPTR);
~FakeServer();
/**
* Sets the encryption mode used by the server socket.
*/
void setEncrypted(QSsl::SslProtocol protocol);
/**
* Starts the server and waits for it to be ready
*
* You should use this instead of start() to avoid race conditions.
*/
void startAndWait();
/**
* Starts the fake IMAP server
*
* You should not call this directly. Use start() instead.
*
* @reimp
*/
virtual void run();
/**
* Removes any previously-added scenarios, and adds a new one
*
* After this, there will only be one scenario, and so the fake
* server will only be able to service a single request. More
* scenarios can be added with addScenario, though.
*
* @see addScenario()\n
* addScenarioFromFile()
*/
void setScenario(const QList<QByteArray> &scenario);
/**
* Adds a new scenario
*
* Note that scenarios will be used in the order that clients
* connect. If this is the 5th scenario that has been added
* (bearing in mind that setScenario() resets the scenario
* count), it will be used to service the 5th client that
* connects.
*
* @see addScenarioFromFile()
*
* @param scenario the scenario as a list of messages
*/
void addScenario(const QList<QByteArray> &scenario);
/**
* Adds a new scenario from a local file
*
* Note that scenarios will be used in the order that clients
* connect. If this is the 5th scenario that has been added
* (bearing in mind that setScenario() resets the scenario
* count), it will be used to service the 5th client that
* connects.
*
* @see addScenario()
*
* @param fileName the name of the file that contains the
* scenario; it will be split at line
* boundaries, and excess whitespace will
* be trimmed from the start and end of lines
*/
void addScenarioFromFile(const QString &fileName);
/**
* Checks whether a particular scenario has completed
*
* @param scenarioNumber the number of the scenario to check,
* in order of addition/client connection
*/
bool isScenarioDone(int scenarioNumber) const;
/**
* Whether all the scenarios that were added to the fake
* server have been completed.
*/
bool isAllScenarioDone() const;
protected:
/**
* Whether the received content is the same as the expected.
* Use QCOMPARE, if creating subclasses.
*/
virtual void compareReceived(const QByteArray &received, const QByteArray &expected) const;
private Q_SLOTS:
void newConnection();
void dataAvailable();
void started();
private:
void writeServerPart(int scenarioNumber);
void readClientPart(int scenarioNumber);
QList< QList<QByteArray> > m_scenarios;
QTcpServer *m_tcpServer;
mutable QMutex m_mutex;
QList<QTcpSocket *> m_clientSockets;
QList<KIMAP::ImapStreamParser *> m_clientParsers;
bool m_encrypted;
bool m_starttls;
QSsl::SslProtocol m_sslProtocol;
};
#endif
|