blob: 7c913fb41b438fdf8b45aeb21170c194939a0a57 (
plain)
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
|
/**
* @file imapserver.cc
* @brief Implementation of the IMAPServer class.
* @author Andreas Aardal Hanssen
* @date 2005
*/
#include "imapserver.h"
#include "broker.h"
#include "globals.h"
#include "imapparser.h"
#include "iodevice.h"
#include "iofactory.h"
#include "session.h"
#include <cstdint>
using namespace Binc;
using std::endl;
namespace Binc {
void showGreeting();
};
IMAPServer::IMAPServer(int argc, char **argv)
{
this->argc = argc;
this->argv = argv;
this->stubMode = false;
Session::getInstance().setState(Session::AUTHENTICATED);
}
IMAPServer::~IMAPServer() {}
int IMAPServer::initialize()
{
Session &session = Session::getInstance();
if (!session.initialize(argc, argv)) return 111;
return 0;
}
void IMAPServer::prepareForNextRequest()
{
serverStatus = OK;
bincClient.setFlags(IODevice::HasInputLimit);
bincClient.flush();
bincClient.setMaxInputBufferSize(INPUT_BUFFER_LIMIT);
Session::getInstance().setLastError("");
Session::getInstance().clearResponseCode();
}
int IMAPServer::runStub()
{
bincDebug << "IMAPServer::runStub(), running stub" << endl;
this->stubMode = true;
Session::getInstance().setState(Session::NONAUTHENTICATED);
return run();
}
int IMAPServer::run()
{
Session &session = Session::getInstance();
bincLog.setOutputLevelLimit(IODevice::InfoLevel);
std::string pid = std::to_string(session.getPid());
bincDebug << "IMAPServer::run(), started server" << endl;
if (this->stubMode) {
if (session.hasEnv("PROTOCOLDUMP")) bincClient.enableProtocolDumping();
bincLog << "bincimap-up: pid " << pid << " Connected: <" << session.getIP() << ">\n";
showGreeting();
} else {
bincLog << "bincimapd: pid " << pid << " Logged in: <" << session.getEnv("USER") << "@"
<< session.getEnv("TCPREMOTEIP") << ">\n";
}
bincLog.flush();
do {
bincDebug << "IMAPServer::run(), preparing for next request" << endl;
prepareForNextRequest();
// Find the current state's broker.
BrokerFactory &brokerFactory = BrokerFactory::getInstance();
Broker *broker = brokerFactory.getBroker(session.getState());
bincDebug << "IMAPServer::run(), found broker " << (uintptr_t)broker << " for state "
<< session.getState() << endl;
bool skipToNextRequest = false;
// Parse the stub of the IMAP request.
Request clientRequest;
int stubParseResult = broker->parseStub(clientRequest);
if (stubParseResult == Operator::TIMEOUT) {
serverStatus = Timeout;
break;
} else if (stubParseResult == Operator::REJECT) {
serverStatus = RequestRejected;
} else if (stubParseResult == Operator::ERROR) {
serverStatus = RequestError;
} else {
// Find an operator that recognizes the name of the request, and
// have it continue the parsing.
Operator *o = broker->get(clientRequest.getName());
if (!o) {
serverStatus = RequestRejected;
std::string err = "The command \"";
if (clientRequest.getUidMode()) err += "UID ";
err += clientRequest.getName();
err += "\" is unsupported in this state. ";
session.setLastError(err);
skipToNextRequest = true;
} else {
int parseResult = o->parse(clientRequest);
if (parseResult == Operator::TIMEOUT) {
serverStatus = Timeout;
} else if (parseResult == Operator::REJECT) {
serverStatus = RequestRejected;
} else if (parseResult == Operator::ERROR) {
serverStatus = RequestError;
} else {
session.addStatement();
Depot *dep = session.getDepot();
int processResult = o->process(*dep, clientRequest);
if (processResult == Operator::OK) {
} else if (processResult == Operator::NO) {
serverStatus = RequestRejected;
} else if (processResult == Operator::BAD) {
serverStatus = RequestError;
} else if (processResult == Operator::NOTHING) {
serverStatus = RequestIgnore; // answer given already
} else if (processResult == Operator::ABORT) {
session.setState(Session::LOGOUT);
}
}
}
}
// If a syntax error was detected, we skip all characters in the
// input stream up to and including '\n'.
if (serverStatus == RequestRejected) {
bincClient << clientRequest.getTag() << " NO " << session.getResponseCode()
<< clientRequest.getName() << " failed: " << session.getLastError() << endl;
} else if (serverStatus == RequestError) {
bincClient << "* BAD " << session.getLastError() << endl;
skipToNextRequest = true;
} else if (serverStatus == RequestIgnore) {
;
} else if (serverStatus == OK && session.getState() != Session::LOGOUT) {
bincClient << clientRequest.getTag() << " OK";
if (clientRequest.getUidMode()) bincClient << " UID";
bincClient << " " << session.getResponseCode() << clientRequest.getName()
<< " completed";
if (clientRequest.getContextInfo() != "")
bincClient << " (" << clientRequest.getContextInfo() << ")";
bincClient << endl;
} else {
// Timeout, ClientDisconnected
session.setState(Session::LOGOUT);
}
bincClient.flush();
if (skipToNextRequest) {
if (!bincClient.skipTo('\n')) {
if (bincClient.getLastError() == IODevice::Timeout)
serverStatus = Timeout;
else
serverStatus = ClientDisconnected;
break;
}
}
} while (session.getState() != Session::LOGOUT); // do line 81
// Session finished - write some log information
std::string userID = this->stubMode ? session.getIP() : session.getEnv("USER");
if (this->stubMode) {
bincLog << "bincimap-up: pid " << pid << " (Read: " << session.getReadBytes()
<< " Written: " << session.getWriteBytes() << ")\n";
} else {
bincLog << "bincimapd: pid " << pid << " (Bodies: " << session.getBodies()
<< " Statements: " << session.getStatements() << ")\n";
}
if (serverStatus == Timeout) {
bincClient << "* BYE Timeout after " << session.timeout() << " seconds of inactivity\n";
bincClient.flush();
bincLog << "bincimapd: pid " << pid << " Timed out: <" << userID << "> after "
<< IDLE_TIMEOUT << "s";
} else if (serverStatus == ClientDisconnected) {
bincLog << "bincimapd: pid " << pid << "Disconnected: <" << userID << ">\n";
} else {
if (this->stubMode) {
bincLog << "bincimap-up: pid " << pid << " Logged out: <" << userID << ">\n";
} else {
bincLog << "bincimapd: pid " << pid << " Disconnected: <" << userID << ">\n";
}
}
bincLog.flush();
return 0;
}
|