#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#include "gpg.h"

extern int sd1[2];
extern int spawn_job (char *path, char *argv[], 
		      int *in_fd, int *out_fd, int *err_fd);
extern time_t nfslock(char *path, char *namelock, int max_age, int notify);
extern int nfsunlock(char *path, char *namelock, int max_age, time_t birth);

void ParseInputFile(struct VerifySignObject *vSO) {
  FILE *fin, *fout;
  char txt[LINE_LENGTH];
  char keyRing[LINE_LENGTH];
  char outputPath[LINE_LENGTH];
  const char PGP_prefix[] = "-----BEGIN PGP ";
  const char PGP_suffix[] = "-----END PGP ";
  int found_prefix = 0, nMsgs = 0, outFileOpened = 0, clearTextBlock = 1;
  char foutName[100];
  struct VerifySignObject *vSOList = vSO;
  
  strcpy(keyRing, vSO->keyRing);
  strcpy(outputPath, vSO->outputPath);

  if (!strcmp(vSOList->iSigFilename, "")) {
    if ((fin = fopen(vSOList->iDocSigFilename, "r")) != NULL) { 

      while (fgets (txt, LINE_LENGTH - 1, fin) != NULL) {

      /* Looking for PGP prefix */
	if ((strstr(txt, PGP_prefix) != NULL) && !found_prefix) {
	  clearTextBlock = 0;
	  found_prefix = 1;
	  /* remember to delete those files */
	  sprintf(foutName, "/tmp/PAtmp.%d.%d", (int)getpid(), nMsgs);
	  if ((fout = fopen(foutName, "w")) == NULL ) {
	    vSOList->isValid = vSO_NO_OUT_FILES;
	    return;
	  }
	  outFileOpened = 1;
	  vSOList->next = malloc(sizeof(struct VerifySignObject));
	  vSOList = vSOList->next;
	  strcpy(vSOList->iDocSigFilename, foutName);
	  strcpy(vSOList->keyRing, keyRing);
	  strcpy(vSOList->outputPath, outputPath);
	  vSOList->next = NULL;
	} else
	  if ((strstr(txt, PGP_suffix) != NULL ) && found_prefix) {
	    found_prefix = 0;
	    clearTextBlock = 1;
	    fputs(txt, fout);
	    fclose(fout);
	    outFileOpened = 0;
	    nMsgs++;
	  } else 
	    if (clearTextBlock && !outFileOpened) {
	      sprintf(foutName, "/tmp/PAtmp.%d.%d", (int)getpid(), nMsgs);
	      if ((fout = fopen(foutName, "w")) == NULL ) {
		vSOList->isValid = vSO_NO_OUT_FILES;
		return;
	      }
	      outFileOpened = 1;
	      vSOList->next = malloc(sizeof(struct VerifySignObject));
	      vSOList = vSOList->next;
	      strcpy(vSOList->iDocSigFilename, foutName);
	      strcpy(vSOList->keyRing, keyRing);
	      strcpy(vSOList->outputPath, outputPath);
	      vSOList->next = NULL;
	    }
	if (outFileOpened) {
	  fputs(txt, fout);
	}       
      }
      if (outFileOpened) {
	fclose(fout);
      }
      fclose(fin);
    } else {
      vSOList->isValid = vSO_NO_IN_FILES;
    }
  }
}

