/** * @file session-initialize-bincimapd.cc * @brief <---> * @author Andreas Aardal Hanssen, Erwin Hoffmann * @date 2002-2005, 2023 */ #include "broker.h" #include "convert.h" #include "depot.h" #include "globals.h" #include "imapserver.h" #include "iodevice.h" #include "iofactory.h" #include "maildir.h" #include "multilogdevice.h" #include "session.h" #include "stdiodevice.h" #include "syslogdevice.h" #include "tools.h" #include #include #include #include #include #include using namespace Binc; using std::endl; using std::string; bool Session::initialize(int argc, char *argv[]) { IOFactory &ioFactory = IOFactory::getInstance(); IODevice *stdioDevice = new StdIODevice(IODevice::IsEnabled | IODevice::HasInputLimit | IODevice::HasTimeout); stdioDevice->setFlags(IODevice::HasOutputLimit); stdioDevice->setMaxOutputBufferSize(TRANSFER_BUFFER_SIZE); ioFactory.addDevice(stdioDevice); Session &session = Session::getInstance(); // Read command line arguments if (!session.parseCommandLine(argc, argv)) return false; // Show help if asked for it if (session.command.help) { printf("%s\n", session.args.usageString().c_str()); return false; } // Show version if asked for it if (session.command.version) { printf("Binc IMAP v" BINC_VERSION "\n"); return false; } // Assign command line arguments to global config. session.assignCommandLineArgs(); // log settings string ip = Tools::getenv("TCP6REMOTEIP") .value_or(Tools::getenv("TCPREMOTEIP").value_or("?")); session.setIP(ip); string logtype = session.getEnv("LOG_TYPE"); lowercase(logtype); trim(logtype); if (logtype == "" || logtype == "multilog") { ioFactory.addDevice(new MultilogDevice(IODevice::IsEnabled)); } else if (logtype == "syslog") { const string f = session.getEnv("SYSLOG_FACILITY"); int facility; if (isdigit(f[0])) facility = atoi(f); else if (f == "LOG_USER") facility = LOG_USER; else if (f == "LOG_LOCAL0") facility = LOG_LOCAL0; else if (f == "LOG_LOCAL1") facility = LOG_LOCAL1; else if (f == "LOG_LOCAL2") facility = LOG_LOCAL2; else if (f == "LOG_LOCAL3") facility = LOG_LOCAL3; else if (f == "LOG_LOCAL4") facility = LOG_LOCAL4; else if (f == "LOG_LOCAL5") facility = LOG_LOCAL5; else if (f == "LOG_LOCAL6") facility = LOG_LOCAL6; else if (f == "LOG_LOCAL7") facility = LOG_LOCAL7; else facility = LOG_DAEMON; session.setEnv("SYSLOG_FACILITY", toString(facility)); ioFactory.addDevice( new SyslogDevice(IODevice::IsEnabled, "bincimapd", LOG_NDELAY | LOG_PID, facility)); } // Now that we know the log type, we can flush. IOFactory::getLogger().flush(); IOFactory::getLogger().setFlags(IODevice::FlushesOnEndl); IOFactory::getLogger().setOutputLevelLimit(IODevice::LogLevel::InfoLevel); string pid = std::to_string(session.getPid()); auto logindetails = Tools::getenv("BINCIMAP_LOGIN"); if (!logindetails) { bincLog << "bincimapd: pid " << pid << " BINCIMAP_LOGIN missing from environment (are you sure you invoked " << argv[0] << " properly?)\n"; return false; } DepotFactory &depotfactory = DepotFactory::getInstance(); depotfactory.assign(new IMAPdirDepot()); depotfactory.assign(new MaildirPPDepot()); string depottype = session.getEnv("DEPOT"); if (depottype == "") depottype = "Maildir++"; if ((depot = depotfactory.get(depottype)) == nullptr) { bincLog << "bincimapd: pid " << pid << " Found no Depot for: " << depottype << ". Please check your configurations file under the Mailbox section\n"; bincLog.flush(); return false; } depot->assign(new Maildir()); depot->setDefaultType("Maildir"); // Configurable delimiter to ease crossover from other IMAPservers string delimiter = session.getEnv("DELIMITER"); if (delimiter != "") depot->setDelimiter(delimiter[0]); BrokerFactory &brokerfactory = BrokerFactory::getInstance(); brokerfactory.assign("APPEND", new AppendOperator()); brokerfactory.assign("CAPABILITY", new CapabilityOperator()); brokerfactory.assign("CHECK", new CheckOperator()); brokerfactory.assign("CLOSE", new CloseOperator()); brokerfactory.assign("COPY", new CopyOperator()); brokerfactory.assign("CREATE", new CreateOperator()); brokerfactory.assign("DELETE", new DeleteOperator()); brokerfactory.assign("EXAMINE", new ExamineOperator()); brokerfactory.assign("EXPUNGE", new ExpungeOperator()); brokerfactory.assign("FETCH", new FetchOperator()); brokerfactory.assign("IDLE", new IdleOperator()); brokerfactory.assign("ID", new IdOperator()); brokerfactory.assign("LIST", new ListOperator()); brokerfactory.assign("LOGOUT", new LogoutOperator()); brokerfactory.assign("LSUB", new LsubOperator()); brokerfactory.assign("NAMESPACE", new NamespaceOperator()); brokerfactory.assign("NOOP", new NoopPendingOperator()); brokerfactory.assign("RENAME", new RenameOperator()); brokerfactory.assign("SEARCH", new SearchOperator()); brokerfactory.assign("SELECT", new SelectOperator()); brokerfactory.assign("STATUS", new StatusOperator()); brokerfactory.assign("STORE", new StoreOperator()); brokerfactory.assign("SUBSCRIBE", new SubscribeOperator()); brokerfactory.assign("UNSUBSCRIBE", new UnsubscribeOperator()); // automatically create depot directory if it's not there already string path; if (session.args.getUnqualifiedArgs().size() > 0) path = session.args.getUnqualifiedArgs()[0]; if (path == "") { path = "."; } else if (chdir(path.c_str()) != 0) { mkdir(path.c_str(), 0777); if (chdir(path.c_str()) != 0) { bincLog << "bincimapd: pid" << pid << " Error entering depot " + toImapString(path) + ": " << strerror(errno) << endl; return false; } } // automatically create INBOX if it's not there already if (depot->get("INBOX") == 0 && !depot->createMailbox("INBOX")) { bincLog << "bincimapd: pid " << pid << " " << depot->getLastError() << endl; return false; } // load subscription list depot->loadSubscribes(); session.setState(Session::AUTHENTICATED); const string details = *logindetails; string::size_type det = details.find('+'); if (det == string::npos) { bincLog << "bincimapd: pid " << pid << " Invalid content of BINCIMAP_LOGIN - did you invoke " << argv[0] << " correctly?" << endl; return false; } const string tag = details.substr(det + 1); const string command = details.substr(0, det); bincClient << tag << " OK " << command << " completed" << endl; bincClient.flush(); bincClient.setTimeout(IDLE_TIMEOUT); return true; }