#ifndef lint
static char *RCSid = "$Header: /source/users/msg/msgd/RCS/server.c,v 1.5 91/08/14 00:00:19 jmsellens Exp $";
#endif

#if 0
/*
 * $Log:	server.c,v $
 * Revision 1.5  91/08/14  00:00:19  jmsellens
 * s/eprintf/errprintf/ to avoid libuw clash
 * 
 * Revision 1.4  90/12/29  22:04:11  jmsellen
 * VARARGS changes
 * 
 * Revision 1.3  88/11/07  11:09:54  jmsellens
 * Call new sanitize() routine to avoid control characters.  This is
 * necessary to avoid someone modifying the msg source and making
 * their own nasty client that doesn't behave nicely.
 * 
 * Revision 1.2  88/09/25  02:41:31  jmsellens
 * Added stuff to accept version records in the future.  Taught to
 * look up the sender's machine name, so that we get the name that
 * we use to get there, not the value of `hostname` on the remote
 * machine, which probably isn't properly domain-ized if it's
 * remote from us.
 * 
 * Revision 1.1  87/08/06  19:06:43  sahayman
 * Initial revision
 * 
 */
#endif

/* server.c
   read message coming from server, call deliver, and acknowledge with
   result code
*/

/* We ignore any errors communicating with the client, since we figure
   they just dies or broke out or something */

#include "msg.h"
#include <netinet/in.h>
#include <netdb.h>
#if vms
#include <string.h>
#include "twg$tcp:[netdist.include.arpa]inet.h"
#else
#include <strings.h>
#include <arpa/inet.h>
#endif
extern int client;
private int remote_ver = 0;

server()
{
    version ver;
    header h;
    int err;
    char sender[BUFSIZ], user[BUFSIZ], rawmsg[BUFSIZ], message[BUFSIZ];
    
#if vms
    if ( netread( client, &ver, sizeof(ver) ) != sizeof(ver) ) goto done;
#else
    if ( read( client, &ver, sizeof(ver) ) != sizeof(ver) ) goto done;
#endif
    if ( ntohl(ver.v.zero) == 0 ) {
	/* got a version struct */
	remote_ver = ntohl(ver.v.vnum);
	if ( remote_ver > VERSION ) {
	    errmsg( BAD_VERSION, remote_ver, VERSION );
	    goto done;
	}
	/* acknowledge that we agree on the version */
	err = htonl(VERSION_OK);
#if vms
	(void) netwrite( client, &err, sizeof(err) );
	if ( netread( client, &h, sizeof(h) ) != sizeof(h) ) goto done;
#else
	(void) write( client, &err, sizeof(err) );
	if ( read( client, &h, sizeof(h) ) != sizeof(h) ) goto done;
#endif
    } else {
	/* Not a version struct, so copy it into header struct */
	h = ver.h;
    }
    h.slen = ntohl(h.slen);
    h.ulen = ntohl(h.ulen);
    h.mlen = ntohl(h.mlen);
#if vms
    if ( netread( client, sender, h.slen ) != h.slen ) goto done;
#else
    if ( read( client, sender, h.slen ) != h.slen ) goto done;
#endif
    sender[h.slen] = '\0';
#if vms
    if ( netread( client, user, h.ulen ) != h.ulen ) goto done;
#else
    if ( read( client, user, h.ulen ) != h.ulen ) goto done;
#endif
    user[h.ulen] = '\0';
#if vms
    if ( netread( client, rawmsg, h.mlen ) != h.mlen ) goto done;
#else
    if ( read( client, rawmsg, h.mlen ) != h.mlen ) goto done;
#endif
    rawmsg[h.mlen] = '\0';
    get_real_sender(sender);
    sanitize( rawmsg, message );
    err = deliver( sender, user, message, FALSE );
    /* deliver gave us a pgrp when it opened a tty... */
#if vms
#else
    setpgrp(0, 0);
#endif
    err = htonl(err);
#if vms
    (void) netwrite( client, &err, sizeof(err) );
#else
    (void) write( client, &err, sizeof(err) );
#endif
done:
    ;
}


#ifdef VARARGS
errmsg( msgnum, va_alist )
int msgnum;
va_dcl
#else
errmsg( msgnum, a, b, c, d, e )
int msgnum;
char *a, *b, *c, *d, *e;
#endif
{
    char buf[BUFSIZ];
    int i = htonl(ERROR_MESSAGE);
    
    (void) write( client, &i, sizeof(i) );
#ifdef VARARGS
    {
	va_list ap;
	va_start( ap );
	(void) vsprintf( buf, errmessages[msgnum], ap );
	va_end( ap );
    }
#else
    (void) sprintf( buf, errmessages[msgnum], a, b, c, d, e );
#endif
    i = htonl(strlen( buf ));
    (void) write( client, &i, sizeof(i) );
    (void) write( client, buf, strlen(buf) );
}




get_real_sender( sender )
char *sender;
{
    struct sockaddr_in from;
    struct hostent *hp;
    char *p;
    int fromlen;
    fromlen = sizeof(from);

    p = index( sender, '@' );
    if ( p == CPNULL ) {
	errprintf( "sender '%s' contains no '@'", sender );
	(void) strcat( sender, "@" );
	p = index( sender, '@' );
    }
    p++;
    if ( index( p, '@' ) != CPNULL ) {
	errprintf( "sender '%s' contains multiple '@'s", sender );
	p = rindex( sender, '@' );
	p++;
    }
    if ( getpeername( client, &from, &fromlen ) < 0 ) {
	errprintf( "couldn't getpeername(): %s", syserr() );
	(void) strcat( sender, "<unknown>" );
    } else {
	hp = gethostbyaddr( (char *)&from.sin_addr, sizeof(struct in_addr),
	    from.sin_family );
	if ( hp )
	    (void) strcpy( p, hp->h_name );
	else
	    (void) strcpy( p, inet_ntoa( from.sin_addr ) );
    }
}