void VerifySignature(struct VerifySignObject *vSO) {
  char *strArgs[10];
  char Args0[100];
  char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
    Args6[100], Args7[100];
  int gpg_pid;
  int gpg_in_fd, out_fd, err_fd;
  int status;
  static int nMsgs = 0;
  char txt[LINE_LENGTH];
  char *keyStr;
  struct VerifySignObject *pvSO = vSO->next, *ptmp;

  while (pvSO != NULL) {
    nMsgs++;
    /* Copy the incoming object on the internal global object */
    /* memmove( &verifySignObj, pvSO, sizeof(struct VerifySignObject) ); */

    sprintf(pvSO->oStream, "%s/PAtmp.%ld.%ld.%d", pvSO->outputPath, 
	    labs(gethostid()), getpid(), nMsgs);

    strcpy(Args0, "--no-secmem-warning");
    strcpy(Args1, "--keyring");
    strcpy(Args2, pvSO->keyRing);
    strcpy(Args3, "-o");
    strcpy(Args4, pvSO->oStream);
    strcpy(Args5, "-d");
    if (!strcmp(pvSO->iSigFilename, "")) {
      strcpy(Args6, pvSO->iDocSigFilename);
      strArgs[6] = Args6;
      strArgs[7] = (char *)0;
    } else {
      strcpy(Args6, pvSO->iSigFilename);
      strcpy(Args7, pvSO->iDocSigFilename);
      strArgs[6] = Args6;
      strArgs[7] = Args7;
      strArgs[8] = (char *)0;
    }

    strArgs[0] = Args0;
    strArgs[1] = Args1;  
    strArgs[2] = Args2;  
    strArgs[3] = Args3;
    strArgs[4] = Args4;
    strArgs[5] = Args5;
  
    gpg_in_fd = INPUT_FD;
    out_fd = OUTPUT_FD;
    err_fd = ERROR_FD;
    if ( ( gpg_pid = spawn_job ("gpg", strArgs,
				&gpg_in_fd, &out_fd, &err_fd) ) < 0 )
      {
	printf ("could not spawn gpg");
      }
  
    if (waitpid (gpg_pid, &status, 0) < 0)
      {
	fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
	printf ("could not reap gpg process");
      }
    if (WIFEXITED(status) == 0)
      {
	fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
	printf ("gpg failure\n");
      }


    /* Parsing gpg output */
    pvSO->isValid = vSO_KO;
    while (fgets (txt, LINE_LENGTH - 1, stdin) != NULL)
      {
	/* 	printf ( "GPG output : %s\n", txt );  */
	if (strstr(txt, "Good signature") != NULL)
	  pvSO->isValid = vSO_IS_VALID;

	if (strstr(txt, "CRC error") != NULL)
	  pvSO->isValid = vSO_CRC_ERROR;

	if (strstr(txt, "public key not found") != NULL)
	  pvSO->isValid = vSO_NO_PUBLIC_KEY;

	if (strstr(txt, "no valid OpenPGP data found") != NULL)
	  pvSO->isValid = vSO_NO_OPENPGP_DATA;

	if ((keyStr = strstr(txt, "key ID")) != NULL) {
	  keyStr += 7;
	  sscanf(keyStr, "%8X\n", &pvSO->keyID);
	}
      }
    
    unlink(pvSO->iDocSigFilename);
    pvSO = pvSO->next;
  }
  if (sd1[0] != 0)  close ( sd1[0] ); 
}


/* ------------------------------------------------- */
void PA_VerifySignature(struct VerifySignObject *vSO) {
  
  /* split input file if there are multiple signed messages */
  ParseInputFile( vSO );

  /* Verify each single PGP mesg */
  VerifySignature( vSO );

}

/* ------------------------------------------------- */
void PA_Decrypt(struct ReadCryptedObject *rDO) {
  
  char *strArgs[9];
  char clearTextExtension[4] = ".gpg";
  char Args0[100] = "abracadabra";
  char Args1[100];
  char Args2[100];
  char Args3[100];
  char Args4[100];
  char Args5[100];
  char Args6[100];
  int gpg_pid;
  int gpg_in_fd, out_fd, err_fd;
  int status;
  char txt[LINE_LENGTH];


  strcpy(Args0, "--no-tty");
  strcpy(Args1, "--no-secmem-warning");
  strcpy(Args2, "--keyring");
  strcpy(Args3, rDO->keyRing);
  strcpy(Args4, "--output");
  strcpy(Args5, strcat(rDO->iFilename, clearTextExtension));
  strcpy(Args6, rDO->iFilename);
  
  strArgs[0] = Args0;
  strArgs[1] = Args1;  
  strArgs[2] = Args2;  
  strArgs[3] = Args3;  
  strArgs[4] = Args4;  
  strArgs[5] = Args5;  
  strArgs[6] = Args6;  
  strArgs[7] = (char *) 0;   

  gpg_in_fd = INPUT_FD;
  out_fd = OUTPUT_FD;
  err_fd = ERROR_FD;
  if ( ( gpg_pid = spawn_job ("gpg", strArgs,
			      &gpg_in_fd, &out_fd, &err_fd) ) < 0 )
    {
      printf ("could not spawn gpg");
    }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      printf ("could not reap gpg process");
    }
  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
    }


  /* Parsing gpg output */
  while (fgets (txt, STRING_LENGTH - 1, stdin) != NULL)
    {
      
    }
  
  if (sd1[0] != 0)  close ( sd1[0] ); 
}


