/*****************************************************************************
POPular -- A POP3 server and proxy for large mail systems
$Id: pserv_ctrl.c,v 1.19 2001/05/24 18:28:12 sqrt Exp $
http://www.remote.org/jochen/mail/popular/
******************************************************************************
Copyright (C) 1999-2001 Jochen Topf <jochen@remote.org>
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*****************************************************************************/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "popular.h"
#include "pserv.h"
#include "ctrl.h"
extern struct pserv_capa capa;
extern struct pservconfig conf;
struct configdesc cd[] = {
/* tag rw type addr min max default value */
{ "backlog", 1, ctInt, &conf.backlog, 5, 1024, DEFAULT_LISTEN_BACKLOG, NULL },
/* RFC1939 says the 'inactivity autologout timer' MUST be >= 10 mins */
{ "idletimeout", 1, ctTime, &conf.idletimeout, 600, 60*60*24, DEFAULT_TIMEOUT_IDLE, NULL },
{ "logeachmsg", 1, ctBool, &conf.logeachmsg, 0, 1, 0, NULL },
{ "maxlocalload", 1, ctInt, &conf.maxlocalload, 0, 9999, 0, NULL },
{ "maxsession", 1, ctInt, &conf.maxsession, 2, MAX_SESSION, DEFAULT_MAX_SESSION, NULL },
{ "pid", 0, ctInt, &conf.pid, 0, 0, 0, NULL },
{ "servport", 1, ctInt, &conf.servport, 1024, 65535, DEFAULT_PORT_XPOP, NULL },
{ "sessionlimit", 0, ctInt, &conf.sessionlimit, 0, 0, MAX_SESSION, NULL },
{ "sessiontimeout", 1, ctTime, &conf.sessiontimeout, 0, 60*60*24, DEFAULT_TIMEOUT_SESSION, NULL },
{ "statusheader", 1, ctBool, &conf.statusheader, 0, 1, 0, NULL },
/* tag rw type addr strlength default value */
{ "capadir", 1, ctDir, conf.capadir, 0, sizeof(conf.capadir), 0, PSERV_CAPA_DIR },
{ "id", 0, ctId, conf.id, 0, sizeof(conf.id), 0, PSERV_PRG_NAME },
{ "localip", 1, ctStr, conf.localip, 0, sizeof(conf.localip), 0, "ANY" },
{ "logfile", 1, ctFile, conf.logfile, 0, sizeof(conf.logfile), 0, PSERV_LOG_FILE },
{ "popdir", 1, ctDir, conf.popdir, 0, sizeof(conf.popdir), 0, PSERV_POP_DIR },
{ "rundir" , 0, ctDir, conf.rundir, 0, sizeof(conf.rundir), 0, RUN_DIR },
{ "version", 0, ctStr, conf.version, 0, sizeof(conf.version), 0, VERSION },
{ NULL, 0, ctNone, NULL, 0, 0 }
};
struct ctrl_cmd_dispatch_table ccdt[] = {
{ "capa", ctrl_cmd_capa, 1, 2 },
{ "debug", ctrl_cmd_debug, 0, 10 },
{ "server", ctrl_cmd_server, 1, 1 },
{ "set", ctrl_cmd_set, 2, 2 },
{ "show", ctrl_cmd_show, 0, 1 },
{ "shutdown", ctrl_cmd_shutdown, 1, 1 },
{ NULL, NULL, 0, 0 }
};
/*****************************************************************************
capa_name()
*****************************************************************************/
char *
capa_name(struct virt_serv *vs)
{
switch (vs->capa_type) {
case capa_error:
return "ERROR";
case capa_none:
return "NONE";
case capa_default:
return "DEFAULT";
case capa_user:
return vs->capa_ptr->name;
default:
return "ERROR";
}
}
/*****************************************************************************
ctrl_cmd_capa()
*****************************************************************************/
void
ctrl_cmd_capa(char *argv[], int argc, char *answer)
{
if (! strcasecmp(argv[1], "show")) {
if (argc != 2) ANSWER0("20 too many arguments");
switch (capa.capa_type) {
case capa_error: ANSWER0("00 capa set ERROR");
case capa_none: ANSWER0("00 capa set NONE");
case capa_default: ANSWER0("00 capa set DEFAULT");
case capa_user: {
char *x;
snprintf(answer, MAXBUF, "00 capa set %s: %s", capa.name, capa.text);
for (x=answer; *x; x++) {
if (*x == '\r') *x=',';
if (*x == '\n') *x=' ';
}
answer[strlen(answer)-2] = '\0';
return;
}
default: ANSWER0("99 illegal capa set");
}
} else if (! strcasecmp(argv[1], "set")) {
struct pserv_capa c;
if (argc != 3) ANSWER0("20 second argument (capa id) is missing");
if (!valid_id(argv[2])) ANSWER0("13 invalid chars in id (must be [a-zA-Z0-9._-]*)");
if (!strcasecmp(argv[2], "ERROR")) {
capa.capa_type = capa_error;
/* XLOG-DOC:ADM:0150:config_capa
* Capability was configured */
xlog_printf(xlog_adm, 0x0150, "config_capa capa=ERROR");
ANSWER0("00 capa set ERROR");
} else if (!strcasecmp(argv[2], "NONE")) {
capa.capa_type = capa_none;
/* XLOG-DOC:ADM:0151:config_capa
* Capability was configured */
xlog_printf(xlog_adm, 0x0151, "config_capa capa=NONE");
ANSWER0("00 capa set NONE");
} else if (!strcasecmp(argv[2], "DEFAULT")) {
capa.capa_type = capa_default;
/* XLOG-DOC:ADM:0152:config_capa
* Capability was configured */
xlog_printf(xlog_adm, 0x0152, "config_capa capa=DEFAULT");
ANSWER0("00 capa set DEFAULT");
} else {
FILE *f;
char buf[MAXBUF];
int offset = 0;
c.capa_type = capa_user;
strlcpy(c.name, argv[2], MAXLEN_ID);
snprintf(buf, sizeof(buf), "%s/%s", conf.capadir, argv[2]);
f = fopen(buf, "r");
if (! f) ANSWER1("33 error opening '%s'", buf);
/* read in capa file converting LF to CRLF as we go */
while (fgets(c.text + offset, sizeof(c.text) - offset - 2, f)) {
int len = strlen(c.text + offset);
c.text[offset+len-1] = '\r';
c.text[offset+len] = '\n';
c.text[offset+len+1] = '\0';
offset += len+1;
if (offset >= sizeof(c.text) - 2) {
ANSWER1("13 capa '%s' too long to be loaded", argv[2]);
}
}
fclose(f);
}
capa = c;
/* XLOG-DOC:ADM:0153:config_capa
* Capability was configured */
xlog_printf(xlog_adm, 0x0153, "config_capa capa=%s", argv[2]);
ANSWER1("00 capa '%s' loaded", argv[2]);
} else {
ANSWER1("22 unknown subcomand: '%s'", argv[1]);
}
}
/*****************************************************************************
ctrl_cmd_server()
*****************************************************************************/
void
ctrl_cmd_server(char *argv[], int argc, char *answer)
{
if (! strcasecmp(argv[1], "online")) {
switch (go_online ()) {
case 0:
ANSWER0("31 can't go online");
case 1:
ANSWER0("00 server is online now");
default:
ANSWER0("13 we are already online");
}
} else if (! strcasecmp(argv[1], "offline")) {
switch (go_offline ()) {
case 0:
ANSWER0("99 can't go offline");
case 1:
ANSWER0("00 server is offline now");
default:
ANSWER0("13 we are already offline");
}
} else if (! strcasecmp(argv[1], "status")) {
if (is_online()) {
ANSWER0("00 server is online");
} else {
ANSWER0("00 server is offline");
}
} else {
ANSWER0("22 subcommand must be 'online', 'offline' or 'status'");
}
}
/** THE END *****************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1