summaryrefslogtreecommitdiff
path: root/src/imapserver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/imapserver.cc')
-rwxr-xr-xsrc/imapserver.cc221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/imapserver.cc b/src/imapserver.cc
new file mode 100755
index 0000000..003352b
--- /dev/null
+++ b/src/imapserver.cc
@@ -0,0 +1,221 @@
+/** --------------------------------------------------------------------
+ * @file imapserver.cc
+ * @brief Implementation of the IMAPServer class.
+ * @author Andreas Aardal Hanssen
+ * @date 2005
+ * --------------------------------------------------------------------
+ */
+#include "broker.h"
+#include "globals.h"
+#include "imapparser.h"
+#include "imapserver.h"
+#include "iodevice.h"
+#include "iofactory.h"
+#include "session.h"
+
+using namespace ::Binc;
+using namespace ::std;
+
+namespace Binc {
+ void showGreeting(void);
+};
+
+IMAPServer::IMAPServer(int argc, char **argv)
+{
+ this->argc = argc;
+ this->argv = argv;
+ this->stubMode = false;
+ Session::getInstance().setState(Session::AUTHENTICATED);
+}
+
+IMAPServer::~IMAPServer(void)
+{
+}
+
+int IMAPServer::initialize(void)
+{
+ Session &session = Session::getInstance();
+ if (!session.initialize(argc, argv)) return 111;
+ return 0;
+}
+
+void IMAPServer::prepareForNextRequest(void)
+{
+ serverStatus = OK;
+
+ bincClient.setFlags(IODevice::HasInputLimit);
+ bincClient.flush();
+ bincClient.setMaxInputBufferSize(INPUT_BUFFER_LIMIT);
+
+ Session::getInstance().setLastError("");
+ Session::getInstance().clearResponseCode();
+}
+
+int IMAPServer::runStub(void)
+{
+ bincDebug << "IMAPServer::runStub(), running stub" << endl;
+ this->stubMode = true;
+ Session::getInstance().setState(Session::NONAUTHENTICATED);
+ return run();
+}
+
+int IMAPServer::run(void)
+{
+ Session &session = Session::getInstance();
+ bincLog.setOutputLevelLimit(IODevice::InfoLevel);
+ string pid = 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;
+ 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
+
+ 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;
+}