/* mpoold

   Modem Pool Daemon.   Listens on a specified port for incoming telnet
   connections, and when it gets one, connects it to a modem if one is
   available. */

/*
 * Copyright (c) 1995 RadioMail Corporation.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of RadioMail Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY RADIOMAIL CORPORATION AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * RADIOMAIL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software was written for RadioMail Corporation by Ted Lemon
 * under a contract with Vixie Enterprises, and is based on an earlier
 * design by Paul Vixie.
 */

#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1995 RadioMail Corporation.  All rights reserved.\n";
#endif /* not lint */

#include "cdefs.h"
#include "osdep.h"
#include "global.h"
#include "mcap.h"
#include <syslog.h>
#include <pwd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

static void usage PROTO ((void));

char **Argv;

int main (argc, argv, envp)
     int argc;
     char **argv, **envp;
{
  struct in_addr addr;
  int port = 0;
  char *capName = (char *)0;
  int pid;
  int i;
  int debugp = 0;

  Argv = argv;
  openlog ("mpoold", LOG_NDELAY | LOG_PID, LOG_DAEMON);
  setlogmask (LOG_UPTO (LOG_INFO));

  /* Become a daemon... */
  if ((pid = fork ()) < 0)
    error ("Can't fork daemon: %m");
  else if (pid)
    exit (0);
  /* Become session leader and get pid... */
  pid = setsid ();

  addr.s_addr = INADDR_ANY;

  for (i = 1; i < argc; i++)
    {
      if (!strcmp (argv [i], "-p"))
	{
	  if (++i == argc)
	    usage ();
	  port = htons (atoi (argv [i]));
	  syslog (LOG_DEBUG, "binding to user-specified port %d\n",
		  ntohs (port));
	}
      else if (!strcmp (argv [i], "-a"))
	{
	  if (++i == argc)
	    usage ();
	  if (!inet_aton (argv [i], &addr))
	    {
	      struct hostent *hent;
	      hent = gethostbyname (argv [i]);
	      if (!hent || hent -> h_addrtype != AF_INET)
		error ("Unable to translate %s into an internet address.",
		       argv [1]);
	      if (hent -> h_addr_list [0] == 0)
		error ("%s resolves to zero addresses.", argv [i]);
	      if (hent -> h_addr_list [1] != 0)
		error ("%s resolves to more than one address.", argv [i]);
	      memcpy (&addr, hent -> h_addr_list [0], hent -> h_length);
	    }
	}
      else if (!strcmp (argv [i], "-d"))
	{
	  debugp++;
	}
      else if (!capName)
	capName = argv [i];
      else
	usage ();
    }

  /* Default modemcap entry is ``modem-pool''. */
  if (!capName)
    capName = "modem-pool";

  /* Default to the telnet port. */
  if (!port)
    {
      struct servent *ent = getservbyname ("telnet", "tcp");
      if (!ent)
	port = htons (23);
      else
	port = ent -> s_port;
    }

  /* Get the modemcap entry specified on the command line. */
  init_mcap (capName);

  /* Wait for somebody to connect... */
  listener (port, &addr, !debugp);
}

/* Print an annoying but informative message... */

static void usage ()
{
  error ("Usage: mpoold [-p port] [-a ip-addr] <modemcap entry>");
}

/* Called when somebody connects to the listener... */

int modemConnect(lastmodem)
     int lastmodem;
{
  char *modem_name = (char *)0;
  int tty;
  char msgbuf [512];
  char psbuf [512];
  int i;

  /* Try the next modem... */
  lastmodem %= modemcap.device_count;
  i = lastmodem;
  do {
    if (ttnewlock (modemcap.device_vector [i], 0))
      {
	modem_name = modemcap.device_vector [i];
	break;
      }
    if (i++ == modemcap.device_count)
      i = 0;
  } while (i != lastmodem);

  /* If every modem is locked, flame and die... */
  if (!modem_name)
    {
      printf ("All ports busy.\n");
      error ("All ports busy.");
    }

  /* Change the ps banner... */
  sprintf (psbuf, "%s %s", Argv [0], modem_name);
  Argv [0] = modem_name;

  /* Open the terminal... */
  syslog (LOG_INFO, "Connecting to %s", modem_name);
  tty = ttsetup (modem_name);

  /* Initialize the modem, unless asked not to. */
  if (!modemcap.skip_init && !modemcap.defer_init)
    {
      if (!modemAttn (tty) &&
	  !modemAttn (tty))
	error ("Can't get modem %s attention on startup.");
      modemInit (tty);
    }

  /* Print a pretty banner... */
  sprintf (msgbuf, "Connected to modem pool line \"%s\"\r\n", modem_name);
  ttwriteslow (tty, "AT\r");

  /* Transfer bits back and forth... */
  telnet (msgbuf, 0, tty);

  /* If requested, reinitialize the modem *after* the user lets go of it. */
  if (modemcap.defer_init)
    {
      if (!modemAttn (tty) &&
	  !modemAttn (tty))
	error ("Can't get modem %s attention on cleanup.");
      modemInit (tty);
    }

  /* Release the modem... */
  syslog (LOG_INFO, "Disconnecting from %s", modem_name);
  ttunlock ();
  return 0;
}

/* Clean up loose ends before exiting... */

void cleanup ()
{
  ttunlock ();
}
