diff options
Diffstat (limited to 'src/imapserver.cc')
-rwxr-xr-x | src/imapserver.cc | 221 |
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; +} |