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

  POPular -- A POP3 server and proxy for large mail systems

  $Id: pcheck.c,v 1.12 2001/04/30 15:14:14 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"


/* program name for error messages */
static char *prgname;


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

  print_usage()

*****************************************************************************/
void
print_usage(void)
{
  printf("Usage: %s [OPTION] ... -l|--get-load\n", prgname);
  printf("   or: %s [OPTION] ... -m|--get-mailbox MAILBOX\n", prgname);
  printf("Send request for load check or mailbox check to pcheckd.\n");
  printf("Options:\n");
  printf("  -s, --server=SERVER     server host name or IP number (default: 127.0.0.1)\n");
  printf("  -p, --port=PORT         set server port (default: %d)\n", DEFAULT_PORT_CHECK);
  printf("  -t, --timeout=TIMEOUT   set timeout (default: %d seconds)\n", DEFAULT_TIMEOUT_CHECK);
  printf("      --help              print this help message\n");
  printf("      --version           print version information\n");
  printf("\n");
}


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

  main()

*****************************************************************************/
int
main(int argc, char *argv[])
{
  int s;
  struct sockaddr_in sa;
  char buf[MAXLEN_MAILCHECK];
  fd_set fdset;
  int c, len, ret;
  int timeout=DEFAULT_TIMEOUT_CHECK;
  int checkport=DEFAULT_PORT_CHECK;
  char action=' ';
  char *server=NULL, *mailbox=NULL;
  struct hostent *host;

  static struct option long_options[] = {
    { "help",          no_argument,       0, 0 },
    { "version",       no_argument,       0, 0 },
    { "server",        required_argument, 0, 's' },
    { "port",          required_argument, 0, 'p' },
    { "timeout",       required_argument, 0, 't' },
    { "get-load",      no_argument,       0, 'l' },
    { "get-mailbox",   required_argument, 0, 'm' },
    { NULL,            0,                 0, 0 }
  };

  prgname = argv[0];            /* program name for error messages */


  /***************************************************************************
    Parse command line options.
  ***************************************************************************/
  while (1) {
    int option_index = 0;
    c = getopt_long(argc, argv, "s:p:t:lm:", long_options, &option_index);
 
    if (c == -1) break;

    switch (c) {
      case 0:
        if (! strcmp(long_options[option_index].name, "version")) {
          printf("pcheck - POPular POP server suite %s\n", VERSION);
          exit(RCODE_OK);
        } else if (! strcmp(long_options[option_index].name, "help")) {
          print_usage();
          exit(RCODE_OK);
        } else {
          fprintf(stderr, "%s: unknown option: %s\n", prgname, long_options[option_index].name);
          exit(RCODE_INTERNAL);
        }
        break;
      case 's':		/* server */
        server = optarg;
        break;
      case 'p':		/* UDP port */
        checkport = get_port(optarg);
        if (checkport < 0) {
          fprintf(stderr, "%s: port must be valid UDP port.\n", prgname);
          exit(RCODE_CMDLINE);
        }
	break;
      case 't':		/* timeout */
        timeout = get_int(optarg, 1, 60, -1, -2, DEFAULT_TIMEOUT_CHECK);
        if (timeout < 0) {
          fprintf(stderr, "%s: timeout must be between 1 and 60 seconds.\n", prgname);
          exit(RCODE_CMDLINE);
        }
	break;
      case 'l':		/* load check */
        if (action != ' ') {
          fprintf(stderr, "%s: only one of -l or -m allowed.\nTry `%s --help' for more information.\n", prgname, prgname);
          exit(RCODE_CMDLINE);
        }
        action = 'L';
	break;
      case 'm':		/* mailbox check */
        if (action != ' ') {
          fprintf(stderr, "%s: only one of -l or -m allowed.\nTry `%s --help' for more information.\n", prgname, prgname);
          exit(RCODE_CMDLINE);
        }
        action = 'M';
	mailbox = optarg;
        break;
      default:
        fprintf(stderr, "Try `%s --help' for more information.\n", prgname);
        exit(RCODE_CMDLINE);
    }
  }

  if (action == ' ') {
    fprintf(stderr, "%s: need either -l or -m. Try `%s --help' for more information.\n", prgname, prgname);
    exit(RCODE_CMDLINE);
  }

  if (optind != argc) {
    fprintf(stderr, "%s: invalid extra arguments.\nTry `%s --help' for more information.\n", prgname, prgname);
    exit(RCODE_CMDLINE);
  }


  /***************************************************************************
    Find host address and "connect" to server.
  ***************************************************************************/
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(checkport);

  host = gethostbyname(server ? server : "127.0.0.1");
  if (host == NULL || (host->h_addr_list)[0] == NULL) {
    fprintf(stderr, "%s: unknown host or IP number: '%s'\n", prgname, server ? server : "127.0.0.1");
    exit(RCODE_ERR);
  } else {
    memcpy(&(sa.sin_addr.s_addr), host->h_addr_list[0], sizeof(sa.sin_addr.s_addr));
  }

  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    fprintf(stderr, "%s: socket open failed: %s\n", prgname, strerror(errno));
    exit(RCODE_ERR);
  }

  if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
    fprintf(stderr, "%s: connect failed: %s\n", prgname, strerror(errno));
    exit(RCODE_ERR);
  }


  /***************************************************************************
    Build request and send it to server.
  ***************************************************************************/
  buf[0] = '*';
  buf[1] = action;
  buf[2] = 0;
  if (action == 'L') {
    len = 2;
  } else if (action == 'M') {
    len = strlcat(buf, mailbox, sizeof(buf));
    if (len >= sizeof(buf)) {
      fprintf(stderr, "%s: mailbox name too long\n", prgname);
      exit(RCODE_CMDLINE);
    }
  } else {	/* should never be here... */
    fprintf(stderr, "%s: internal error\n", prgname);
    exit(RCODE_INTERNAL);
  }

  if (send(s, buf, len, 0) != len) {
    fprintf(stderr, "%s: sendto failed: %s\n", prgname, strerror(errno));
    exit(RCODE_ERR);
  }


  /***************************************************************************
    Wait for answer from server and print it.
  ***************************************************************************/
  memset(buf, 0, sizeof(buf));

  FD_ZERO(&fdset);
  FD_SET(s, &fdset);
  ret = rel_select(&fdset, timeout, 0);
  if (ret < 0) {
    fprintf(stderr, "%s: select failed: %s\n", prgname, strerror(errno));
    exit(RCODE_ERR);
  }

  if (FD_ISSET(s, &fdset)) {
    if ((recv(s, buf, sizeof(buf)-1, 0) < 0)) {
      fprintf(stderr, "%s: recv failed: %s\n", prgname, strerror(errno));
      exit(RCODE_ERR);
    } else {
      printf("%s", buf); 
      if (buf[0] == '-') exit(RCODE_ERR);
      else if (!strncmp("+OK 0", buf, 5)) exit(RCODE_OK);
      else if (!strncmp("+OK 3", buf, 5)) exit(RCODE_OK);
      else if (!strncmp("+OK 4", buf, 5)) exit(RCODE_OK);
      exit(RCODE_NO_MAILS);
    }
  }

  fprintf(stderr, "%s: timeout\n", prgname);
  exit(RCODE_ERR);
}


/** THE END *****************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1