/* This file is part of the Project Athena Zephyr Notification System.
 * It contains functions for the windowgram COMPILER interface to Zephyr.
 *
 *	Created by:	Mark W Eichin
 *
 *	$Source: /mit/zephyr/src/zwgc/RCS/inter_zep.c,v $
 *	$Author: jtkohl $
 *
 *	Copyright (c) 1987 by the Massachusetts Institute of Technology.
 *	For copying and distribution information, see the file
 *	"mit-copyright.h". 
 */

#include <zephyr/mit-copyright.h>

#ifndef lint
static char rcsid_inter_zep_c[] = "$Header: inter_zep.c,v 2.6 89/05/30 11:24:36 jtkohl Exp $";
#endif lint

#include <zephyr/zephyr.h>
#include "comp_types.h"
#include "ropes.h"
#include "string.h"

#include <netdb.h>		/* for $FROMHOST to keep probe, tytso happy */
#include <sys/socket.h>		/* for AF_INET */

char *index();
char *malloc();
#define CPY(s) strcpy(malloc(strlen(s)+1),s)
extern int ttymode;

init_headers(note)
     ZNotice_t note;
{
  char *zscan, *nwmsg, *timestmp, *timescan;
  char pnum[128];
#define IN_HEAD(x) strand_head[((int)x)]
#define INIT_HEAD(x,y) IN_HEAD(x) = CPY(note.y)

  /* Port number */
  sprintf(pnum, "%d", note.z_port);
  IN_HEAD(HEAD_PORT) = CPY(pnum);
  IN_HEAD(HEAD_MODE) = CPY(ttymode ? "tty" : "window");	/* CPY? constants? */

  /* Do the easy ones right out here... */
  INIT_HEAD(HEAD_CLASS,z_class);
  INIT_HEAD(HEAD_INSTANCE,z_class_inst);
  INIT_HEAD(HEAD_OPCODE,z_opcode);
  INIT_HEAD(HEAD_FULL_SENDER,z_sender);
  INIT_HEAD(HEAD_RECIPIENT,z_recipient);


  /* make a short name with no realm... */
  zscan = index(note.z_sender, '@');
  if(zscan)
    {
      if(!strcmp(zscan+1,ZGetRealm()))
	{
	  /* sender IS in the current realm, so... */
	  *zscan = '\0';
	}
    }
  INIT_HEAD(HEAD_SENDER,z_sender);

  {
    struct hostent *hst = gethostbyaddr((char *)&note.z_sender_addr,
					sizeof(note.z_sender_addr), AF_INET);
    if(hst)
      {
	IN_HEAD(HEAD_FROMHOST) = CPY(hst->h_name);
      }
    else
      {
	IN_HEAD(HEAD_FROMHOST) = CPY(inet_ntoa(note.z_sender_addr));
      }
  }
  
  /* Now we scan the entire message body. Possibly check for deathgrams. */
  nwmsg = malloc(note.z_message_len+1);
  bcopy(note.z_message, nwmsg , note.z_message_len);
  nwmsg[note.z_message_len] = '\0';
  for(zscan = &nwmsg[note.z_message_len-2]; zscan >= nwmsg; zscan--)
    { /* delete all nulls, not last (real or added), backwards */
      if(*zscan == '\0')
	{
	  *zscan = '\n';
	}
    }

  IN_HEAD(HEAD_MESSAGE) = nwmsg;

  /* Set the KIND enumeration. */
  switch(note.z_kind)
    {
    case UNSAFE:
      IN_HEAD(HEAD_KIND) = CPY("unsafe");
      break;
    case UNACKED:
      IN_HEAD(HEAD_KIND) = CPY("unacked");
      break;
    case ACKED:
      IN_HEAD(HEAD_KIND) = CPY("acked");
      break;
    case HMACK:
      IN_HEAD(HEAD_KIND) = CPY("hmack");
      break;
    case HMCTL:
      IN_HEAD(HEAD_KIND) = CPY("hmctl");
      break;
    case SERVACK:
      IN_HEAD(HEAD_KIND) = CPY("servack");
      break;
    case SERVNAK:
      IN_HEAD(HEAD_KIND) = CPY("servnak");
      break;
    case CLIENTACK:
      IN_HEAD(HEAD_KIND) = CPY("clientack");
      break;
    case STAT:
      IN_HEAD(HEAD_KIND) = CPY("stat");
      break;
    default:
      IN_HEAD(HEAD_KIND) = CPY("BAD KIND FIELD");
      break;
    }

  /* Check auth field here... */
  switch(note.z_auth)
    {
    case ZAUTH_YES:
      IN_HEAD(HEAD_AUTH) = CPY("Yes");
      break;
    case ZAUTH_NO:
      IN_HEAD(HEAD_AUTH) = CPY("No");
      break;
    case ZAUTH_FAILED:
      IN_HEAD(HEAD_AUTH) = CPY("Forged");
      break;
    default:
      IN_HEAD(HEAD_AUTH) = CPY("UNKNOWN");
      break;
    }

  /* Create timestamp string, split into time and date */
  /* change "Tue Feb 07 15:34:55 1967" to 15:34:55, Tue Feb 07 1967 */
  /*         0000000000111111111122222 */
  /*         0123456789012345678901234 */
  timestmp = ctime(&note.z_time.tv_sec);
  timestmp[24] = '\0';		/* based on man page, gunch newline */
  timestmp[10] = '\0';		/* split it? pray for fixed format... */
  timestmp[19] = '\0';		/* again, pre date... */
  IN_HEAD(HEAD_TIME) = CPY(&timestmp[11]);
  /* remember, sizeof("xy") is 3 since it includes the null... */
  timescan = IN_HEAD(HEAD_DATE) = malloc(sizeof("Tue Feb 07 1967"));
  bcopy(&timestmp[0],  &timescan[0], 10); /* "Tue Feb 07" */
  timescan[10] = ' ';		/* blank for readability... */
  bcopy(&timestmp[20], &timescan[11], 5); /* "1967\0" */

  create_default(note.z_default_format);

  strand_head_max = ((int)HEAD_lasthead)-1;

  zap_trailing_newlines(strand_head_max,strand_head);
}

