/*
 * sendpass.c -- A Zephyr utility to securely+ send a pass phrase to
 * your zwgc.  
 *
 * +Secure only so long as the link between your CPU and your zwgc port
 * is secure, as this uses UDP packets (hopefully) through the loopback
 * port.
 *
 * Created by:	Derek Atkins <warlord@MIT.EDU>
 *
 */

#include <zephyr/zephyr_internal.h>
#include <string.h>
#include <netdb.h>
#include <pwd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/param.h>

#ifdef KERBEROS
#include <krb.h>
#endif

char *getenv();

char hostname[MAXHOSTNAMELEN];
int (*auth)();
char *myhost;
u_short toport;
Code_t MyZ_XmitFragment();

main(argc, argv)
int argc;
char *argv[];
{
    int retval, msglen;
    char *class = "*";
    char *message;
    char bfr[BUFSIZ];
    char *whoami = argv[0];
    static ZNotice_t notice, retnotice;
    auth = ZAUTH;

    if (argc > 2) {
	fprintf(stderr, "Usage: %s [class]\n", whoami);
	exit(1);
    }

    if (argc == 2)
	class = argv[1];

    /* Initialize Zephyr */
    if ((retval = ZInitialize()) != ZERR_NONE) {
        com_err(whoami, retval, "while initializing");
        exit(1);
    }
    
    if ((retval = Z_GetMyAddr()) != ZERR_NONE) {
        com_err(whoami, retval, "while finding my host");
        exit(1);
    }

    /* Get my hostname and port set up appropriately */
    if ((gethostname(hostname, MAXHOSTNAMELEN)) < 0) {
	fprintf(stderr, "%s: Cannot get local host name\n", whoami);
	exit(1);
    }
    myhost = hostname;

    if (ZGetWGPort() < 0) {
        fprintf(stderr, "%s: Cannot get local WindowGram Port.\n", whoami);
        exit(1);
    }
    toport = ZGetWGPort();

    ZSetServerState(1);
    
    __HM_addr.sin_port = toport;
    __HM_set = 1;

    /* Set up notice */
    notice.z_kind = ACKED;
    notice.z_port = 0;
    notice.z_class = "MESSAGE";
    notice.z_class_inst = "PERSONAL";
    notice.z_opcode = "PGPPASS";
    notice.z_sender = 0;
    notice.z_recipient = ZGetSender();
    notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold($1) <$sender>\n\n$2";

    /* Initialize Passphrase XXX */
    if (strcmp(class, "*"))
	printf("Passphrase for class \"%s\": ", class);
    else
	printf("Passphrase: ");

    if ((retval = des_read_pw_string(bfr, BUFSIZ, "", 0)) != 0) {
	fprintf(stderr, "%s: Error reading pass phrase\n", whoami);
	exit(1);
    }

    /* message == signature\0message\0 */
    msglen = 0;
    message = malloc(strlen(class) + strlen(bfr) + 2);

    strcpy(message, bfr);
    msglen += strlen(bfr);
    message[msglen++] = '\0';

    bzero(bfr, BUFSIZ);

    strcpy(message+msglen, class);
    msglen += strlen(class);
    message[msglen++] = '\0';

    notice.z_message = message;
    notice.z_message_len = msglen;

    if ((retval = MyZSendNotice(&notice, auth)) != ZERR_NONE) {
	(void) sprintf(bfr, "while sending notice to %s", 
		       notice.z_recipient);
	com_err(whoami, retval, bfr);
	exit(1);
    }

    if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0,
			    ZCompareUIDPred,
			    (char *)&notice.z_uid)) !=
	ZERR_NONE) {
	ZFreeNotice(&retnotice);
	(void) sprintf(bfr, "while waiting for acknowledgement for %s",
		       notice.z_recipient);
	com_err(whoami, retval, bfr);
	exit(1);
    }

    if (retnotice.z_kind != CLIENTACK) {
	printf("Detected server failure while receiving acknowledgement for %s\n",
	       notice.z_recipient);
	ZFreeNotice(&retnotice);
	exit(1);
    }

    if (!strcmp(retnotice.z_message, ZSRVACK_SENT) ||
	(retnotice.z_kind == CLIENTACK)) {
	printf("%s: Message sent\n", notice.z_recipient);
    } else {
	if (!strcmp(retnotice.z_message,
		    ZSRVACK_NOTSENT)) {
	    printf("%s: Not logged in or not subscribing to messages\n",
		   notice.z_recipient);
	} else
	    printf("Internal failure - illegal message field in server response\n");
	ZFreeNotice(&retnotice);
	exit(1);
    }
    
    ZFreeNotice(&retnotice);
    exit (0);
}

/*ARGSUSED*/
Code_t MyZ_XmitFragment(notice, buf, len, wait)
ZNotice_t *notice;
char *buf;
int len;
int wait;
{
#ifdef KERBEROS
    int result;
    Code_t retval;
    CREDENTIALS c;
    char realm[REALM_SZ +1], *tkt_file;
    
    if ((tkt_file = getenv("KRBTKFILE")) == NULL)
	tkt_file = TKT_FILE;
    
    krb_get_tf_realm(tkt_file, realm);
    
    result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm, &c);
    
    if ((retval = ZFormatAuthenticNotice(notice, buf, len, &len, c.session))
	!= ZERR_NONE) {
	com_err(retval, "While formatting notice");
	return(retval);
    }
#endif
    
    return(ZSendPacket(buf, len, wait));
}

Code_t MyZSendNotice(notice, cert_routine)
ZNotice_t *notice;
int (*cert_routine)();
{
    return(ZSrvSendNotice(notice, cert_routine, MyZ_XmitFragment));
}
