/*  $Revision: 1.18 $
**
**  Active file server for readers (NNRP) for InterNetNews.
*/

#define		UPDATE_INTERVAL	30
#define		MAINLINE
#include	<stdio.h>
#include	"actived.h"
#include	"protocol.h"
#include	"configdata.h"
#include	"paths.h"



char	ACTIVE[] = _PATH_ACTIVE;
char	PID[] = _PATH_ACTIVEDPID;
char	INNDDIR[] = _PATH_INNDDIR;
STATIC	UID_T	NewsUID;
STATIC	GID_T	NewsGID;
struct	stat	Sb;

int
handle(s)
    int			s;
{
    GROUPENTRY *ptr;
    struct sockaddr saddr;
    struct sockaddr_in *sin = (struct sockaddr_in *)&saddr;
    int saddrsiz = sizeof(saddr);
    struct wireprotocol buffer;
    int len = sizeof(buffer);
    int rval;

    if ((rval = recvfrom(s, (char *)&buffer, len, 0, &saddr, &saddrsiz)) < 0) {
	syslog(L_ERROR, "cant recvfrom %m");
	return(-1);
    }

    if (rval != sizeof(buffer)) {
	syslog(L_ERROR, "message size wrong");
	return(-1);
    }

    /* XXX If not 127.0.0.1, then reject and return */


    switch (buffer.RequestType) {
	case 	REQ_AYT:
	    buffer.RequestType = REQ_AYTACK;
	    if (sendto(s, (char *)&buffer, len, 0, &saddr, saddrsiz) < 0) {
		syslog(L_ERROR, "cant sendto %m");
		return(-1);
	    }
	    return(0);
	case 	REQ_FIND:
	    buffer.RequestType = REQ_FINDRESP;

	    buffer.Name[sizeof(buffer.Name) - 1] = '\0';
	    if (! (ptr = GRPfind(buffer.Name))) {
		buffer.Success = 0;
	    } else {
		buffer.Success = 1;
		if (ptr->Name) {
		    buffer.NameNull = 0;
		    strncpy(buffer.Name, ptr->Name, sizeof(buffer.Name) - 1);
		    buffer.Name[sizeof(buffer.Name) - 1] = '\0';
		} else {
		    buffer.NameNull = 1;
		}
		buffer.High = ptr->High;
		buffer.Low = ptr->Low;
		buffer.Flag = ptr->Flag;
		if (ptr->Alias) {
		    buffer.AliasNull = 0;
		    strncpy(buffer.Alias, ptr->Alias, sizeof(buffer.Alias) - 1);
		    buffer.Alias[sizeof(buffer.Alias) - 1] = '\0';
		} else {
		    buffer.AliasNull = 1;
		}
	    }
	    if (sendto(s, (char *)&buffer, len, 0, &saddr, saddrsiz) < 0) {
		syslog(L_ERROR, "cant sendto %m");
		return(-1);
	    }
	    return(0);
    }
    syslog(L_ERROR, "unknown requesttype %d", buffer.RequestType);
    return(-1);
}





/* ARGSUSED0 */
int
main(argc, argv)
    int			argc;
    char		*argv[];
{
    int s, i;
    time_t last_active_update = time(NULL), now;
    fd_set fdset;
    struct timeval tv;
    FILE *F;
    PID_T pid;
    static char WHEN[] = "Pid file";
    char LogName[] = "ACTIVED";
    if (stat(INNDDIR, &Sb) < 0 || !S_ISDIR(Sb.st_mode)) {
	syslog(L_FATAL, "inndstart cant stat %s %m", INNDDIR);
	exit(1);
    }
    NewsUID = Sb.st_uid;
    NewsGID = Sb.st_gid;

    openlog("actived", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);

    if ((s = create_udp_socket(1119)) < 0) {
	syslog(L_ERROR, "cant createudpsocket %m");
	exit(1);
    }
    if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
	syslog(L_ERROR, "cant fcntl O_NDELAY socket %m");
	exit(1);
    }
    if (!GetGroupList()) {
	/* This shouldn't really happen. */
	syslog(L_ERROR, "cant getgrouplist %m");
	exit(1);
    }
    i = fork();
    if (i < 0)
        syslog(L_ERROR, "daemon: cannot fork");
    if (i != 0)
        exit(0);

    /* Change our UID and GID */
    if (setgid(NewsGID) == -1)
	syslog(L_ERROR, "actived cant setgid: %m");
    if (setuid(NewsUID) == -1)
	syslog(L_ERROR, "actived cant setuid: %m");

    /* Record our PID. */
    pid = getpid();
    if ((F = fopen(PID, "w")) == NULL) {
      i = errno;
      syslog(L_ERROR, "%s cant fopen %s %m", LogName, PID);
    }
    else {
      if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F)) {
            i = errno;
            syslog(L_ERROR, "%s cant fprintf %s %m", LogName, PID);
      }
      if (fclose(F) == EOF) {
            i = errno;
            syslog(L_ERROR, "%s cant fclose %s %m", LogName, PID);
      }
      if (chmod(PID, 0664) < 0) {
            i = errno;
            syslog(L_ERROR, "%s cant chmod %s %m", LogName, PID);
      }
    }

    for (;;) {
	FD_ZERO(&fdset);
	FD_SET(s, &fdset);
	tv.tv_sec = 0;
	tv.tv_usec = 300000;
	if (select(s + 1, &fdset, NULL, NULL, &tv) < 0) {
	    syslog(L_ERROR, "cant select %m");
	    exit(1);
	}
	now = time(NULL);
	if (now > last_active_update + UPDATE_INTERVAL) {
	    last_active_update = now;
	    if (!GetGroupList()) {
		/* This shouldn't really happen. */
		syslog(L_ERROR, "cant getgrouplist %m");
		exit(1);
	    }
	}
	if (FD_ISSET(s, &fdset)) {
		handle(s);
		loads(0, 1);
	}
    }
    /* NOTREACHED */
}
