/*
 * access.c: Zugriff fuer tty* und Sites.
 *
 * Feb. / Maerz 1995, Jan Wedekind
  
  Mit Hilfe einer Konfigurationsdatei (/etc/lines.conf)
  in der Gueltigkeitsbereiche und Zugriffszeiten festgelegt
  werden und einer Accounting Datei (obsolete: /etc/access.time)
  in der die gueltigen Login-Zeiten fuer die einzelnen
  hosts aufgelistet sind, wird festgestellt,
  ob und wie lange ein host momentan zugriffsberechtigt ist.
  
  In acess.conf sind Gueltigkeitsbereiche durch Zeilen mit den
  folgenden Eintraegen definiert
  
  	Protokolle, ttys, Wochentag, Uhrzeit, Zugriff, Hosts
  
  jeweils durch WS (white space) getrennt. Alle Eintraege erkennen
  Bereiche durch ein '-' zwischen den Angaben, und Aufzaehlungen
  durch ein ','. Ein '*' ist ein Jokerzeichen und bedeutet,
  dass die Definition immer gueltig ist.

   Protokolle:	I(p), U(ucp), S(lip), C(slip), P(pp)
  		Vorgestelltes '-' verbietet den Zugriff.
  		U,-I erlaubt Uucp und verbietet gleichzeitig alle Ip-Protok.
   ttys:	z.B. 0-6,8 um den Modems auf tty00 - tty06 und tty08
  		Zugriff zu erlauben / verbieten (s.u.)
   Wochentag:	0 fuer Sonntag bis 6 fuer Samstag
   Uhrzeit:	erkannt werden sowohl Dezimal (18.5-7.3), als auch
  		Formate der Form (18:30-20).
   Zugriff:	erlaubte login Zeit (Minuten), maximale Login Zeit (Std.)
   Hosts:	host access liste. vorangestelltes '-' deaktiviert
   		den Bereich fuer einen (bzw. alle bei '*') host(s),
		ein '+' aktiviert den Bereich.
 *
 */

#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <utmp.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

#include "access.h"

static int debug = 0;
int ttynr = UNKNOWN_TTY;	/* global definition, calculate only 1x */

int expresslines = 0;		/* # of express lines */
int checklines = 0;		/* # of normal lines (incl. express) */

#define EXPRESS_CHKTIME	60	/* Check again after 1 Minute */

char* access_conf = ACC_CONF;
char* access_daily = ACC_DAILY;
char* access_month = ACC_MONTH;

/* Linux definiert UT_HOSTSIZE nicht */
#ifndef UT_HOSTSIZE
#define UT_HOSTSIZE 16
#endif

#ifdef STDERR
#define syslog fprintf
#undef LOG_ERR
#define LOG_ERR stderr
#endif

typedef struct _ttyline {
    char* tty;
    int	  nr;
    char* modem;
    struct _ttyline* next;
} ttyline;

typedef struct _confline {	/* access.conf Zeile */
    char* protokoll;	/* Protokolle */
    char* ttys;		/* Nr. der ttys */
    char* dayofweek;	/* Wochentage */
    char* timeofday;	/* Uhrzeit */
    char* access;
    char* hosts;
    struct _confline* next;
} confline;

confline *config = NULL, *conf_last = NULL;
ttyline  *ttylist= NULL, *tty_last = NULL;

typedef enum { TTYS, PROTO, DOW, TOD, ACC, HOSTS } COLUMN;
typedef enum { OK, EOL, EDIGIT, ETERM,
	       EERANGE, EIRANGE, ECHAR, EPROTO } ERRCODE;
typedef enum { MODE_FIRST, MODE_LIST, MODE_RANGE } MODE;

char* colstr[] = { "ttys", "Protoc.", "Weekday", "Time", "Access", "Hosts" };
char* errstr[] = { "no error",
		   "unexpected end of line",
		   "Digit / Number expected",
		   "List separator (',') expected",
		   "Range seperator ('-') expected",
		   "Invalid range",
		   "Invalid character", "Unknown protokoll" };

#define EAT_WHITE(s) while (isspace(*s)) s++
#define isterm(s)  (s == ',')
#define isrange(s) (s == '-')

static ERRCODE eat_number(char** s, int min, int max)
{
    int num;
    char* st = *s;
    if (**s == '*') { (*s)++; return OK; }
    if (!isdigit(**s)) return EDIGIT;
    while (isdigit(**s)) (*s)++;
    sscanf(st, "%d", &num);
    if (min < max && (num < min || num > max)) return EIRANGE;
    return OK;
}

