/* This file is part of the Project Athena Zephyr Notification System.
 * It contains code for the "zaway" command.
 *
 *	Created by:	Robert French
 *
 *	$Id: zaway.c,v 1.2 2000/08/23 00:23:00 assar Exp $
 *
 *	Copyright (c) 1987, 1993 by the Massachusetts Institute of Technology.
 *	For copying and distribution information, see the file
 *	"mit-copyright.h". 
 */

#include <sysdep.h>
#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>
#include <pwd.h>
#include <com_err.h>

#include <roken.h>

#ifndef lint
static const char rcsid_zaway_c[] = "$Id: zaway.c,v 1.2 2000/08/23 00:23:00 assar Exp $";
#endif

#define MESSAGE_CLASS "MESSAGE"
#define DEFAULT_MSG "I'm sorry, but I am currently away from the terminal and am\nnot able to receive your message.\n"
#define RESPONSE_OPCODE ""

static char *find_message(const ZNotice_t *notice, FILE *fp);

static u_short port;

static void
usage(const char *name)
{
	printf("Usage: %s [OPTIONS] [FILE]\n"
	       "\n"
	       "  -m STRING    use STRING as the body of the reply message\n"
	       "  -w           watch your location and only reply if you aren't locatable\n"
	       "  -h           display this help and exit\n",
	       name);
}

static int quit = 0;

static RETSIGTYPE
cleanup(int sig)
{
    quit = 1;
}