#define CPYn(s,n) strncpy(malloc(n+1),s,n+1)

init_fields(mess,ln)
     char *mess;		/* message body */
     int ln;
{
  int in=0, ct=0;

  while(in < ln)
    {
      /* This is a bit messy, so that we don't try to copy
       * way beyond the end of the z_message. It would be cleaner
       * as a while loop here, I think...
       */
      strand_field[ct] = CPYn(&mess[in], min(strlen(&mess[in]), ln - in));
      strand_field[ct][min(strlen(&mess[in]), ln - in)] = '\0';
      in += strlen(&mess[in]) + 1;
      ct++;
    }
  strand_field_max = ct;
  zap_trailing_newlines(strand_field_max,strand_field);
}

clear_strand(strand,strand_max)
     char *strand[];
     int strand_max;
{
  int i;
  for(i=0; i <= strand_max; i++)
    {
      if(strand[i]) 
	{
	  free(strand[i]);
	  strand[i] = NULL;
	}
    }
}

clear_ropes(ropes,strand_max)
     rope *ropes[];
     int strand_max;
{
  int i;
  for(i=0; i <= strand_max; i++)
    {
      if(ropes[i])
	{
	  ropfree(ropes[i]);
	  ropes[i] = NULL;
	}
    }
}


rope *cmdbuff;
create_default(str)
     char *str;
{
  char *ss;
  char **s;
  rope rb, tokenize_raw(), tokenize_variable(), *parse_show(), *parselit_raw();
  rope *arg_ro;

  if(cmdbuff)
    {
      ropfree(cmdbuff);
      cmdbuff = NULL;
    }
  
  ss = str;
  s = &ss;

  if(sanitize(s))
    {
      str = "";			/* make this a valid BLANK string... */
    }

  cmdbuff = ropinit(ROPE_SIZE);
  rb.typ = COMMAND;
  rb.ind.ex = (int)CMD_SET;
  ropappend(cmdbuff, rb, ROPE_SIZE);

  {				/* create dest + arg */
    
    arg_ro = ropinit(ROPE_SIZE);

    rb = tokenize_variable("default", sizeof("default")-1);
    ropappend(arg_ro, rb, ROPE_SIZE);
    
    ss = str;
    s = &ss;
    rb.typ = ROPE;
    rb.ind.next = parse_show(s);
    ropappend(arg_ro, rb, ROPE_SIZE);
  }

  rb.typ = ROPE;
  rb.ind.next = arg_ro;
  ropappend(cmdbuff, rb, ROPE_SIZE);
  

  new_eval(cmdbuff,0);

  return;
}

sanitize(s)
     char **s;
{
  if ( (!(*s)) || (! (**s)) )
    {
      return(!0);
    }
  else
    {
      while(**s)
	{
	  if(is_blank(**s)) **s = ' ';
	  if(is_newline(**s)) **s = '\n';
	  if(!is_char(**s))
	    {
	      printf("zwgc:inter_zep Non ASCII char found, punting string (%03o@%d)\n",
		     **s, *s);
	      return(!0);
	    }
	  ++*s;
	}
      return(0);
    }
}

/*
 * This simple routine deletes any SINGLE trailing newlines from headers,
 * since they are PROBABLY extraneous. If you want them, put in two, 
 * they're small...
 */

zap_trailing_newlines(maxlen,arr)
     int maxlen;
     char *arr[];
{
  int i, j;
  for(i=0; i<=maxlen; i++)
    {
      if(arr[i] && strlen(arr[i]))
	{
	  j = strlen(arr[i])-1;
	  if(arr[i][j] == '\n')
	    arr[i][j] = '\0';
	}
    }
}
