/*****************************************************************************

  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