static ERRCODE eat_proto(char** s)
{
    ERRCODE err = EPROTO;
    int ok = 1;
    while (*s && **s && ok)
    {
	switch (**s)
	{
	  case 'I': case 'U':
	  case 'S': case 'C': case 'P':
	    (*s)++; err = OK;
	    break;
	  default:
	    ok = 0;
	}
    }
    return err;
}

static ERRCODE eat_host (char** s)
{
    ERRCODE err = EPROTO;
    int ok = 1;
    while (*s && **s && ok)
    {
	if (isalnum(**s) || **s == '-' || **s == '_')
	{
	    err = OK; (*s)++;
	} else if (isterm(**s) || isspace(**s))
	  ok = 0;
    }
    return err;
}

static char* makestr(char* s, int n)
{
    char* copy = (char*) malloc(n+1);
    strncpy(copy, s, n);
    copy[n] = 0;
    return copy;
}

int access_init()
{
    struct stat buf;

    if (config) return;
    
    if (!access_conf) access_conf = ACC_CONF;
    if (strcmp(access_conf, ACC_CONF) != 0)
      printf ("reading Configuration from: %s\n", access_conf);

    if (   !stat(access_conf, &buf)
	&& !access(access_conf, R_OK))
    {
	FILE*	fp;
	char	line[200];
	char	*lp, *sp;
	int	lnum = 0;
	COLUMN	col;
	confline* cfline = NULL;

	fp = fopen(access_conf, "r");
	while (!feof(fp))
	{
	    ERRCODE	err = OK;
	    MODE        mode = MODE_FIRST;
	    COLUMN	col = TTYS;
	    
	    if (!cfline) /* Config Line Record anlegen */
	    {
		cfline = (confline*) malloc(sizeof(confline));
		cfline->next = NULL;
	    }
	    sp = lp = fgets(line, sizeof(line), fp);
	    lnum++;

	    if (strstr(line, "tty") == line) /* tty config line */
	    {
		char tty[80];
		int  nr;
		sscanf(line, "%s %d", tty, &nr);
		if (nr > 0)
		{
		    ttyline* line = (ttyline*) malloc(sizeof(ttyline));
#ifdef OUTPUT		    
		    /* printf("tty: %s %d\n", tty, nr); */
#endif
		    switch (nr)
		    {
		      case 1: expresslines++;
		      case 2: checklines++;
			break;
		    }
		    line->tty = strdup(tty);
		    line->nr  = nr;
		    line->next = NULL;
		    if (ttylist)
		      tty_last->next = line;
		    else
		      ttylist = line;
		    tty_last = line;
		}
	    } else
	    while (err == OK && lp && *lp && *lp != '#')
	    {
		switch(col)
		{
		  case TTYS:
		  case ACC:
		    err = eat_number(&lp, -1, -1);
		    break;
		    
		  case DOW:
		    err = eat_number(&lp, 0, 6);
		    break;
		    
		  case TOD:
		    if (   (err = eat_number(&lp, 0, 24)) == OK
			&& (   ((*lp != ':') && (*lp != '.'))
			    || (   *lp++==':'
				&& (err = eat_number(&lp,0,59)) == OK)
			    || (   *lp++=='.'
				&& (err = eat_number(&lp,0,99)) == OK)));
		    break;
		    
		  case PROTO:
		    if (*lp == '+' || *lp == '-') lp++;
		    if (*lp == '*') lp++; else err = eat_proto(&lp);
		    break;
		    
		  case HOSTS:
		    if (*lp == '+' || *lp == '-') lp++;
		    if (*lp == '*') lp++; else err = eat_host(&lp);
		    break;
		}
		
		if (err == OK)
		{
		    if (isspace(*lp))
		    {
			char* s = makestr(sp, lp-sp);
			switch (col)
			{
			  case TTYS: cfline->ttys = s; break;	    
			  case DOW: cfline->dayofweek = s; break;
			  case TOD: cfline->timeofday = s; break;
			  case PROTO: cfline->protokoll = s; break;
			  case ACC: cfline->access = s; break;
			  case HOSTS: cfline->hosts = s; break;
			}			    
			if (col < HOSTS) col++; else lp++;
			mode = MODE_FIRST;
			EAT_WHITE(lp);
			sp = lp;		
		    } else if (isrange(*lp))
		    {
			lp++;
			/* Range '-', nur erlaubt, wenn nicht innerhalb
			   eines Bereichs. */
			if (mode == MODE_FIRST)
			  mode = MODE_RANGE;
			else err = EIRANGE;
		    } else if (isterm(*lp))
		    {
			lp++;
			/* Fuer Time of D. muss eine Range angegeben werden. */
			if (mode != MODE_FIRST || col != TOD)
			  mode = MODE_LIST;
			else err = EERANGE;
		    } else 
		      err = ECHAR;
		}
	    } /* column scan */
	    if (lp != line) /* No comment line */
	    {
		if (col != HOSTS && err == OK) err = EOL;

		if (lp && err == OK)
		{
		    if (config)
		      conf_last->next = cfline;
		    else
		      config = cfline;
		    conf_last = cfline;
		    cfline = NULL;
		} else if (lp)
		  syslog(LOG_ERR, "%s(line %d, section %s): %s.\n",
			 access_conf, lnum, colstr[col], errstr[err]);
	    }
	} /* line read */
	fclose(fp);
	return (config == NULL);
    }
    syslog(LOG_ERR, "access config %s not found.\n", access_conf);
    return -1;
}

