/*
 * main.c: for rcpt500 (X.500 email query responder)
 *
 * 16 June 1992 by Mark C Smith
 * Copyright (c) 1992 The Regents of The University of Michigan
 * All Rights Reserved
 */

#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>

#include "portable.h"
#include "ldapconfig.h"
#include "rcpt500.h"

#ifdef ultrix
extern char *strdup();
#endif

int dosyslog = 0;
#ifdef CLDAP
int do_cldap = 0;
#endif /* CLDAP */
int derefaliases = 1;
int sizelimit = RCPT500_SIZELIMIT;
int rdncount = RCPT500_RDNCOUNT;
int ldapport = 0;
char *ldaphost = LDAPHOST;
char *searchbase = RCPT500_BASE;
char *dapuser = RCPT500_BINDDN;
char *filterfile = FILTERFILE;
char *templatefile = TEMPLATEFILE;
char reply[ MAXSIZE * RCPT500_LISTLIMIT ];



/*
 * functions
 */
int	read_msg();
char	*read_hdr();
int 	send_reply();

/*
 * main is invoked by sendmail via the alias file
 * the entire incoming message gets piped to our standard input
 */
main( argc, argv )
    int		argc;
    char	**argv;
{
    char		*prog, *usage = "%s [-l] [-U] [-h ldaphost] [-p ldapport] [-b searchbase] [-a] [-z sizelimit] [-u dapuser] [-f filterfile] [-t templatefile] [-c rdncount]\n";
    struct msginfo	msg;
    int			c, errflg;
    char		*replytext;

    extern int		optind;
    extern char		*optarg;

    *reply = '\0';

    if (( prog = strrchr( argv[ 0 ], '/' )) == NULL ) {
	prog = strdup( argv[ 0 ] );
    } else {
	prog = strdup( prog + 1 );
    }

    errflg = 0;
    while (( c = getopt( argc, argv, "alUh:b:s:z:f:t:p:c:" )) != EOF ) {
	switch( c ) {
	case 'a':
	    derefaliases = 0;
	    break;
	case 'l':
	    dosyslog = 1;
	    break;
	case 'U':
#ifdef CLDAP
	    do_cldap = 1;
#else /* CLDAP */
	    fprintf( stderr, "Compile with -DCLDAP for -U support\n" );
#endif /* CLDAP */
	    break;	
	case 'b':
	    searchbase = optarg;
	    break;
	case 'h':
	    ldaphost = optarg;
	    break;
	case 'p':
	    ldapport = atoi( optarg );
	    break;
	case 'z':
	    sizelimit = atoi( optarg );
	    break;
	case 'u':
	    dapuser = optarg;
	    break;
	case 'f':
	    filterfile = optarg;
	    break;
	case 't':
	    templatefile = optarg;
	    break;
	case 'c':
	    rdncount = atoi( optarg );
	    break;
	default:
	    ++errflg;
	}
    }
    if ( errflg || optind < argc ) {
	fprintf( stderr, usage, prog );
	exit( 1 );
    }

    if ( dosyslog ) {
	/*
	 * if syslogging requested, initialize
	 */
#ifdef LOG_DAEMON
	openlog( prog, OPENLOG_OPTIONS, LOG_DAEMON );
#else
	openlog( prog, OPENLOG_OPTIONS );
#endif
    }

    if ( read_msg( stdin, &msg ) < 0 ) {
	if ( dosyslog ) {
	    syslog( LOG_INFO, "unparseable message ignored" );
	}
	exit( 0 );	/* so as not to give sendmail an error */
    }

    if ( dosyslog ) {
	syslog( LOG_INFO, "processing command \"%s %s\" from %s",
		( msg.msg_command < 0 ) ? "Unknown" :
		cmds[ msg.msg_command ].cmd_text,
		( msg.msg_arg == NULL ) ? "" : msg.msg_arg, msg.msg_replyto );
    }

    if ( msg.msg_command < 0 ) {
	msg.msg_command = 0;	/* unknown command == help command */
    }

/*
    sprintf( reply, "Your request was interpreted as: %s %s\n\n",
	    cmds[ msg.msg_command ].cmd_text, msg.msg_arg );
*/

    (*cmds[ msg.msg_command ].cmd_handler)( &msg, reply );

    if ( send_reply( &msg, reply ) < 0 ) {
	if ( dosyslog ) {
	    syslog( LOG_INFO, "reply failed: %m" );
	}
	exit( 0 );	/* so as not to give sendmail an error */
    }

    if ( dosyslog ) {
	syslog( LOG_INFO, "reply OK" );
    }

    exit( 0 );
}


int
read_msg( fp, msgp )
    FILE		*fp;
    struct msginfo	*msgp;
{
    char	buf[ MAXSIZE ], *line;
    int		command = -1;

    msgp->msg_replyto = msgp->msg_date = msgp->msg_subject = NULL;