/* ------------------------------------------------- */
void PA_ImportKey(struct ImportKeyObject *iKO) {
  
  char *strArgs[9];
  char Args0[100] = "abracadabra";
  char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100];
  int gpg_pid;
  int gpg_in_fd, out_fd, err_fd;
  int status;
  char txt[LINE_LENGTH];
  char *keyStr, *pos;
  const char lockFilename[] = ".PAlock";
  char keyRingLockFile[1000], keyRingPath[1000];
  time_t lockBirthDate;
  FILE *mystdin;

  iKO->rc = iKO_GENERALFAILURE;

  strcpy(Args0, "--no-tty");
  strcpy(Args1, "--no-secmem-warning");
  strcpy(Args2, "--keyring");
  strcpy(Args3, iKO->keyRing);
  strcpy(Args4, "--import");
  strcpy(Args5, iKO->iFilename);

  strArgs[0] = Args0;  
  strArgs[1] = Args1;  
  strArgs[2] = Args2;  
  strArgs[3] = Args3;  
  strArgs[4] = Args4;  
  strArgs[5] = Args5;
  strArgs[6] = (char *)0;

  gpg_in_fd = INPUT_FD;
  out_fd = OUTPUT_FD;
  err_fd = ERROR_FD;

  /* create lock file filenames for NFS */

  strcpy(keyRingLockFile, iKO->keyRing);
  if ((pos = strrchr(keyRingLockFile, '/')) != NULL) {
    strcpy(pos + 1, lockFilename);
    strcpy(keyRingPath, keyRingLockFile);
    keyRingPath[pos - keyRingLockFile] = 0;
  } else {
    strcpy(keyRingLockFile, lockFilename);
    strcpy(keyRingPath, "");
  }
  
  lockBirthDate = nfslock(keyRingPath, (char*)lockFilename, 0, 0);

  if ( ( gpg_pid = spawn_job ("gpg", strArgs,
			      &gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
    printf ("could not spawn gpg");
  }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      printf ("could not reap gpg process");
    }

  nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);

  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
    }


  /* Parsing gpg output */
  /*   while (read(0, txt, 1000) != 0)
       fprintf(stderr, "child read %s\n", txt); */

  mystdin = fdopen(0, "r");
  iKO->rc = iKO_GENERALFAILURE;
  while (fgets (txt, LINE_LENGTH - 1, mystdin) != NULL)
    {
          printf ( "GPG output : %s\n", txt );     

      if ((keyStr = strstr(txt, "imported")) != NULL) {
	iKO->rc = iKO_OK;
      }

      if ((keyStr = strstr(txt, "CRC error")) != NULL) {
	iKO->rc = iKO_CRC_ERROR;
      }

      if ((keyStr = strstr(txt, "no valid OpenPGP")) != NULL) {
	iKO->rc = iKO_NO_OPENPGP_DATA;
      }

      if ((keyStr = strstr(txt, "unchanged")) != NULL) {
	iKO->rc = iKO_UNCHANGED;
      }

      if ((keyStr = strstr(txt, "key")) != NULL) {
	 keyStr += 4;
	 sscanf(keyStr, "%8X\n", &iKO->keyID); 
      } 
    }

  if (sd1[0] != 0)  close ( sd1[0] ); 
}