print_config()
{
    confline* line = config;
    int i;
    for (i=0; i<6; i++) printf("%s\t", colstr[i]);
    printf("\n");
    while (line)
    {
	printf("%s\t%s\t%s\t%s\t%s\t%s\n",
	       line->ttys, line->protokoll,
	       line->dayofweek, line->timeofday,
	       line->access, line->hosts);
	line = line->next;
    }    
    printf("\n");
}

int get_time (char* time_file, char* host)
{
    struct stat buf;
    if (   !stat(time_file, &buf)
	&& !access(time_file, R_OK))
    {
	FILE*	fp;
	int ok = 0, lno, lhour, lmin;
	char lhost[80];

	fp = fopen(time_file, "r");

	while (!ok && !feof(fp))
	{
	    fscanf(fp, "%d %d:%d %s", &lno, &lhour, &lmin, lhost);
	    ok = (strcmp(lhost, host) == 0);
	}
        fclose(fp);
	if (ok) return lhour*60+lmin;
    }
    return 0;
}

void eat_int (char**s, int* num)
{
    sscanf(*s, "%d", num);
    while (isdigit(**s)) (*s)++;
}

#define NORMAL	0
#define TIME	1

void eat_num (char**s, int* num, int hour)
{
    eat_int(s, num); if (hour) *num *= 60;
    if (**s == '.' || **s == ':')
    {
	char* d = *s;
	int rest;
	(*s)++;
	eat_int(s, &rest);
	if (*d == ':')
	  *num += rest;
	else {
	    if (rest < 10.0) rest *= 10;
	    *num += (int) ((double)rest*3.0/5.0);
	}
    }      
}
void eat_range (char** s, int* min, int* max, int hour)
{
    eat_num(s, min, hour);
    if (**s == '-')
    {
	(*s)++;
	eat_num(s, max, hour);
    } else
      *max = *min;	 
}
int in_range (int val, char* s, int hour)
{
    int min, max;
    int ok = 0;
    while (!ok && s && *s && !isspace(*s))
    {
	if (*s == '*') return 1;
	eat_range(&s, &min, &max, hour);
	ok = (   min <= val
	      && (   ( hour && val < max)
		  || (!hour && val <= max)));
	if (*s) s++;
    }
    return ok;
}

int in_hosts (char* host, char* hosts)
{
    int found = 0;
    int sign = 1;
    while (*hosts)
    {
	switch (*hosts)
	{
	  case ',': break;
	  case '+': sign = 1; break;
	  case '-': sign = 0; break;
	  case '*': found = sign; break;
	  default:
	    if (   strncmp(host, hosts, strlen(host)) == 0
		&& (   hosts[strlen(host)] == 0
		    || hosts[strlen(host)] == ',')) found = sign;
	    while (*hosts && *hosts != ',') hosts++;
	}
	if (*hosts) hosts++;
    }
    return found;
}