    line = NULL;
    while( 1 ) {
	if ( line == NULL ) {
	    if (( line = fgets( buf, MAXSIZE, fp )) == NULL ) {
		break;
	    }
	    buf[ strlen( buf ) - 1 ] = '\0';	/* remove trailing newline */
	}

	if ( *buf == '\0' ) {	/* start of message body */
	    break;
	}
	if ( strncasecmp( buf, "Reply-To:", 9 ) == 0 ) {
	    if ( msgp->msg_replyto != NULL ) {
		free( msgp->msg_replyto );
	    }
	     msgp->msg_replyto = read_hdr( fp, 9, buf, MAXSIZE, &line );
	} else if ( strncasecmp( buf, "From:", 5 ) == 0 &&
		    msgp->msg_replyto == NULL ) {
	     msgp->msg_replyto = read_hdr( fp, 5, buf, MAXSIZE, &line );
	} else if ( strncasecmp( buf, "Date:", 5 ) == 0 ) {
	     msgp->msg_date = read_hdr( fp, 5, buf, MAXSIZE, &line );
	} else if ( strncasecmp( buf, "Message-ID:", 5 ) == 0 ) {
	     msgp->msg_messageid = read_hdr( fp, 11, buf, MAXSIZE, &line );
	} else if ( strncasecmp( buf, "Subject:", 8 ) == 0 ) {
	     if (( msgp->msg_subject =
		    read_hdr( fp, 8, buf, MAXSIZE, &line )) != NULL ) {
		command = find_command( msgp->msg_subject, &msgp->msg_arg );
	    }
	} else {
	    line = NULL;	/* discard current line */
	}
    }

    while ( command < 0 && line != NULL ) {
	/*
	 * read the body of the message, looking for commands
	 */
	if (( line = fgets( buf, MAXSIZE, fp )) != NULL ) {
	    buf[ strlen( buf ) - 1 ] = '\0';	/* remove trailing newline */
	    command = find_command( buf, &msgp->msg_arg );
	}
    }

    if ( msgp->msg_replyto == NULL ) {
	return( -1 );
    }

    msgp->msg_command = command;
    return( 0 );
}


char *
read_hdr( fp, offset, buf, MAXSIZEe, linep )
    FILE	*fp;
    int		offset;
    char	*buf;
    int		MAXSIZEe;
    char	**linep;
{
    char	*hdr;

    for ( hdr = buf + offset; isspace( *hdr ); ++hdr ) {
	;
    }
    if (( hdr = strdup( hdr )) == NULL ) {
	if ( dosyslog ) {
	    syslog( LOG_ERR, "strdup: %m" );
	}
	exit( 1 );
    }

    while ( 1 ) {
	*linep = fgets( buf, MAXSIZE, fp );
	buf[ strlen( buf ) - 1 ] = '\0';	/* remove trailing newline */
	if ( *linep == NULL || !isspace( **linep )) {
	    break;
	}
	if (( hdr = realloc( hdr, strlen( hdr ) +
		    strlen( *linep ) + 3 )) == NULL) {
	    if ( dosyslog ) {
		syslog( LOG_ERR, "realloc: %m" );
	    }
	    exit( 1 );
	}
	strcat( hdr, "\n" );
	strcat( hdr, *linep );
    }

    return( hdr );
}


int
send_reply( msgp, body )
    struct msginfo	*msgp;
    char		*body;
{
    char	buf[ MAXSIZE ];
    FILE	*cmdpipe;
    int		rc;
    
    if (( cmdpipe = popen( RCPT500_PIPEMAILCMD, "w" )) == NULL ) {
	if ( dosyslog ) {
	    syslog( LOG_ERR, "popen pipemailcmd failed: %m" );
	}
	return( -1 );
    }

    /*
     * send the headers
     */

    sprintf( buf, "From: %s\n", RCPT500_FROM );
    rc = fwrite( buf, strlen( buf ), 1, cmdpipe );

    if ( rc == 1 ) {
	if ( msgp->msg_subject != NULL ) {
	    sprintf( buf, "Subject: Re: %s\n", msgp->msg_subject );
	} else {
	    sprintf( buf, "Subject: query response\n" );
	}
	rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
    }

    if ( rc == 1 && msgp->msg_date != NULL ) {
	/*
	 * add "In-reply-to:" header
	 */
	if ( msgp->msg_messageid == NULL ) {
	    sprintf( buf, "In-reply-to: Your message of \"%s\"\n",
		    msgp->msg_date );
	} else {
	    sprintf( buf,
		    "In-reply-to: Your message of \"%s\"\n             %s\n",
		    msgp->msg_date, msgp->msg_messageid );
	}
	rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
    }

    if ( rc == 1 ) {
	sprintf( buf, "To: %s\n", msgp->msg_replyto );
	rc = fwrite( buf, strlen( buf ), 1, cmdpipe );
    }

    /*
     * send the header/body separator (blank line)
     */
    if ( rc == 1 ) {
	rc = fwrite( "\n", 1, 1, cmdpipe );
    }

    /*
     * send the body
     */
    if ( rc == 1 ) {
	rc = fwrite( body, strlen( body ), 1, cmdpipe );
    }

    if ( rc != 1 && dosyslog ) {
	syslog( LOG_ERR, "write to binmail failed: %m" );
    }

    if ( pclose( cmdpipe ) < 0 ) {
	if ( dosyslog ) {
	    syslog( LOG_ERR, "pclose binmail failed: %m" );
	}
	return( -1 );
    }

    return( rc == 1 ? 0 : -1 );
}


int
find_command( text, argp )
    char	*text;
    char	**argp;
{
    int		i;
    char	*s, *p;
    static char argbuf[ MAXSIZE ];

    p = text;
    for ( s = argbuf; *p != '\0'; ++p ) {
	*s++ = tolower( *p );
    }
    *s = '\0';

    for ( i = 0; cmds[ i ].cmd_text != NULL; ++i ) {
	if (( s = strstr( argbuf, cmds[ i ].cmd_text )) != NULL
		    && isspace( *(s + strlen( cmds[ i ].cmd_text )))) {
	    strcpy( argbuf, text + (s - argbuf) + strlen( cmds[ i ].cmd_text ));
	    *argp = argbuf;
	    while ( isspace( **argp )) {
		++(*argp);
	    }
	    return( i );
	}
    }

    return( -1 );
}
