/*
 *  $Id: main.c,v 1.5 1994/05/25 08:20:31 bert Exp bert $
 *
 *  initialization and main accept() loop
 *  (part of diswww, a Discuss->WWW gateway)
 */

#ifndef lint
static char rcsid_main[] = "$Id: main.c,v 1.5 1994/05/25 08:20:31 bert Exp bert $";
#endif

#include "proto.h"  /* the copyright notice is included in this file, too. */
#include "extern.h"
#include "status.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <malloc.h>

char *progname;                 /* what is our name? */
struct clt_sock conn;           /* connection information */
struct access  *file_list;      /* files exported by the server */

int main(int argc, char **argv, char **envp)
{
  int l_sock;

#ifdef PROGNAME
  progname = PROGNAME;
#else
  /* get program name from argv[0] */

  if ((progname = strrchr(argv[0],'/')))
    progname++;
  else
    progname = argv[0];
#endif

#ifdef BACKGROUND
  /* run in background */

  background();
#else
  chdir(SRV_ROOT_DIR);
  umask(SRV_UMASK);
#endif

  /* deal with titles */

  envsetup(argc, argv, envp);
  setproctitle("%s (main)", progname);

  /* start syslogging */

  openlog(progname, SRV_SYSLOG_OPT, SRV_SYSLOG_LVL);

  /* install signal handlers */

  deal_with_signals();

  /* read access list */

  file_list = access_list(SRV_ACCESS_FILE);

  /* open server socket */

  if ((l_sock = open_socket(SRV_PORT)) < 0) {
    SYSLOG_ERROR("can't open socket!");
    exit(1);
  }

  while (1) {
    struct sockaddr_in addr;
    int size = sizeof(addr);
    pid_t pid;

    /* accept a connection and deal with the client */

    if ((conn.fd = accept(l_sock, (struct sockaddr*)&addr, &size)) < 0) {
      if (errno != EINTR)
	SYSLOG_EWARN("accept() call failed");
    } else {
      switch (pid=fork()) {
      case 0:
	conn.method = conn.path = conn.ver = conn.agent = conn.reply = NULL;
	conn.begin = conn.size = 0;
	conn.host = find_peer_name(&addr);
	setproctitle("%s: connection from %s", progname, conn.host);

        if (! talk_to_client(&conn)) {
	  char *host, *mtg;
	  int trn, lfrom, lto;

#ifdef LOG_EACH_REQUEST
	  if (conn.ver)
	    SYSLOG(LOG_INFO, "%s   %s %s %s", 
		   conn.host, conn.method, conn.path, conn.ver);
	  else
	    SYSLOG(LOG_INFO, "%s   %s %s",
		   conn.host, conn.method, conn.path);
#endif /* LOG_EACH_REQUEST */

	  if (! strcmp(conn.path, "/")) {
	    if (conn.ver)
	      send_header(&conn, S_ok, T_html);
	    fd_spew_file(conn.fd, SRV_INDEX);
	  } else {
	    struct access *find;
	    char *pathname;

	    for (pathname = conn.path; *pathname == '/'; pathname++);

	    for (find=file_list;
		 find && strcmp(pathname, find->filename); 
		 find = find->next);
	    if (find) {
	      if (conn.ver)
		send_header(&conn, S_ok, find->type);
	      fd_spew_file(conn.fd, find->filename);
	    } else {
	      parse_path(conn.path, &host, &mtg, &trn, &lfrom, &lto);
	      if (trn == -1)
		dslist(host, mtg, lfrom, lto, 20, conn.fd);
	      else if (trn)
		dsread(host, mtg, trn, conn.fd);
	      else
		send_error_notice(&conn, S_not_found, E_not_found_fmt,
				  conn.path);
	      free(mtg);
	      free(host);
	    }
	  }
	}

        close(conn.fd);
        free(conn.host);   /* deallocate the strings */
        free(conn.method);
        free(conn.path);
        free(conn.ver);
        free(conn.agent);
        free(conn.reply);
        exit(0);
      case -1:
        SYSLOG_ERROR("oops, fork failed...");
        exit(1);
      default:
        close(conn.fd);
      }
    }
  }
}
