Bincimap 2.0.17
Easy Imapping
Loading...
Searching...
No Matches
imapserver.cc
Go to the documentation of this file.
1
8#include <cstdint>
9#include "broker.h"
10#include "globals.h"
11#include "imapparser.h"
12#include "imapserver.h"
13#include "iodevice.h"
14#include "iofactory.h"
15#include "session.h"
16
17using namespace ::Binc;
18using namespace ::std;
19
20namespace Binc {
21 void showGreeting(void);
22};
23
24IMAPServer::IMAPServer(int argc, char **argv)
25{
26 this->argc = argc;
27 this->argv = argv;
28 this->stubMode = false;
29 Session::getInstance().setState(Session::AUTHENTICATED);
30}
31
32IMAPServer::~IMAPServer(void)
33{
34}
35
36int IMAPServer::initialize(void)
37{
38 Session &session = Session::getInstance();
39 if (!session.initialize(argc, argv)) return 111;
40 return 0;
41}
42
43void IMAPServer::prepareForNextRequest(void)
44{
45 serverStatus = OK;
46
47 bincClient.setFlags(IODevice::HasInputLimit);
48 bincClient.flush();
49 bincClient.setMaxInputBufferSize(INPUT_BUFFER_LIMIT);
50
51 Session::getInstance().setLastError("");
52 Session::getInstance().clearResponseCode();
53}
54
55int IMAPServer::runStub(void)
56{
57 bincDebug << "IMAPServer::runStub(), running stub" << endl;
58 this->stubMode = true;
59 Session::getInstance().setState(Session::NONAUTHENTICATED);
60 return run();
61}
62
63int IMAPServer::run(void)
64{
65 Session &session = Session::getInstance();
66 bincLog.setOutputLevelLimit(IODevice::InfoLevel);
67 string pid = to_string(session.getPid());
68 std::string ip = session.getEnv("TCPREMOTEIP");
69 std::string userID = session.getEnv("AUTH_USER");
70
71 bincDebug << "IMAPServer::run(), started server" << endl;
72
73 if (this->stubMode) {
74 if (session.hasEnv("PROTOCOLDUMP"))
75 bincClient.enableProtocolDumping();
76 bincLog << "bincimap-up: pid " << pid
77 << " Connected: " << ip << "\n";
79 } else {
80 bincLog << "bincimapd: pid " << pid << " Session::" << session.getEnv("AUTH") << " <"
81 << userID << "> from: " << ip << "\n";
82 }
83 bincLog.flush();
84
85 do {
86 bincDebug << "IMAPServer::run(), preparing for next request" << endl;
87
88 prepareForNextRequest();
89
90 // Find the current state's broker.
91 BrokerFactory &brokerFactory = BrokerFactory::getInstance();
92 Broker *broker = brokerFactory.getBroker(session.getState());
93
94 bincDebug << "IMAPServer::run(), found broker " << (uintptr_t) broker
95 << " for state " << session.getState() << endl;
96
97 bool skipToNextRequest = false;
98
99 // Parse the stub of the IMAP request.
100 Request clientRequest;
101 int stubParseResult = broker->parseStub(clientRequest);
102 if (stubParseResult == Operator::TIMEOUT) {
103 serverStatus = Timeout;
104 break;
105 } else if (stubParseResult == Operator::REJECT) {
106 serverStatus = RequestRejected;
107 } else if (stubParseResult == Operator::ERROR) {
108 serverStatus = RequestError;
109 } else {
110 // Find an operator that recognizes the name of the request, and
111 // have it continue the parsing.
112 Operator *o = broker->get(clientRequest.getName());
113 if (!o) {
114 serverStatus = RequestRejected;
115 string err = "The command \"";
116 if (clientRequest.getUidMode()) err += "UID ";
117 err += clientRequest.getName();
118 err += "\" is unsupported in this state. ";
119 session.setLastError(err);
120 skipToNextRequest = true;
121 } else {
122 int parseResult = o->parse(clientRequest);
123 if (parseResult == Operator::TIMEOUT) {
124 serverStatus = Timeout;
125 } else if (parseResult == Operator::REJECT) {
126 serverStatus = RequestRejected;
127 } else if (parseResult == Operator::ERROR) {
128 serverStatus = RequestError;
129 } else {
130 session.addStatement();
131 Depot *dep = session.getDepot();
132
133 int processResult = o->process(*dep, clientRequest);
134 if (processResult == Operator::OK) {
135 } else if (processResult == Operator::NO) {
136 serverStatus = RequestRejected;
137 } else if (processResult == Operator::BAD) {
138 serverStatus = RequestError;
139 } else if (processResult == Operator::NOTHING) {
140 serverStatus = RequestIgnore; // answer given already
141 } else if (processResult == Operator::ABORT) {
142 session.setState(Session::LOGOUT);
143 }
144 }
145 }
146 }
147
148 // If a syntax error was detected, we skip all characters in the
149 // input stream up to and including '\n'.
150 if (serverStatus == RequestRejected) {
151 bincClient << clientRequest.getTag() << " NO "
152 << session.getResponseCode()
153 << clientRequest.getName() << " failed: "
154 << session.getLastError() << endl;
155 } else if (serverStatus == RequestError) {
156 bincClient << "* BAD "
157 << session.getLastError() << endl;
158 skipToNextRequest = true;
159 } else if (serverStatus == RequestIgnore) {
160 ;
161 } else if (serverStatus == OK && session.getState() != Session::LOGOUT) {
162 bincClient << clientRequest.getTag() << " OK";
163 if (clientRequest.getUidMode()) bincClient << " UID";
164 bincClient << " " << session.getResponseCode()
165 << clientRequest.getName() << " completed";
166 if (clientRequest.getContextInfo() != "")
167 bincClient << " (" << clientRequest.getContextInfo() << ")";
168
169 bincClient << endl;
170 } else {
171 // Timeout, ClientDisconnected
172 session.setState(Session::LOGOUT);
173 }
174
175 bincClient.flush();
176
177 if (skipToNextRequest) {
178 if (!bincClient.skipTo('\n')) {
179 if (bincClient.getLastError() == IODevice::Timeout) {
180 serverStatus = Timeout;
181 } else
182 serverStatus = ClientDisconnected;
183 break;
184 }
185 }
186 } while (session.getState() != Session::LOGOUT); // do line 81
187
188 // Session finished - write some log information
189
190 if (this->stubMode) {
191 bincLog << "bincimap-up: pid " << pid
192 << " (Read: " << session.getReadBytes()
193 << " Written: " << session.getWriteBytes() << ")\n";
194 } else {
195 bincLog << "bincimapd: pid " << pid
196 << " (Bodies: " << session.getBodies()
197 << " Statements: " << session.getStatements() << ")\n";
198 }
199
200 if (serverStatus == Timeout) {
201 bincClient << "* BYE Timeout after " << session.timeout()
202 << " seconds of inactivity\n";
203 bincClient.flush();
204 bincLog << "bincimapd: pid " << pid << " Timed out: <" << userID << "> after "
205 << IDLE_TIMEOUT << "s";
206 } else if (serverStatus == ServerStatus::ClientDisconnected) {
207 bincLog << "bincimapd: pid " << pid << " Disconnected: " << ip << "\n";
208 } else {
209 if (this->stubMode) {
210 bincLog << "bincimap-up: pid " << pid << " Disconnected: " << ip << "\n";
211 } else {
212 bincLog << "bincimapd: pid " << pid << " Logged out: <" << userID << ">\n";
213 }
214 }
215 bincLog.flush();
216
217 return 0;
218}
Declaration of the Broker class.
Broker * getBroker(int state)
Definition: broker.cc:78
Operator * get(const std::string &name) const
Definition: broker.cc:106
Operator::ParseResult parseStub(Request &cmd)
Definition: broker.cc:114
virtual ParseResult parse(Request &) const =0
virtual ProcessResult process(Depot &, Request &)=0
const std::string & getTag(void) const
Definition: imapparser.cc:52
const std::string & getName(void) const
Definition: imapparser.cc:76
bool getUidMode(void) const
Definition: imapparser.cc:40
const std::string & getContextInfo(void) const
Definition: imapparser.cc:185
const int getState(void) const
Definition: session.cc:40
bool initialize(int argc, char *argv[])
void setLastError(const std::string &error) const
Definition: session.cc:185
void setState(int n)
Definition: session.cc:46
const std::string & getLastError(void) const
Definition: session.cc:179
int timeout() const
Definition: session.cc:218
Depot * getDepot(void) const
Definition: session.h:110
void addStatement(void)
Definition: session.cc:94
int getBodies(void) const
Definition: session.cc:112
int getWriteBytes(void) const
Definition: session.cc:124
int getReadBytes(void) const
Definition: session.cc:130
int getStatements(void) const
Definition: session.cc:118
pid_t getPid(void)
Definition: session.cc:209
const std::string & getResponseCode(void) const
Definition: session.cc:191
std::string getEnv(const std::string &key)
Definition: session.cc:230
bool hasEnv(const std::string &key) const
Definition: session.cc:224
Global constants.
Declaration of the common items for parsing IMAP input.
Declaration of the IMAPServer class.
Declaration of the IODevice class.
Declaration of the IOFactory class.
#define bincDebug
Definition: iofactory.h:46
#define bincLog
Definition: iofactory.h:50
#define bincClient
Definition: iofactory.h:31
Definition: bincimapd.cc:9
void showGreeting(void)
Definition: bincimapd.cc:10