/*
** ttyrots.c - For the finger distribution.
**
** Written by Keith Gabryelski
** Released into public domain September 1, 1988.
** Please keep this header.
**
** Some basic routines used in finger and ttyloc.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#include <fcntl.h>
#include "ttyloc.h"
#include "defs.h"

extern int errno;
extern struct utmp *getutline();
extern struct ltmp *getltline();

extern char *myrealloc();

static char *tlocbuf = NULL;

static char *
get_default_ttyloc(ttyname)
char *ttyname;
{
    char *ttyloc = "", *tlocbufend, *bp, *cp;
    int fd, size;
    struct stat stbuf;

    if ((fd = open(TTYLOCS, O_RDONLY)) < 0 || fstat(fd, &stbuf) < 0)
	return ttyloc;

    size = stbuf.st_size;
    tlocbuf = myrealloc(tlocbuf, size + 1);
    tlocbufend = tlocbuf + size;

    if (read(fd, tlocbuf, size) != size)
	return ttyloc;

    close(fd);

    bp = tlocbuf;
    while (bp < tlocbufend)
    {
	for (cp = bp; *bp != ':' && bp < tlocbufend; ++bp) ;

	*bp++ = '\0';
	if (!strcmp(cp, ttyname))
	{
	    ttyloc = bp;
	    while (*bp != '\n' && bp < tlocbufend)
		bp++;
	    *bp = '\0';
	    break;
	}
	else
	{
	    while (*bp != '\n' && bp < tlocbufend)
		++bp;

	    if (*bp == '\n' && bp < tlocbufend)
		++bp;
	}
    }

    return ttyloc;
}

char *
get_ttyloc(ttyname)
char *ttyname;
{
    char *bp, *cp;
    struct ltmp *lt;
    static struct utmp utbuf, *ut;

    strncpy(utbuf.ut_line, ttyname, sizeof(utbuf.ut_line));

    if ((ut = getutline(&utbuf)) == (struct utmp *)NULL)
	return NULL;

    bp = get_default_ttyloc(ttyname);

    if ((lt = getltline(ttyname)) == (struct ltmp *)NULL ||
	lt->lt_time != ut->ut_time)
    {
	cp = bp;
	while (*bp != ':' && *bp != '\0')
	    bp++;

	*bp = '\0';
	return cp;
    }

    return lt->lt_loc;
}

set_ttyloc(ttyname, ttyloc)
char *ttyname, *ttyloc;
{
    char *bp, *cp;
    int l, fd;
    static struct ltmp lt;
    static struct utmp utbuf, *ut;

    strncpy(utbuf.ut_line, ttyname, sizeof(utbuf.ut_line));

    if ((ut = getutline(&utbuf)) == (struct utmp *)NULL)
	return FAIL;

    if ((fd = open(LTMP, O_CREAT|O_RDWR, 0622)) < 0)
	return FAIL;

    while (read(fd, &lt, sizeof(struct ltmp)) == sizeof(struct ltmp))
	if (!strcmp(lt.lt_line, ut->ut_line))
	{
	    lseek(fd, (long)-sizeof(struct ltmp), 1);
	    break;
	}
    
    /* lseek to something divisible by sizeof struct ltmp */
    lseek(fd, lseek(fd, 0, 1) / (long)sizeof(struct ltmp) *
	  (long)sizeof(struct ltmp), 0);

    strncpy(lt.lt_line, ut->ut_line, sizeof(lt.lt_line));
    lt.lt_time = ut->ut_time;

#ifdef DEBUG
    printf("line = %s, time = %lx.\n", lt.lt_line, lt.lt_time);
#endif /* DEBUG */
    bp = get_default_ttyloc(ttyname);

#ifdef DEBUG
    printf("bp = `%s'.\n", bp);
#endif /* DEBUG */

    cp = bp;
    while (*bp != ':' && *bp != '\0')
	bp++;

    if (ttyloc == NULL || *ttyloc == '\0' || *bp == '\0')
    {
	*bp = '\0';
	strncpy(lt.lt_loc, cp, sizeof(lt.lt_loc));
#ifdef DEBUG
	printf("put default %s.\n", cp);
#endif /* DEBUG */
    }
    else
	if (*++bp != '\0')
	{
	    strncpy(lt.lt_loc, bp, sizeof(lt.lt_loc));
	    l = strnlen(lt.lt_loc, sizeof(lt.lt_loc));
	    strncpy(lt.lt_loc+l, ": ", sizeof(lt.lt_loc)-l);
	    l = strnlen(lt.lt_loc, sizeof(lt.lt_loc));
	    strncpy(lt.lt_loc+l, ttyloc, sizeof(lt.lt_loc)-l);
#ifdef DEBUG
	    printf("put :+ %s.\n", lt.lt_loc);
#endif /* DEBUG */
	}
	else
	{
	    strncpy(lt.lt_loc, ttyloc, sizeof(lt.lt_loc));
#ifdef DEBUG
	    printf("put ttyloc %s.\n", lt.lt_loc);
#endif /* DEBUG */
	}

    write(fd, &lt, sizeof(struct ltmp));
    close(fd);
    return OK;
}

struct ltmp *
getltline(line)
char line[12];
{
    int fd;
    static struct ltmp lt;

    if ((fd = open(LTMP, O_RDONLY)) < 0)
	return (struct ltmp *)NULL;

    while (read(fd, &lt, sizeof(struct ltmp)) == sizeof(struct ltmp))
	if (!strcmp(lt.lt_line, line))
	{
	    close(fd);
	    return &lt;
	}

    close(fd);
    return (struct ltmp *)NULL;
}
