/*
 *  Copyright (C) 1994 by Albert Dvornik.
 *
 *  This code may be distributed, modified and used to your heart's content
 *  as long as the code (and portions thereof) includes this notice intact
 *  in its entirety, you don't try to make any money off of it, and all
 *  corrections and improvements to the code are sent back to the author.
 *  The code is provided as is, without any warranty, although the author
 *  hopes you find it useful.
 *
 *  E-mail address: bert@mit.edu
 *  Paper mail:
 *    Albert Dvornik
 *    MIT Student Information Processing Board
 *    room W20-557; 84 Massachusetts Avenue; Cambridge, MA 02215; U.S.A.
 */

#include <syslog.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>

/* configuration parameters */
#ifndef SRV_ROOT_DIR                           /* directory to run from */
#define SRV_ROOT_DIR     "/var/local/diswww/files"
#endif
#ifndef SRV_PORT                               /* default port */
#define SRV_PORT         8008
#endif
#ifndef SRV_SELF                               /* server root */
#define SRV_SELF         "http://www.mit.edu:8008"
#endif
#ifndef SRV_WEBMASTER
#define SRV_WEBMASTER    "webmaster@mit.edu"   /* server webmasters */
#endif
#ifndef SRV_INDEX
#define SRV_INDEX        "index.html"          /* "root" document */
#endif
#ifndef SRV_ACCESS_FILE
#define SRV_ACCESS_FILE  ".access"             /* access permission list */
#endif
#ifndef SRV_SYSLOG_LVL
#define SRV_SYSLOG_LVL   LOG_LOCAL5            /* facility (for syslog) */
#endif
#define SRV_SYSLOG_OPT   LOG_PID | LOG_ODELAY  /* syslog options */
#define SRV_UMASK        0                     /* umask to run with */
#define SRV_SOCK_BACKLOG 1                     /* length of socket queue */
#define SRV_BUFSIZE      1024                  /* input buffer size */
#define SRV_REPLYSIZE    2048                  /* output buffer size */

/* constants */
#define CR_CHAR (char)015  /* octal */
#define LF_CHAR (char)012  /* octal */

/* macros for syslogging */
#define SYSLOG_ERROR(msg) syslog(LOG_ERR, "%s (%m)", msg)
#define SYSLOG_EWARN(msg) syslog(LOG_WARNING, "%s (%m)", msg)
#define SYSLOG_WARNING(msg) syslog(LOG_WARNING, msg)
#define SYSLOG_NOTICE(msg) syslog(LOG_NOTICE, msg)
#define SYSLOG_DEBUG(msg) syslog(LOG_DEBUG, msg)
#define SYSLOG syslog

/* deal if malloc() fails */
#define CHECK_MALLOC(var) if (!var) {SYSLOG_ERROR("out of core!"); exit(1); }

/*** types, global variables and prototypes ***/

struct clt_sock {       /* connection information */
  int fd;                     /* socket to client */
  char *host;                 /* client hostname */
  char *method, *path, *ver;  /* request */
  char *agent;                /* value of "User-Agent:" field */
  char buf[SRV_BUFSIZE];      /* buffer for read_line */
  int begin, size;            /* buffer position and end+1 */
  char *reply;                /* reply information */
};

struct access {         /* files exported by the server */
  char *filename, *type;      /* filename and MIME type */
  struct access *next;        /* next record */
};

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

extern int    fd_write(int, char*);
extern int    fd_print(int, const char*, ...);
extern void   fd_spew_file(int, char*);

extern int    write_quoted(int, char*, int);
extern int    fd_write_quoted(int, char*);
extern int    fd_print_quoted(int, const char*, ...);

extern void   send_error_notice(struct clt_sock*, char*, char*, ...);
extern void   send_moved_notice(struct clt_sock*, char*, char*);
extern void   send_header(struct clt_sock*, char*, char*);
extern void   send_header2(struct clt_sock*, char*, char*, ...);

extern void   setproctitle(char*, ...);
extern void   envsetup(int, char**, char**);

extern int    talk_to_client(struct clt_sock*);
extern void   deal_with_signals(void);
extern void   background(void);
extern void   foreground(void);
extern int    open_socket(int);
extern int    parse_path(char*, char**, char**, int*, int*, int*);
extern char  *sstrdup(char*);
extern char  *find_peer_name(struct sockaddr_in*);

extern struct access *access_list(char* file);

extern void   dsread(char*, char*, int, int);
extern void   dslist(char*, char*, int, int, int, int);