int calc_access (int dow, int tod, int tty, char proto, char* host, int recur)
{
    int min, max;
    int access = 0;
    int acctime = 0;
    int accdlimit = 0;
    int acclimit = 0;
    confline* line = config;

    switch(proto)
    {
      case 'S': case 'C': case 'P': proto = 'I';
    }
	
    while (line)
    {
	int acc = 0, time, limit, dlimit;
	int sign = 1;
	char *s;
	
	/* Protokoll erlaubt / verboten */
	s = line->protokoll;
	while (*s)
	{
	    switch (*s)
	    {
	      case '-': sign = -1; break;
	      case '+': sign = +1; break;
	      case '*': acc = sign; break;
	      default:
		if (*s == proto) acc = sign;
	    }
	    s++;
	}     
	if (   acc
	    && (tty == 99 || in_range(tty, line->ttys, NORMAL))
	    && in_hosts(host, line->hosts))
	{	    
	    s = line->timeofday;
	    eat_range (&s, &min, &max, TIME);
	    
	    if (   (   *(line->timeofday) == '*'
		    && in_range(dow, line->dayofweek, NORMAL))
		|| (   min < max
		    && in_range(dow, line->dayofweek, NORMAL)
		    && in_range(tod, line->timeofday, TIME))
		|| (   min > max
		    && (   (   min <= tod
			    && in_range(dow, line->dayofweek, NORMAL))
			|| (   tod < max
			    && in_range((dow+6)%7, line->dayofweek, NORMAL)))))
	    {
		s = line->access;
		time = limit = 9999;
		dlimit = 0;
		if (*s != '*') eat_int(&s, &time); else s++;
		if (isterm(*s))
		{
		    s++;
		    if (*s != '*') eat_int(&s, &limit);
		}
		/* Wenn max. Loginzeit angegeben, muss
		   geprueft werden, ob host schon mal eingeloggt
		   war; wenn ja, wird loginzeit berechnet und dann
		   verglichen. */
		if (   recur == 0
		    && time < 9999
		    && *(line->timeofday) != '*'
		    && min > max && min <= ACC_LHOUR*60)		  
		{		    
		    struct stat buf;
		    char hostfile[100];
		    int time2 = 0;
		    dlimit = 1;
		    if (time < 60) /* Express Line */
		    {
			if (MAX_EXPRESS - time2 < time)
			  time = MAX_EXPRESS - time2;
		    } else
		      time = time-time2;
		    if (time < 0) time = 0;
		}
		
		access = acc;
		acctime = time;
		accdlimit = dlimit;
		acclimit = limit;
		if (tod < ACC_LHOUR*60)
		{
		    int time2 = calc_access(dow, ACC_LHOUR*60, tty,
					    proto, host, recur+1);
		    if (ACC_LHOUR*60 - tod + time2 < acctime)
		      acctime = ACC_LHOUR*60 - tod + time2;
		}
	    }
	}
	line = line->next;	
    }
    switch (access)
    {
      case +1:
#if 0
	if (accdlimit && acctime >= MIN_ACCESS)
	{
	    char hostfile[100];
	    int fd;
	    sprintf(hostfile, "%s/hosts/%s", ACC_PATH, host);
	    fd = creat(hostfile, 0660);
	    if (fd>=0) close(fd);
	}
#endif
	if (acclimit < 9999)
	{
	    int time = get_time(access_month, host);
	    if (time >= 60*acclimit)
	      return 0;
	    else if (60*acclimit - time > acctime)
	      return acctime;
	    else
	      return 60*acclimit - time;		
	}
	return (acctime>=MIN_ACCESS) ? acctime : 0;
	break;
      case -1:
	return 0; break;
    }
    return 9999;	
}

/* return the Nr. of the login port, or -1 if Pseudo tty */
int get_ttydef (char* tty)
{
    char *ttyn;
    int nr;
    ttyline* line;

    if (tty == NULL)
    {
	/* looking up for login tty */
	ttyn = ttyname(STDIN_FILENO);
	if (tty = rindex(ttyn, '/'))
	  tty++;
	else
	  tty = ttyn;
#ifdef OUTPUT
	printf("assuming tty: %s\n", tty);
#endif
    }

    line = ttylist;
    while (line && strcmp(line->tty, tty) != 0) line = line->next;
    if (!line)
    {
	if (   strlen(tty+3) == 2  /* real Port tty */
	    && isdigit(tty[3])
	    && isdigit(tty[4]))
	  nr = atoi(tty+3);
	else if (tty[3] == 'p')
	  nr = PSEUDO_TTY;
	else
	  nr = UNKNOWN_TTY;
    } else
      nr = line->nr;

    if (debug)
      printf("get_ttydef(%s) = %d\n", tty, nr);
    return nr;
}

