#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include "Connect.h"
#include "inet-udp.h"
#include "Code.h"
#include "literal.h"
#include "machdefs.h"
#include "slw.h"

char pname[100];

void printError(die)
     int die;
{
  int fatal = 0;

  while (Error_Exists)
    {
#ifdef DEBUG
      if (1)
#else
      if (Error_Severity == S_FATAL)
#endif
	{
	  fprintf(stderr, "%s: ", pname);
	  fprintf(stderr, Error_String(Error), Error_Info);
	  fputc('\n', stderr);
	}
      if (Error_Severity == S_FATAL)
	fatal++;
      Error_Pop();
    }

  if (fatal && die)
    exit(1);
}

#define E(x) if (x) printError(1)
#define ED(x) if (x) printError(0)

main(argc, argv)
     char **argv;
{
  Addr local;
  char *message;
  int i;
  Packet req, repl;
  CodeBlock *request, *reply;
  char name[50];
  char from[50];
  char *program, *version, *vendor, *restriction, *path, *wrapped;
  struct timeval t;
  Card16 ptype;
  char *keyptr;
  int keysize;
  int fd_in, fd_out;

  /*
   * Random initialization
   */
  sprintf(pname, "%s", argv[0]);

  if (argc != 7)
    {
      fprintf(stderr,
	  "usage: %s program version vendor restriction executable wrapped\n",
	      pname);
      exit(1);
    }

  program = argv[1];
  version = argv[2];
  vendor = argv[3];
  restriction = argv[4];
  path = argv[5];
  wrapped = argv[6];

  E(Connect_Initialize());
  E(Connect_RegisterDomain(&inetudp));

  E(Code_Initialize());
  E(Code_RegisterDomain(&literal));

  sprintf(from, "%s:.", PORTDOMAIN);
  E(Connect_NameToAddress(from, &local));

  /*
   * Create the request packet we want to send.
   */
  gettimeofday(&t, NULL);

  E(Code_CreateBlock(&request, CODEDOMAIN, NULL, 0));
  E(Code_PutCard16(request, PROTOVERSION0));	/* protocol version */
  E(Code_PutCard16(request, REQUEST_REGISTRATION));	/* request type */

  E(Code_PutString(request, SYSTEM));		/* key identifier */
  E(Code_PutString(request, program));
  E(Code_PutString(request, version));
  E(Code_PutString(request, vendor));
  E(Code_PutString(request, restriction));	/* also restriction type */

  E(Code_PutString(request, path));		/* so we can find it */
  E(Code_PutCard32(request, t.tv_sec));		/* partial key generator */

  req.Source = local;
  req.packet = Code_BlockData(request);
  req.length = Code_BlockLength(request);

  if (askQuestionOfServer(&req, &repl))
    {
      fprintf(stderr, "%s: Could not contact any servers.\n", pname);
      exit(1);
    }

  E(Code_CreateBlock(&reply, CODEDOMAIN, repl.packet, repl.length));
#ifdef DEBUG
  Connect_AddressToName(repl.Source, name, sizeof(name));
  fprintf(stdout, "From: %d - %s\n", repl.Source, name);
  fprintf(stdout, "length: %d\n", repl.length);
#endif
  E(Code_GetCard16(reply, &ptype));
#ifdef DEBUG
  fprintf(stdout, "type: %d\n", ptype);
#endif
  switch(ptype)
    {
    case REPLY_REGISTRATION:
      E(Code_GetMemory(reply, &keyptr, &keysize));
      if (keysize != 8)
	fprintf(stderr, "keysize = %d\n");
      else
	{
#ifdef DEBUG
	  for (i = 0; i < 8; i++)
	    fprintf(stdout, "%02x", keyptr[i]&0xff);
	  fputc('\n', stdout);
#endif
	  decrypt_key(keyptr, t.tv_sec);
#ifdef DEBUG
	  for (i = 0; i < 8; i++)
	    fprintf(stdout, "%02x", keyptr[i]&0xff);
	  fputc('\n', stdout);
#endif
	}
      break;

    default:
      fprintf(stderr, "ptype = %d\n", ptype);
      exit(1);
      break;
    }

  fd_in = open(path, O_RDONLY);
  if (fd_in == -1)
    {
      fprintf(stderr, "%s: unable to open %s\n", pname, path);
      exit(2);
    }

  fd_out = open(wrapped, O_WRONLY | O_CREAT, 0666);
  if (fd_out == -1)
    {
      fprintf(stderr, "%s: unable to open %s\n", pname, wrapped);
      exit(3);
    }

  if (copy_crypt_file(pname, fd_in, fd_out, keyptr, 1))
    exit(4);

  if (close(fd_out))
    {
      fprintf(stderr, "%s: error %d closing %s\n", pname, errno, wrapped);
      exit(5);
    }

  E(Code_FreeBlock(reply));
  fprintf(stdout, "Done.\n");
  exit(0);
}