int
main(int argc, char **argv)
{
	FILE *fp;
	ZNotice_t notice;
	ZSubscription_t sub;
	int retval;
	struct passwd *pw;
	char *ptr;
	char awayfile[MAXPATHLEN],*msg[2],*envptr;
	int optchar, watch_location;
	char *cmdline_msg;
	int nlocs;
#ifdef _POSIX_VERSION
	struct sigaction sa;
#endif
	int i;
	int nrealms;
	
	if ((retval = ZInitialize()) != ZERR_NONE) {
		com_err(argv[0],retval,"while initializing");
		exit(1);
	}

	port = 0;
	if ((retval = ZOpenPort(&port)) != ZERR_NONE) {
		com_err(argv[0],retval,"while opening port");
		exit(1);
	}

	sub.zsub_class = MESSAGE_CLASS;
	sub.zsub_classinst = "*";
	sub.zsub_recipient = ZGetSender();

	cmdline_msg = 0;
	watch_location = 0;
	while ((optchar = getopt(argc, argv, "m:wh")) != EOF) {
		switch (optchar) {
		case 'm':
			cmdline_msg = optarg;
			break;

		case 'w':
			watch_location = 1;
			break;

		case 'h':
			usage(argv[0]);
			return 0;

		case '?':
			fprintf(stderr,
				"Unrecognized option '-%c'.\n"
				"Try '%s -h' for more information.\n",
				optopt, argv[0]);
			return 1;
		}
	}

	if (argc > optind)
		strlcpy(awayfile, argv[optind], sizeof(awayfile));
	else {
		envptr = getenv("HOME");
		if (envptr)
			snprintf(awayfile, sizeof(awayfile),
				 "%s/.away",envptr);
		else {
			if (!(pw = getpwuid(getuid()))) {
				fprintf(stderr,"Who are you?\n");
				exit(1);
			}
			snprintf(awayfile, sizeof(awayfile),
				 "%s/.away", pw->pw_dir);
		} 
	}

	fp = fopen(awayfile,"r");
	if (!fp && argc > 1) {
		fprintf(stderr,"File %s not found!\n",awayfile);
		exit(1);
	} 
#ifdef _POSIX_VERSION
	(void) sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sa.sa_handler = cleanup;
	(void) sigaction(SIGINT, &sa, (struct sigaction *)0);
	(void) sigaction(SIGTERM, &sa, (struct sigaction *)0);
	(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
#else
	(void) signal(SIGINT, cleanup);
	(void) signal(SIGTERM, cleanup);
	(void) signal(SIGHUP, cleanup);
#endif
	retval = ZGetRealmCount(&nrealms);
	if (retval) {
	    com_err(argv[0], retval, "ZGetRealmCount");
	    exit(1);
	}

	for (i = 0; i < nrealms; ++i) {
	    char *realm;

	    retval = ZGetRealmName(i, &realm);
	    if (retval) {
		com_err(argv[0], retval, "ZGetRealmName");
		exit(1);
	    }

	    retval = ZSubscribeToSansDefaults(realm, &sub, 1, port);
	    if(retval != ZERR_NONE) {
		com_err(argv[0],retval,"while subscribing");
		exit(1);
	    }
	}

	while (!quit) {
		retval = ZReceiveNotice(&notice, (struct sockaddr_in *)0);
		if (retval != ZERR_NONE) {
			com_err(argv[0],retval,"while receiving notice");
			continue;
		}

		if (strcmp(notice.z_sender,ZGetSender()) == 0 ||
		    strcmp(notice.z_opcode,"PING") == 0 ||
		    strcmp(notice.z_message,"Automated reply:") == 0) {
		     ZFreeNotice(&notice);
		     continue;
		}

		if (watch_location) {
		        retval = ZNewLocateUser(NULL, ZGetSender(), &nlocs,
						ZNOAUTH);
			if (retval != ZERR_NONE) {
				com_err(argv[0],retval,"while locating self");
				continue;
			}

			if (nlocs != 0) {
				/* User is logged in.  Don't send an autoreply. */
				continue;
			}

			ZFlushLocations();
		}

		if (cmdline_msg) {
		        ptr = strdup(cmdline_msg);
			if (ptr == NULL) {
				com_err(argv[0],ENOMEM,"while getting cmdline message");
				exit(1);
			}
		} else if (fp) {
			if (!(ptr = find_message(&notice,fp))) {
				ZFreeNotice(&notice);
				continue;
			}
		} else {
		        ptr = strdup(DEFAULT_MSG);
			if (ptr == NULL) {
				com_err(argv[0],ENOMEM,"while getting default message");
				exit(1);
			}
		}
		notice.z_recipient = notice.z_sender;
		notice.z_sender = 0;
		notice.z_default_format = "";
		notice.z_opcode = RESPONSE_OPCODE;

		msg[0] = "Automated reply:";
		msg[1] = ptr;
		
		notice.z_message_len = strlen(notice.z_message)+1;
		if ((retval = ZSendList(&notice,msg,2,ZNOAUTH)) != ZERR_NONE) {
			com_err(argv[0],retval,"while sending notice");
		}
		free(ptr);
		ZFreeNotice(&notice);
	}
	for (i = 0; i < nrealms; ++i) {
	    char *realm;

	    retval = ZGetRealmName(i, &realm);
	    if (retval) {
		com_err(argv[0], retval, "ZGetRealmName");
		exit(1);
	    }

	    ZCancelSubscriptions (realm, port);
	}
	exit(0);
}

static char *
find_message(const ZNotice_t *notice, FILE *fp)
{
	char *ptr,*ptr2;
	char bfr[BUFSIZ],sender[BUFSIZ];
	int gotone,lastwasnt;
	
	rewind(fp);

	(void) strcpy(sender, notice->z_sender);
	ptr2 = strchr(sender,'@');
	if (ptr2)
		*ptr2 = '\0';
	
	ptr = 0;
	gotone = 0;
	lastwasnt = 0;
	
	while (fgets(bfr,sizeof bfr,fp) != (char *)0) {
		if (*bfr == '>') {
			if (lastwasnt)
				gotone = 0;
			bfr[strlen(bfr)-1] = '\0';
			ptr2 = strchr(bfr,'@');
			if (ptr2)
				*ptr2 = '\0';
			if (!strcmp(bfr+1,sender) ||
			    !strcmp(bfr+1,"*") ||
			    (!strcmp(bfr+1,"%") && !ptr))
				gotone = 1;
			lastwasnt = 0;
		} 
		else {
			if (gotone) {
				if (!ptr) {
					ptr = malloc(strlen(bfr)+1);
					*ptr = '\0';
				} 
				else
					ptr = realloc(ptr,strlen(bfr)+strlen(ptr)+1);
				(void) strcat(ptr,bfr);
			}
			lastwasnt = 1;
		}
	}

	return (ptr);
}