int check_express()
{
    static int busy = 0;		/* all lines busy at last call */
    int active = 0;			/* # lines busy at this call */
    FILE* ut;
    struct utmp utmp;

    if (ttynr != EXPRESS_LINE)	/* no Express Line */      
      return 0; 	/* no further access */
	
    if (ut = fopen(_PATH_UTMP, "r"))
    {
	while (fread(&utmp, sizeof(utmp), 1, ut))
	{
	    int nr;
	    
	    /* Nur entries beruecksichtigen, die aktiv sind */
	    if (utmp.ut_name[0] == '\0')
	      continue;

	    nr = get_ttydef(utmp.ut_line);
	    if (nr == 1 || nr == 2)
	    {
		active++;
#ifdef OUTPUT
		printf("line active: %s with %-8s (%s)\n",
		       utmp.ut_line, utmp.ut_name, utmp.ut_host);
#endif
	    }
	}
	fclose (ut);
    } else
      active = 0;		/* no utmp file: simulate NOT busy */

    if (busy && active == checklines) /* busy last & this time: exit() */
      return 0;
    
    busy = (active == checklines);
    return EXPRESS_CHKTIME;
}

void (*hup_function)() = NULL;

static void watch_handler(int nr)
{
    int time = check_express(); /* check for further access (in seconds) */
#ifdef OUTPUT
    printf("watch_handler: %d seconds more\n", time);
#endif
    
    if (time > 0)
    {
	struct itimerval ti;
	ti.it_interval.tv_sec = ti.it_value.tv_sec = time;
	ti.it_interval.tv_usec = ti.it_value.tv_usec = 0;
	setitimer(ITIMER_REAL, &ti, NULL);
	signal(SIGALRM, watch_handler);
	return;
    }
    if (hup_function) hup_function(SIGHUP);
    exit(1);
}

void watch_access(int ttynr, int time, void (*exit_fun)())
{
    access_init();
    hup_function = exit_fun;
    time = time*60;
    if (ttynr == EXPRESS_LINE) time -= EXPRESS_CHKTIME;
    
    if (time)
    {
	struct itimerval ti;
	ti.it_interval.tv_sec = ti.it_value.tv_sec = time;
	ti.it_interval.tv_usec = ti.it_value.tv_usec = 0;
	setitimer(ITIMER_REAL, &ti, NULL);
	signal(SIGALRM, watch_handler);
    } else
      watch_handler(1);
}
     
void wu_tmp (char* path, char* tty, char prefix, char* host)
{
    int fd;
    struct stat st;
    struct utmp wtmp;
    unsigned pos;	
    
    fd = open(path, O_RDWR);
    if (fd > 0)
    {
	/* look up for [uw]tmp entry */
	fstat(fd, &st);
	pos = st.st_size;
	do {
	    pos -= sizeof(wtmp);
	    lseek(fd, pos, SEEK_SET);
	    read (fd, &wtmp, sizeof(wtmp));
	    /* printf ("%s %s\n", wtmp.ut_name, wtmp.ut_line); */
	} while (pos >= sizeof(wtmp) && strcmp(wtmp.ut_line, tty) != 0);

	if (strcmp(wtmp.ut_line, tty) == 0)
	{
	    wtmp.ut_host[0] = prefix;
	    strncpy(wtmp.ut_host+1, host, UT_HOSTSIZE-1);
	    lseek(fd, pos, SEEK_SET);
	    write(fd, &wtmp, sizeof(wtmp));
	}
	close(fd);	
    } else
      syslog(LOG_ERR, "Cannot open %s: %m", path);
}

/* Erzeuge wtmp / utmp entry */
void set_wtmp(char prefix, char* host)
{
    char *ttyn, *tty;
    
    /* looking up for login tty */
    ttyn = ttyname(STDIN_FILENO);
    if (tty = rindex(ttyn, '/'))
      ++tty;
    else
      tty = ttyn;

    wu_tmp (_PATH_WTMP, tty, prefix, host);
    wu_tmp (_PATH_UTMP, tty, prefix, host);
}

