main.c revision 1b04762685272a53643ac2179939537a44c7c044
0N/A/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
0N/A
0N/A#include "common.h"
0N/A#include "ioloop.h"
0N/A#include "istream.h"
0N/A#include "buffer.h"
0N/A#include "base64.h"
0N/A#include "restrict-access.h"
0N/A#include "fd-close-on-exec.h"
0N/A#include "process-title.h"
0N/A#include "master-service.h"
0N/A#include "var-expand.h"
0N/A#include "mail-storage-service.h"
0N/A
0N/A#include <stdio.h>
0N/A#include <stdlib.h>
0N/A#include <unistd.h>
0N/A
0N/A#define IS_STANDALONE() \
0N/A (getenv("LOGGED_IN") == NULL)
0N/A
0N/Astruct client_workaround_list {
0N/A const char *name;
0N/A enum client_workarounds num;
0N/A};
0N/A
0N/Astatic struct client_workaround_list client_workaround_list[] = {
0N/A { "outlook-no-nuls", WORKAROUND_OUTLOOK_NO_NULS },
0N/A { "oe-ns-eoh", WORKAROUND_OE_NS_EOH },
0N/A { NULL, 0 }
0N/A};
0N/A
0N/Astruct master_service *service;
0N/Avoid (*hook_client_created)(struct client **client) = NULL;
0N/A
0N/Astatic struct io *log_io = NULL;
0N/A
0N/Astatic void log_error_callback(void *context ATTR_UNUSED)
0N/A{
0N/A /* the log fd is closed, don't die when trying to log later */
0N/A i_set_failure_ignore_errors(TRUE);
0N/A
0N/A master_service_stop(service);
0N/A}
0N/A
0N/Astatic enum client_workarounds
0N/Aparse_workarounds(const struct pop3_settings *set)
0N/A{
0N/A enum client_workarounds client_workarounds = 0;
0N/A struct client_workaround_list *list;
0N/A const char *const *str;
0N/A
0N/A str = t_strsplit_spaces(set->pop3_client_workarounds, " ,");
0N/A for (; *str != NULL; str++) {
0N/A list = client_workaround_list;
0N/A for (; list->name != NULL; list++) {
0N/A if (strcasecmp(*str, list->name) == 0) {
0N/A client_workarounds |= list->num;
0N/A break;
0N/A }
0N/A }
0N/A if (list->name == NULL)
0N/A i_fatal("Unknown client workaround: %s", *str);
0N/A }
0N/A return client_workarounds;
0N/A}
0N/A
0N/Astatic enum uidl_keys parse_uidl_keymask(const char *format)
0N/A{
0N/A enum uidl_keys mask = 0;
0N/A
0N/A for (; *format != '\0'; format++) {
0N/A if (format[0] == '%' && format[1] != '\0') {
0N/A switch (var_get_key(++format)) {
0N/A case 'v':
0N/A mask |= UIDL_UIDVALIDITY;
0N/A break;
0N/A case 'u':
0N/A mask |= UIDL_UID;
0N/A break;
0N/A case 'm':
0N/A mask |= UIDL_MD5;
0N/A break;
0N/A case 'f':
0N/A mask |= UIDL_FILE_NAME;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A return mask;
0N/A}
0N/A
0N/Astatic bool main_init(const struct pop3_settings *set, struct mail_user *user)
0N/A{
0N/A struct client *client;
0N/A const char *str;
0N/A bool ret = TRUE;
0N/A
0N/A if (set->shutdown_clients) {
0N/A /* If master dies, the log fd gets closed and we'll quit */
0N/A log_io = io_add(STDERR_FILENO, IO_ERROR,
0N/A log_error_callback, NULL);
0N/A }
0N/A
0N/A clients_init();
0N/A
0N/A client = client_create(0, 1, user, set);
0N/A if (client == NULL)
0N/A return FALSE;
0N/A client->workarounds = parse_workarounds(set);
0N/A client->uidl_keymask = parse_uidl_keymask(set->pop3_uidl_format);
0N/A if (client->uidl_keymask == 0) {
0N/A i_fatal("pop3_uidl_format setting doesn't contain any "
0N/A "%% variables.");
0N/A }
0N/A
0N/A if (!IS_STANDALONE())
0N/A client_send_line(client, "+OK Logged in.");
0N/A
0N/A str = getenv("CLIENT_INPUT");
0N/A if (str != NULL) T_BEGIN {
0N/A buffer_t *buf = t_base64_decode_str(str);
0N/A if (buf->used > 0) {
0N/A if (!i_stream_add_data(client->input, buf->data,
0N/A buf->used))
0N/A i_panic("Couldn't add client input to stream");
0N/A ret = client_handle_input(client);
0N/A }
0N/A } T_END;
return ret;
}
static void main_deinit(void)
{
if (log_io != NULL)
io_remove(&log_io);
clients_deinit();
}
int main(int argc, char *argv[], char *envp[])
{
enum master_service_flags service_flags = 0;
enum mail_storage_service_flags storage_service_flags =
MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
struct mail_user *mail_user;
const struct pop3_settings *set;
const char *user;
int c;
#ifdef DEBUG
if (!IS_STANDALONE() && getenv("GDB") == NULL)
fd_debug_verify_leaks(3, 1024);
#endif
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
printf("-ERR pop3 binary must not be started from "
"inetd, use pop3-login instead.\n");
return 1;
}
if (IS_STANDALONE())
service_flags |= MASTER_SERVICE_FLAG_STANDALONE;
else
service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
service = master_service_init("pop3", service_flags, argc, argv);
while ((c = getopt(argc, argv, master_service_getopt_string())) > 0) {
if (!master_service_parse_option(service, c, optarg))
i_fatal("Unknown argument: %c", c);
}
user = getenv("USER");
if (user == NULL) {
if (IS_STANDALONE())
user = getlogin();
if (user == NULL)
i_fatal("USER environment missing");
}
mail_user = mail_storage_service_init_user(service, user,
&pop3_setting_parser_info,
storage_service_flags);
set = mail_storage_service_get_settings(service);
restrict_access_allow_coredumps(TRUE);
process_title_init(argv, envp);
/* fake that we're running, so we know if client was destroyed
while initializing */
io_loop_set_running(current_ioloop);
if (main_init(set, mail_user))
master_service_run(service);
main_deinit();
mail_storage_service_deinit_user();
master_service_deinit(&service);
return 0;
}