From 022bd2b4a123c7860a7c9529e253c569c1613933 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 28 May 2007 22:14:21 -0400 Subject: [PATCH] Get native Win32 mode working (at least in a basic state). Makefile.win32: Use mail-smtp backend. Fix main build rule. src/ioset-win32.c (ioset_win32_init): Return values appropriately. (ioset_win32_loop): Update "now" before dispatching events. src/ioset.c: Add errno kludges to work properly on Win32. Use send() and recv() rather than write() and read(). Use simple comparisons rather than switch statements with only one case. src/mail-smtp.c: Initial pass at SMTP backend for mail service. Does not yet try to send the mail body, and has not been tested. src/main-common.c: Move usage(), version(), license() to here .. src/main.c: .. from here. src/main-win32.c: Parse command-line options. --- Makefile.win32 | 6 +- src/ioset-win32.c | 8 +- src/ioset.c | 67 +++++-- src/mail-smtp.c | 449 +++++++++++++++++++++++++++++++++++++++++++ src/main-common.c | 43 +++++ src/main-win32.c | 85 +++++++- src/main.c | 42 +--- src/mod-qserver.help | 0 src/mod-snoop.help | 0 9 files changed, 643 insertions(+), 57 deletions(-) create mode 100644 src/mail-smtp.c create mode 100644 src/mod-qserver.help create mode 100644 src/mod-snoop.help diff --git a/Makefile.win32 b/Makefile.win32 index 14f68f6..24c2419 100644 --- a/Makefile.win32 +++ b/Makefile.win32 @@ -58,17 +58,17 @@ SRVX_OBJS = \ src/proto-$(PROTOCOL).o \ src/recdb.o \ src/saxdb.o \ - src/sendmail.o \ + src/mail-smtp.o \ src/timeq.o \ src/tools.o \ $(addsuffix .o,$(addprefix src/mod-,$(MODULES))) srvx$(EXE_EXT): src/config.h src/modules-list.h $(RX_OBJS) $(SRVX_OBJS) - $(CC) -o $< $(RX_OBJS) $(SRVX_OBJS) $(LIBS) + $(CC) -o $@ $(RX_OBJS) $(SRVX_OBJS) $(LIBS) src/config.h: $(VPATH)/src/config.h.win32 cp $< $@ src/modules-list.h: - rm -f $@; \ + rm -f $@ ; \ for module in $(MODULES) ; do \ echo "WITH_MODULE($$module)" >> $@ ; \ done diff --git a/src/ioset-win32.c b/src/ioset-win32.c index d58696a..15b3cbd 100644 --- a/src/ioset-win32.c +++ b/src/ioset-win32.c @@ -103,6 +103,7 @@ ioset_win32_init(void) if (res) { log_module(MAIN_LOG, LOG_FATAL, "Unable to start Windows Sockets (%d)", res); + return 0; } // Get Windows HINSTANCE. @@ -117,15 +118,17 @@ ioset_win32_init(void) if (!RegisterClassEx(&wcx)) { log_module(MAIN_LOG, LOG_FATAL, "Unable to register window class (%lu)", GetLastError()); + return 0; } ioset_window = CreateWindow("srvxMainWindow", PACKAGE_STRING, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL); if (!ioset_window) { log_module(MAIN_LOG, LOG_FATAL, "Unable to create window (%lu)", GetLastError()); + return 0; } - return 0; + return 1; } static long @@ -253,6 +256,9 @@ ioset_win32_loop(struct timeval *timeout) } else { + extern int clock_skew; + + now = time(NULL) + clock_skew; TranslateMessage(&msg); DispatchMessage(&msg); } diff --git a/src/ioset.c b/src/ioset.c index 861b3ae..4b6225e 100644 --- a/src/ioset.c +++ b/src/ioset.c @@ -31,6 +31,55 @@ #include #endif +#ifdef WITH_IOSET_WIN32 + +# undef errno +# define errno WSAGetLastError() +# undef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +# undef EHOSTUNREACH +# define EHOSTUNREACH WSAEHOSTUNREACH +# undef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +# undef EAGAIN +# define EAGAIN WSAEWOULDBLOCK +# define strerror wsa_strerror + +static const char * +wsa_strerror(int wsa_err) +{ + switch (wsa_err) + { + case WSAEINTR: return "Operation interrupted"; + case WSAEBADF: return "Bad file descriptor"; + case WSAEACCES: return "Permission denied"; + case WSAEFAULT: return "Invalid address"; + case WSAEINVAL: return "Invalid parameter"; + case WSAEMFILE: return "Too many open files"; + case WSAEWOULDBLOCK: return "Try again later"; + case WSAEINPROGRESS: return "Operation in progress"; + case WSAEALREADY: return "Operation already in progress"; + case WSAENOTSOCK: return "Not a socket"; + case WSAEDESTADDRREQ: return "Destination address required"; + case WSAEMSGSIZE: return "Invalid message size"; + case WSAEPROTOTYPE: return "Invalid protocol type for socket"; + case WSAENOPROTOOPT: return "Invalid protocol option"; + case WSAEPROTONOSUPPORT: return "Protocol not supported"; + case WSAEOPNOTSUPP: return "Operation not supported"; + case WSAEADDRINUSE: return "Address already in use"; + case WSAEADDRNOTAVAIL: return "Address not available"; + case WSAENETDOWN: return "Network down"; + case WSAENETUNREACH: return "Network unreachable"; + case WSAENETRESET: return "Network reset"; + case WSAECONNABORTED: return "Connection aborted"; + case WSAECONNRESET: return "Connection reset by peer"; + case WSAECONNREFUSED: return "Connection refused"; + } + return "unknown error"; +} + +#endif /* WITH_IOSET_WIN32 */ + #define IS_EOL(CH) ((CH) == '\n') extern int uplink_connect(void); @@ -290,13 +339,10 @@ ioset_try_write(struct io_fd *fd) { unsigned int req; req = ioq_get_avail(&fd->send); - res = write(fd->fd, fd->send.buf+fd->send.get, req); + res = send(fd->fd, fd->send.buf+fd->send.get, req, 0); if (res < 0) { - switch (errno) { - case EAGAIN: - break; - default: - log_module(MAIN_LOG, LOG_ERROR, "write() on fd %d error %d: %s", fd->fd, errno, strerror(errno)); + if (errno != EAGAIN) { + log_module(MAIN_LOG, LOG_ERROR, "send() on fd %d error %d: %s", fd->fd, errno, strerror(errno)); } } else { fd->send.get += res; @@ -396,13 +442,10 @@ ioset_buffered_read(struct io_fd *fd) { if (!(put_avail = ioq_put_avail(&fd->recv))) put_avail = ioq_grow(&fd->recv); - nbr = read(fd->fd, fd->recv.buf + fd->recv.put, put_avail); + nbr = recv(fd->fd, fd->recv.buf + fd->recv.put, put_avail, 0); if (nbr < 0) { - switch (errno) { - case EAGAIN: - break; - default: - log_module(MAIN_LOG, LOG_ERROR, "Unexpected read() error %d on fd %d: %s", errno, fd->fd, strerror(errno)); + if (errno != EAGAIN) { + log_module(MAIN_LOG, LOG_ERROR, "Unexpected recv() error %d on fd %d: %s", errno, fd->fd, strerror(errno)); /* Just flag it as EOF and call readable_cb() to notify the fd's owner. */ fd->state = IO_CLOSED; fd->readable_cb(fd); diff --git a/src/mail-smtp.c b/src/mail-smtp.c new file mode 100644 index 0000000..85b68d9 --- /dev/null +++ b/src/mail-smtp.c @@ -0,0 +1,449 @@ +/* mail-smtp.c - mail sending utilities + * Copyright 2007 srvx Development Team + * + * This file is part of srvx. + * + * srvx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with srvx; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ioset.h" + +static void mail_println(const char *fmt, ...); + +#include "mail-common.c" + +struct pending_mail { + const char *from; + const char *to_name; + const char *to_email; + const char *subject; + const char *body; + int first_time; +}; + +DECLARE_LIST(mail_queue, struct pending_mail *); + +enum smtp_socket_state { + CLOSED, /* no connection active */ + CONNECTING, /* initial connection in progress */ + WAITING_GREETING, /* waiting for server to send 220 */ + IDLE, /* between messages, waiting to see if we get a new one soon */ + SENT_EHLO, /* sent EHLO , waiting for response */ + SENT_HELO, /* sent HELO , waiting for response */ + SENT_MAIL_FROM, /* sent MAIL FROM:
, waiting for response */ + SENT_RCPT_TO, /* sent RCPT TO:
, waiting for response */ + SENT_DATA, /* sent DATA, waiting for response */ + SENT_BODY, /* sent message body, waiting for response */ + SENT_RSET, /* sent RSET, waiting for response */ + SENT_QUIT, /* asked server to close connection, waiting for response */ +}; + +static const char * const smtp_state_names[] = { + "closed", + "connecting", + "greeting", + "idle", + "ehlo", + "helo", + "mail-from", + "rcpt-to", + "data", + "body", + "rset", + "quit", +}; + +static struct pending_mail *active_mail; +static struct log_type *MAIL_LOG; +static struct io_fd *smtp_fd; +static enum smtp_socket_state smtp_state; +static struct mail_queue mail_queue; + +static struct { + const char *smtp_server; + const char *smtp_service; + const char *smtp_myname; + const char *smtp_from; + int enabled; +} smtp_conf; + +DEFINE_LIST(mail_queue, struct pending_mail *); + +static void mail_println(const char *fmt, ...) +{ + char tmpbuf[1024]; + va_list ap; + int res; + + va_start(ap, fmt); + res = vsnprintf(tmpbuf, sizeof(tmpbuf) - 2, fmt, ap); + va_end(ap); + if (res > 0 && (size_t)res <= sizeof(tmpbuf) - 2) + { + tmpbuf[res++] = '\r'; + tmpbuf[res++] = '\n'; + ioset_write(smtp_fd, tmpbuf, res); + } +} + +static void mail_smtp_read_config(void) +{ + dict_t conf_node; + const char *str; + + memset(&smtp_conf, 0, sizeof(smtp_conf)); + conf_node = conf_get_data("mail", RECDB_OBJECT); + if (!conf_node) + return; + str = database_get_data(conf_node, "enabled", RECDB_QSTRING); + smtp_conf.enabled = (str != NULL) && enabled_string(str); + smtp_conf.smtp_server = database_get_data(conf_node, "smtp_server", RECDB_QSTRING); + if (!smtp_conf.smtp_server) + log_module(MAIL_LOG, LOG_FATAL, "No mail smtp_server configuration setting."); + str = database_get_data(conf_node, "smtp_service", RECDB_QSTRING); + if (!str) str = "25"; + smtp_conf.smtp_service = str; + smtp_conf.smtp_myname = database_get_data(conf_node, "smtp_myname", RECDB_QSTRING); + /* myname defaults to [ip.v4.add.r] */ + smtp_conf.smtp_from = database_get_data(conf_node, "from_address", RECDB_QSTRING); + if (!smtp_conf.smtp_from) + log_module(MAIL_LOG, LOG_FATAL, "No mail from_address configuration setting."); +} + +static void smtp_fill_name(char *namebuf, size_t buflen) +{ + char sockaddr[128]; + struct sockaddr *sa; + socklen_t sa_len; + int res; + + sa = (void*)sockaddr; + sa_len = sizeof(sockaddr); + res = getsockname(smtp_fd->fd, sa, &sa_len); + if (res < 0) { + log_module(MAIL_LOG, LOG_ERROR, "Unable to get SMTP socket name: %s", strerror(errno)); + namebuf[0] = '\0'; + } + res = getnameinfo(sa, sa_len, namebuf, buflen, NULL, 0, NI_NUMERICHOST); + if (res != 0) { + log_module(MAIL_LOG, LOG_ERROR, "Unable to get text form of socket name: %s", strerror(errno)); + } +} + +static void smtp_handle_greeting(const char *linebuf, short code) +{ + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_ERROR, "SMTP server error on connection: %s", linebuf); + ioset_close(smtp_fd, 1); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error on connection: %s", linebuf); + ioset_close(smtp_fd, 1); + } else { + if (smtp_conf.smtp_myname) { + mail_println("EHLO %s", smtp_conf.smtp_myname); + } else { + char namebuf[64]; + smtp_fill_name(namebuf, sizeof(namebuf)); + mail_println("EHLO [%s]", namebuf); + } + smtp_state = SENT_EHLO; + } +} + +static void discard_mail(void) +{ + mail_queue_remove(&mail_queue, active_mail); + free(active_mail); + active_mail = NULL; + mail_println("RSET"); + smtp_state = SENT_RSET; +} + +static void smtp_idle_work(void) +{ + if ((smtp_state != IDLE) || (mail_queue.used == 0)) + return; + active_mail = mail_queue.list[0]; + mail_println("MAIL FROM:<%s>", smtp_conf.smtp_from); + smtp_state = SENT_MAIL_FROM; +} + +static void smtp_handle_ehlo(const char *linebuf, short code) +{ + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_DEBUG, "Falling back from EHLO to HELO"); + if (smtp_conf.smtp_myname) { + mail_println("HELO %s", smtp_conf.smtp_myname); + } else { + char namebuf[64]; + smtp_fill_name(namebuf, sizeof(namebuf)); + mail_println("HELO [%s]", namebuf); + } + smtp_state = SENT_HELO; + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after EHLO: %s", linebuf); + ioset_close(smtp_fd, 1); + } else { + smtp_state = IDLE; + smtp_idle_work(); + } +} + +static void smtp_handle_helo(const char *linebuf, short code) +{ + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after HELO: %s", linebuf); + ioset_close(smtp_fd, 1); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after HELO: %s", linebuf); + ioset_close(smtp_fd, 1); + } else { + smtp_state = IDLE; + smtp_idle_work(); + } +} + +static void smtp_handle_mail_from(const char *linebuf, short code) +{ + assert(active_mail != NULL); + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_ERROR, "SMTP server error after MAIL FROM: %s", linebuf); + discard_mail(); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after MAIL FROM: %s", linebuf); + } else { + mail_println("RCPT TO:<%s>", active_mail->to_email); + smtp_state = SENT_RCPT_TO; + } +} + +static void smtp_handle_rcpt_to(const char *linebuf, short code) +{ + assert(active_mail != NULL); + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_ERROR, "SMTP server error after RCPT TO: %s", linebuf); + discard_mail(); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after RCPT TO: %s", linebuf); + } else { + mail_println("DATA"); + smtp_state = SENT_DATA; + } +} + +static void smtp_handle_data(const char *linebuf, short code) +{ + assert(active_mail != NULL); + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_ERROR, "SMTP server error after DATA: %s", linebuf); + discard_mail(); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after DATA: %s", linebuf); + } else { + /* TODO: print the mail contents properly */ + smtp_state = SENT_BODY; + } +} + +static void smtp_handle_body(const char *linebuf, short code) +{ + assert(active_mail != NULL); + if (linebuf[3] == '-') { + return; + } else if (code >= 500) { + log_module(MAIL_LOG, LOG_ERROR, "SMTP server error after DATA: %s", linebuf); + discard_mail(); + } else if (code >= 400) { + log_module(MAIL_LOG, LOG_WARNING, "SMTP server error after DATA: %s", linebuf); + } else { + log_module(MAIL_LOG, LOG_INFO, "Sent mail to %s <%s>: %s", active_mail->to_name, active_mail->to_email, active_mail->subject); + mail_queue_remove(&mail_queue, active_mail); + free(active_mail); + active_mail = NULL; + smtp_state = IDLE; + if (mail_queue.used > 0) + smtp_idle_work(); + } +} + +static void smtp_handle_rset(const char *linebuf, short code) +{ + assert(active_mail != NULL); + smtp_state = IDLE; + if (mail_queue.used > 0) + smtp_idle_work(); + (void)linebuf; (void)code; +} + +static void mail_readable(struct io_fd *fd) +{ + char linebuf[1024]; + int nbr; + short code; + + assert(fd == smtp_fd); + + /* Try to read a line from the socket. */ + nbr = ioset_line_read(fd, linebuf, sizeof(linebuf)); + if (nbr < 0) { + /* should only happen when there is no complete line */ + log_module(MAIL_LOG, LOG_DEBUG, "Unexpectedly got empty line in mail_readable()."); + return; + } else if (nbr == 0) { + log_module(MAIL_LOG, LOG_DEBUG, "Mail connection has been closed."); + ioset_close(fd, 1); + return; + } else if ((size_t)nbr > sizeof(linebuf)) { + log_module(MAIL_LOG, LOG_WARNING, "Got %u-byte line from server, truncating to 1024 bytes.", nbr); + nbr = sizeof(linebuf); + linebuf[nbr - 1] = '\0'; + } + + /* Trim CRLF at end of line */ + while (linebuf[nbr - 1] == '\r' || linebuf[nbr - 1] == '\n') + linebuf[--nbr] = '\0'; + + /* Check that the input line looks reasonable. */ + if (!isdigit(linebuf[0]) || !isdigit(linebuf[1]) || !isdigit(linebuf[2]) + || (linebuf[3] != ' ' && linebuf[3] != '-')) + { + log_module(MAIL_LOG, LOG_ERROR, "Got malformed SMTP line: %s", linebuf); + } + code = strtoul(linebuf, NULL, 10); + + /* Log it at debug level. */ + log_module(MAIL_LOG, LOG_REPLAY, "S[%s]: %s", smtp_state_names[smtp_state], linebuf); + + /* Dispatch line based on connection's current state. */ + switch (smtp_state) + { + case CLOSED: + log_module(MAIL_LOG, LOG_ERROR, "Unexpectedly got readable callback when SMTP in CLOSED state."); + break; + case CONNECTING: + log_module(MAIL_LOG, LOG_ERROR, "Unexpectedly got readable callback when SMTP in CONNECTING state."); + break; + case WAITING_GREETING: + smtp_handle_greeting(linebuf, code); + break; + case SENT_EHLO: + smtp_handle_ehlo(linebuf, code); + break; + case SENT_HELO: + smtp_handle_helo(linebuf, code); + break; + case SENT_MAIL_FROM: + smtp_handle_mail_from(linebuf, code); + break; + case SENT_RCPT_TO: + smtp_handle_rcpt_to(linebuf, code); + break; + case SENT_DATA: + smtp_handle_data(linebuf, code); + break; + case SENT_BODY: + smtp_handle_body(linebuf, code); + break; + case SENT_RSET: + smtp_handle_rset(linebuf, code); + break; + case IDLE: + case SENT_QUIT: + /* there's not much we can do to sensibly handle these cases */ + break; + } +} + +static void mail_destroyed(struct io_fd *fd) +{ + assert(smtp_fd == fd); + smtp_state = CLOSED; + smtp_fd = NULL; +} + +static void mail_connected(struct io_fd *fd, int error) +{ + if (error) + { + log_module(MAIL_LOG, LOG_ERROR, "Unable to connect to SMTP server: %s", strerror(error)); + smtp_state = CLOSED; + smtp_fd = NULL; + return; + } + + fd->line_reads = 1; + fd->readable_cb = mail_readable; + fd->destroy_cb = mail_destroyed; + smtp_state = WAITING_GREETING; +} + +void +mail_send(struct userNode *from, struct handle_info *to, const char *subject, const char *body, int first_time) +{ + struct pending_mail *new_mail; + char *pos; + size_t from_len; + size_t to_name_len; + size_t to_email_len; + size_t subj_len; + size_t body_len; + + /* Build a new pending_mail structure. */ + from_len = strlen(from->nick) + 1; + to_name_len = strlen(to->handle) + 1; + to_email_len = strlen(to->email_addr) + 1; + subj_len = strlen(subject) + 1; + body_len = strlen(body) + 1; + new_mail = malloc(sizeof(*new_mail) + from_len + to_name_len + to_email_len + subj_len + body_len); + pos = (char*)(new_mail + 1); + new_mail->from = memcpy(pos, from->nick, from_len), pos += from_len; + new_mail->to_name = memcpy(pos, to->handle, to_name_len), pos += to_name_len; + new_mail->to_email = memcpy(pos, to->email_addr, to_email_len), pos += to_email_len; + new_mail->subject = memcpy(pos, subject, subj_len), pos += subj_len; + new_mail->body = memcpy(pos, body, body_len), pos += body_len; + new_mail->first_time = first_time; + + /* Stick the structure onto the pending list and ask for a transmit. */ + mail_queue_append(&mail_queue, new_mail); + + /* Initiate a mail connection if necessary; otherwise, poke an idle one. */ + if (!smtp_fd) { + smtp_state = CONNECTING; + smtp_fd = ioset_connect(NULL, 0, smtp_conf.smtp_server, strtoul(smtp_conf.smtp_service, NULL, 10), 0, NULL, mail_connected); + } else if (smtp_state == IDLE) { + smtp_idle_work(); + } +} + +void +mail_init(void) +{ + smtp_state = CLOSED; + MAIL_LOG = log_register_type("mail", "file:mail.log"); + mail_common_init(); + conf_register_reload(mail_smtp_read_config); +} diff --git a/src/main-common.c b/src/main-common.c index e5d6116..248d610 100644 --- a/src/main-common.c +++ b/src/main-common.c @@ -529,6 +529,49 @@ conf_rlimits(void) #endif +static void +usage(char *self) +{ + /* We can assume we have getopt_long(). */ + printf("Usage: %s [-c config] [-r log] [-d] [-f] [-v|-h]\n" + " -c, --config selects a different configuration file.\n" + " -d, --debug enables debug mode.\n" + " -f, --foreground run srvx in the foreground.\n" + " -h, --help prints this usage message.\n" + " -k, --check checks the configuration file's syntax.\n" + " -r, --replay replay a log file (for debugging).\n" + " -v, --version prints this program's version.\n" + , self); +} + +static void +version() +{ + printf(" --------------------------------------------------\n" + " - "PACKAGE_STRING" ("CODENAME"), Built: " __DATE__ ", " __TIME__".\n" + " - Copyright (C) 2000 - 2005, srvx Development Team\n" + " --------------------------------------------------\n"); +} + +static void +license() +{ + printf("\n" + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n"); +} + void main_shutdown(void) { struct uplinkNode *ul, *ul_next; diff --git a/src/main-win32.c b/src/main-win32.c index 657f991..95c63b6 100644 --- a/src/main-win32.c +++ b/src/main-win32.c @@ -17,10 +17,91 @@ #include +static int daemon; +static int debug; + +void parse_options(LPSTR args) +{ + const char *replay_file_name; + const char *arg; + char *argv[16]; + unsigned int jj; + unsigned int check_conf; + int argc; + int ii; + + argc = split_line(args, 0, ArrayLength(argv), argv); + if (argc < 1) + return; + + replay_file_name = NULL; + check_conf = 0; + daemon = 1; + for (ii = 0; ii < argc; ++ii) { + arg = argv[ii]; + if ((arg[0] == '/') || (arg[0] == '-' && arg[1] == '-')) { + arg += 1 + (arg[0] == '-' && arg[1] == '-'); + if (!strcmp(arg, "config")) { + } else if (!strcmp(arg, "debug")) { + debug = 1; + } else if (!strcmp(arg, "foreground")) { + daemon = 0; + } else if (!strcmp(arg, "check")) { + check_conf = 1; + } else if (!strcmp(arg, "replay")) { + replay_file_name = argv[++ii]; + } else if (!strcmp(arg, "version")) { + version(); + license(); + exit(0); + } else { + usage("srvx"); + exit(0); + } + } else if (arg[0] == '-') { + for (jj = 1; arg[jj] != '\0'; ++jj) { + switch (arg[jj]) { + case 'c': services_config = argv[++ii]; break; + case 'd': debug = 1; break; + case 'f': daemon = 0; break; + case 'k': check_conf = 1; break; + case 'r': replay_file_name = argv[++ii]; break; + break; + case 'v': + version(); + license(); + exit(0); + default: + usage("srvx"); + exit(0); + } + } + } + } + + if (check_conf) { + if (conf_read(services_config)) { + printf("%s appears to be a valid configuration file.\n", services_config); + } else { + printf("%s is an invalid configuration file.\n", services_config); + } + exit(0); + } + + if (replay_file_name) { + replay_file = fopen(optarg, "r"); + if (!replay_file) { + fprintf(stderr, "Could not open %s for reading: %s (%d)\n", + optarg, strerror(errno), errno); + exit(0); + } + } +} + int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { tools_init(); - /* TODO: parse lpCmdLine */ + parse_options(lpCmdLine); log_module(MAIN_LOG, LOG_INFO, "Initializing daemon..."); if (!conf_read(services_config)) { @@ -35,6 +116,8 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int log_init(); MAIN_LOG = log_register_type("srvx", "file:main.log"); + if (debug) + log_debug(); ioset_init(); init_structs(); init_parse(); diff --git a/src/main.c b/src/main.c index fc890c5..1cf2da7 100644 --- a/src/main.c +++ b/src/main.c @@ -95,43 +95,6 @@ void sigaction_rehash(int x) do_reopen = 1; } -void usage(char *self) { - /* We can assume we have getopt_long(). */ - printf("Usage: %s [-c config] [-r log] [-d] [-f] [-v|-h]\n" - "-c, --config selects a different configuration file.\n" - "-d, --debug enables debug mode.\n" - "-f, --foreground run srvx in the foreground.\n" - "-h, --help prints this usage message.\n" - "-k, --check checks the configuration file's syntax.\n" - "-r, --replay replay a log file (for debugging)\n" - "-v, --version prints this program's version.\n" - , self); -} - -void version() { - printf(" --------------------------------------------------\n" - " - "PACKAGE_STRING" ("CODENAME"), Built: " __DATE__ ", " __TIME__".\n" - " - Copyright (C) 2000 - 2005, srvx Development Team\n" - " --------------------------------------------------\n"); -} - -void license() { - printf("\n" - "This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with this program; if not, write to the Free Software\n" - "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n"); -} - #if WITH_MALLOC_BOEHM_GC void gc_warn_proc(char *msg, GC_word arg) @@ -182,12 +145,11 @@ int main(int argc, char *argv[]) {"check", 0, 0, 'k'}, {"replay", 1, 0, 'r'}, {"version", 0, 0, 'v'}, - {"verbose", 0, 0, 'V'}, {0, 0, 0, 0} }; - while ((c = getopt_long(argc, argv, "c:kr:dfvVh", options, NULL)) != -1) { - switch(c) { + while ((c = getopt_long(argc, argv, "c:dfhkr:v", options, NULL)) != -1) { + switch (c) { case 'c': services_config = optarg; break; diff --git a/src/mod-qserver.help b/src/mod-qserver.help new file mode 100644 index 0000000..e69de29 diff --git a/src/mod-snoop.help b/src/mod-snoop.help new file mode 100644 index 0000000..e69de29 -- 2.20.1