#ifdef CHECK_ACCESS
int main (int argc, char** argv)
#else
int get_access (char proto, char* host, void (*exit_fun)())
#endif
{
    time_t timeval = time(NULL);
    struct tm* time;
    int tday, wday;
    int acc = 9999;
    char accsign = '-';

#ifdef CHECK_ACCESS
    char proto;
    char* host;

    if (argc < 3) return 255; /* No Limit for UUCP / uucico */
    proto = *(argv[1]);
    host = argv[2];
#endif

    if (   (config || access_init() == 0)
	&& (ttynr = get_ttydef(NULL)) != PSEUDO_TTY)
    {
	time = localtime(&timeval);
	tday = time->tm_hour * 60 + time->tm_min;
	wday = time->tm_wday;
	
	acc = calc_access(wday, tday, ttynr, proto, host, 0);
    }
    
    if (acc >= MIN_ACCESS)
    {
	/* if (ttynr != PSEUDO_TTY) */
	set_wtmp('-', host);
    } else
      acc = 0;

#ifdef CHECK_ACCESS
    /* Return (=Exit) code darf maximal 255 sein!
       -> <100	: access time in Minuten
	  <255	: access time (-100)x5 + 100 in Minuten
	  255	: unlimitiert
     */
    if (acc < 100)
      return acc;

    if (acc < 9999)
    {
	int ret = 100 + (acc - 100 + 4) / 5;
	if (ret > 255) ret = 255;
	return ret;
    }

    return(255);
#else
    if (acc < 9999 && exit_fun)
      watch_access(ttynr, acc, exit_fun);
    return acc;
#endif
}

#ifdef ACCESS_MAIN

main(int argc, char** argv)
{
    time_t timeval = time(NULL);
    struct tm* time;
    int acc, wday, tday;
    time = localtime(&timeval);
    tday = time->tm_hour * 60 + time->tm_min;
    wday = time->tm_wday;

    if (argc == 6) wday = atoi(argv[5]);
    if (argc >= 5)
    {
	char* s = argv[4];
	eat_num(&s, &tday, TIME);
    }
    if (argc >= 4)
    {
	int ttynr = atoi(argv[1]);
	access_conf = ACC_CONF;
	access_daily = ACC_DAILY;
/*	access_conf  = "linetest.conf";
	access_daily = "linetest.time"; */
	if (access_init()) return 0;
	
	if (!ttynr) ttynr = get_ttydef(argv[1]);
#ifdef OUTPUT
	print_config();
	printf("calculating for tty-type: %d\n", ttynr);
#endif
	acc = calc_access(wday, tday, ttynr, argv[2][0],argv[3], 0);
#ifdef OUTPUT
	printf("access: %d\n", acc);
#endif
    } else if (argc > 1 && strcmp(argv[1], "test") == 0)
    {
	typedef struct acctest
	{
	    int tty;
	    char proto;
	    char* host;
	    int wday;
	    float tday;
	    int acc;
	} acctest;
	int n;
	acctest accarr[] =
	{
	    { 0, 'S', "castrop", 1, 10.0, 480 },
	    { 2, 'C', "castrop", 3, 17.5,  30 },
	    { 3, 'P', "castrop", 5, 18.0,   0 },
	    { 1, 'S', "castrop", 6, 19.3,   0 },
	    { 1, 'I', "amberle", 1, 18.0,  20 }, 	    
	    { 1, 'U', "amberle", 1, 18.0,  25 }, 	    
	    { 1, 'S', "witten", 5, 18.5, 10 },
	    { 4, 'S', "witten", 5, 18.5, 99 },
	    { 4, 'S', "witten", 6, 18.5, 1899 },
	    { 0, 'S', "todonix", 0, 19, 60  },
	    { 4, 'S', "todonix", 0, 19, 3600 },
        };
	access_conf = "linetest.conf";
	access_daily = "linetest.daily";
	if (access_init())
	  return 0;
	
#ifdef OUTPUT
	print_config();
#endif
	for (n=0; n<sizeof(accarr)/sizeof(*accarr); n++)
	{
	    acc = calc_access(accarr[n].wday,
			      (int) (accarr[n].tday*60.0),
			      accarr[n].tty,
			      accarr[n].proto,
			      accarr[n].host, 0);
	    printf("tty%02d %c %d %02d:%02d %-10s\t: %4d min.",
		   accarr[n].tty, accarr[n].proto,
		   accarr[n].wday, (int) accarr[n].tday,
		   (int) (accarr[n].tday*60.0 - ((int)accarr[n].tday)*60.0),
		   accarr[n].host, acc);
	    if (acc != accarr[n].acc) printf("!");
	    printf("\n");
	}
    } else      
      printf("\nusage: access tty Protokoll host [time] [Weekday]\n");
}

#endif
#ifdef EXPRESS_TEST
void main(int argc, char** argv)
{
    if (argc > 1)
    {
	access_init();
	ttynr = get_ttydef(argv[1]);
	printf ("tty: %s %d\n", argv[1], ttynr);
	printf ("express: %d\n", check_express());
	printf ("express: %d\n", check_express());
	watch_access(ttynr,1,NULL);
    }
}
#endif
    
