#include<stdio.h>
#include<ctype.h>
#include<krb.h>
#include<syslog.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/file.h>
#include<sys/time.h>
#include<sys/ioctl.h>
#include<netinet/in.h>
#include<zephyr/zephyr.h>

#define FACILITY LOG_LOCAL2
#define DEF_ER_CLASS "message"
#define DEF_ER_INSTANCE "er-joke"
#define RESPONSES_FILE "/site/lib/er-joke-responses"

unsigned short z_port = 0;

char 
  er_class[40], 
  er_instance[40]; /* Big enough because I say so */

kick_me();

main(argc, argv)
     int argc;
     char **argv;
{
  struct sockaddr_in from;
  ZNotice_t notice;
  ZSubscription_t sub;
  int err, fd;
  struct itimerval value;

  openlog("er-joke-responder", 0, FACILITY);
  syslog(LOG_DEBUG, "starting");

  switch (argc) {
  case 1:
    strcpy(er_class, DEF_ER_CLASS);
    strcpy(er_instance, DEF_ER_INSTANCE);
    break;
  case 3:
    strcpy(er_class, argv[1]);
    strcpy(er_instance, argv[2]);
    break;
  default:
    fprintf(stderr, "usage: er [class instance]\n");
    exit(1);
  }
  if (err = fork()) {
    if (err = err < 0) 
      perror("fork");
    exit(err);
  }

  syslog(LOG_DEBUG, "Child starting");
  close(0);
  close(1);
  close(2);
  open("/", O_RDONLY);
  dup(0);
  dup(0);

  if ((fd = open("/dev/tty", O_RDWR)) > 0) {
    ioctl(fd, TIOCNOTTY, (char *)0);
    close(fd);
  }
  setpgrp(0, 0);
  
  value.it_value.tv_sec  = value.it_interval.tv_sec  = 20000;
  value.it_value.tv_usec = value.it_interval.tv_usec = 0;
/*  setitimer(ITIMER_REAL, &value, NULL); 
  signal(SIGALRM, kick_me); */

  kick_me();			/* Get kerberos tickets */

				/* Initialize zephyr */
  if (err = ZInitialize()) {	
    syslog(LOG_ERR,"ZInitialize: %d", err);
    exit(1);
  }
  syslog(LOG_DEBUG,"ZInitialize ok");
				/* Open zephyr port */
  if (err = ZOpenPort (&z_port)) {
    syslog(LOG_ERR, "ZOpenPort: %d", err);
    exit(1);
  }
  syslog(LOG_DEBUG,"ZOpenPort ok: fd = %d", z_port);
				/* Subscribe */
  sub.zsub_recipient = "*";
  sub.zsub_class = er_class;
  sub.zsub_classinst = er_instance;
  if (err = ZSubscribeToSansDefaults(&sub, 1, z_port)) {
    syslog(LOG_ERR, "ZSubscribeToSansDefaults: %d", err);
    exit(1);
  }
  syslog(LOG_DEBUG,"ZSubscribeToSansDefaults ok");
				/* Main loop. ... whee */
  while(1) {
    syslog(LOG_DEBUG, "waiting for notices");
    if (err = ZReceiveNotice (&notice, &from)) 
      syslog(LOG_WARNING, "ZReceiveNotice: %d", err);
    else {
      syslog(LOG_DEBUG, "got a notice class %s instance %s opcode %s sender %s recipient %s",
	     notice.z_class, notice.z_class_inst,
	     notice.z_opcode, notice.z_sender, notice.z_recipient);
      if (!strcasecmp(notice.z_class, er_class) &&
	  !strcasecmp(notice.z_class_inst, er_instance) &&
	  !strcasecmp(notice.z_opcode, "") && 
	  !strcasecmp(notice.z_recipient, ""))
	respond_to_message(&notice, &from);
      ZFreeNotice(&notice);	/* This doesn't return anything useful. */
    }
  }
}

char *choose_response()
{
  static char buf[BUFSIZ];
  FILE *fptr;
  long filesize,pos;
  char c, *retval;
  int ptr=0,nl=0,displ=0;

  retval = NULL;
  if((fptr=fopen(RESPONSES_FILE, "r"))== NULL)
    {
      syslog (LOG_ERR,"unable to open responses file");
      exit(1);
    }
  srandom(time(0));
  fseek(fptr,0L,2);
  filesize = ftell(fptr)-20;
  pos = random() % filesize;
  fseek(fptr,pos,0);
  fread(buf,1,sizeof(buf),fptr);
  while(displ < 2) {
    c = buf[ptr++];
    if(c=='\n') {
      if(++nl == 2) {
	nl = 0;
	if (++displ == 1) 
	  retval = buf + ptr;
	else
	  buf[ptr] = 0;
      }
    }
    if(ptr>=BUFSIZ) {
      syslog(LOG_WARNING, "bad response in responses file");
      return NULL;
    }
  }
  fclose(fptr);
  return retval;
}

respond_to_message(notice, from)
     ZNotice_t *notice;
     struct sockaddr_in *from;
{
  ZNotice_t response;
  int err;
  char *c;
  
  c = notice->z_message + notice->z_message_len - 2;
  while (c > notice->z_message && (isspace(*c))) c--;
  if (strncmp(c-2, "...", 3)) {
    syslog(LOG_DEBUG, "matching message has no ellipses");
    return;
  }
  syslog(LOG_DEBUG, "received matching message");
  bzero(&response, sizeof(response));
  do {}
  while ( (response.z_message = choose_response()) == NULL );
  response.z_class = er_class;
  response.z_class_inst = er_instance;
  response.z_recipient = "";
  response.z_opcode = "";
  response.z_sender = "er-joke responder";
  response.z_message_len = strlen(response.z_message) + 1;
  response.z_kind = UNACKED;
  response.z_port = 0;
  response.z_default_format = "@bold(UNAUTHENTIC) Class $class, Instance $instance at $time $date:\n$message";
  if (err = ZSendNotice(&response, ZNOAUTH)) 
    syslog(LOG_WARNING, "ZSendNotice: %d", err);
  else
    syslog(LOG_INFO, "I sent a message!");
}

kick_me ()
{
  char instance[INST_SZ];

  syslog(LOG_NOTICE, "getting kerberos tickets");

  setenv ("KRBTKFILE","/tmp/er-joke-receiver.tickets", 1);
  strcpy(instance,"salamander");
  if (krb_get_svc_in_tkt ("rcmd",instance,"ATHENA.MIT.EDU",
			  "krbtgt","ATHENA.MIT.EDU",1,"/etc/srvtab") < 0) {
    syslog (LOG_ERR, "Failed to get kerberos tickets");
    exit(1);
  }
  syslog(LOG_DEBUG,"got tickets");
}


