/***************************************
  $Revision: 1.21 $

  gpg.c - core of the PA module. Contains functions that are used
  to check the PGP authentication in a message.

  Status: COMPLETE, REVUED, TESTED

  ******************/ /******************
  Filename            : gpg.c
  Authors             : filippo@ripe.net
  OSs Tested          : Solaris 7
  ******************/ /******************
  Copyright (c) 2000                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  ***************************************/



#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 <signal.h>
#include <sys/time.h>
#include <sys/param.h>

#include "mm.h" 
/*#include "misc.h"*/   /* isMIME functions need case insensitive string search()*/
#include "gpg.h"
#include "erroutines.h"

extern char EP_outputPrefix[FILENAME_LENGTH];
extern char EP_keyRing[FILENAME_LENGTH];
extern int  EP_TreeHeight;
extern int  EP_Node_ID;
extern int  EP_Debug;

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);


/* static int parseMailBlock_nMsg;
   static int parseRecursionLevel; */

/* ------------------------------------------------- */

void GetFingerPrint(struct ImportKeyObject *iKO) {
  
  char *strArgs[9];
  char Args0[100] ;
  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;
  FILE *mystdin;
  int childRC;

  strcpy(Args0, "--no-tty");
  strcpy(Args1, "--no-secmem-warning");
  strcpy(Args2, "--keyring");
  strcpy(Args3, iKO->keyRing);
  strcpy(Args4, "--fingerprint");
  sprintf(Args5, "%08lX", iKO->keyID);

  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 */

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

  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
      exit(1);
    } else {
      /* Child exited, checking return code */
      childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
      }
    }


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

      if ((keyStr = strstr(txt, "Key fingerprint =")) != NULL) {
	strcpy(iKO->fingerPrint, keyStr + 18);
	iKO->fingerPrint[strlen(iKO->fingerPrint)-1] = 0;
      }

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

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

/* ------------------------------------------------- */

void VerifySignAndExplodeFile(EPNodePtr ptr) {
  char *strArgs[10];
  char Args0[100];
  char Args1[100], Args2[100], Args3[100], Args4[100], Args5[100],
    Args6[100];
  int gpg_pid;
  int gpg_in_fd, out_fd, err_fd;
  int status;
  char txt[LINE_LENGTH];
  /* char hostname[MAXHOSTNAMELEN]; */
  char oFile[FILENAME_LENGTH];
  char *keyStr;
  /* int childRC; */

  sprintf(oFile, "%s.%d.exp", ptr->file, ptr->nodeID);

  strcpy(Args0, "--no-secmem-warning");
  strcpy(Args1, "--keyring");
  strcpy(Args2, EP_keyRing);
  strcpy(Args3, "-o");
  strcpy(Args4, oFile);
  strcpy(Args5, "-d");
  strcpy(Args6, ptr->file);
  strArgs[6] = Args6;
  strArgs[7] = (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");
      exit(1);
    }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      printf ("could not reap gpg process");
      exit(1);
    }
  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure\n");
      exit(1);
    } else {
      /* Child exited, checking return code */
      /* childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
	} */
    }


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

      if (strstr(txt, "CRC error") != NULL)
	ptr->isValidPGPSignature = vS_CRC_ERROR;

      if (strstr(txt, "public key not found") != NULL)
	ptr->isValidPGPSignature = vS_NO_PUBLIC_KEY;

      if (strstr(txt, "no valid OpenPGP data found") != NULL)
	ptr->isValidPGPSignature = vS_NO_OPENPGP_DATA;

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

/* ------------------------------------------------- */

void PA_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;
  /* int childRC; */

  vSO->type = vSO_Type_Signed;

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

  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");
      exit(1);
    }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      printf ("could not reap gpg process");
      exit(1);
    }
  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure\n");
      exit(1);
    } else {
      /* Child exited, checking return code */
      /* childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
	} */
    }


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

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

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

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

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

/* ------------------------------------------------- */
/* This functions is not used by PA/EP/MM
   can be useful in the future ....  FP              */
void PA_Decrypt(struct ReadCryptedObject *rDO) {
  
  char *strArgs[9];
  char clearTextExtension[4] = ".gpg";
  char Args0[100];
  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];
  int childRC;

  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");
      exit(1);
    }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      printf ("could not reap gpg process");
      exit(1);
    }
  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
      exit(1);
    } else {
      /* Child exited, checking return code */
      childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
      } 
    }


  /* 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];
  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;
  int childRC;

  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");
    exit(1);
  }
  
  if (waitpid (gpg_pid, &status, 0) < 0)
    {
      fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
      nfsunlock(keyRingPath, (char*)lockFilename, 0, lockBirthDate);
      printf ("could not reap gpg process");
      exit(1);
    }

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

  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
    } else {
      /* Child exited, checking return code */
      childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
      }
    }


  /* 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) || 
	  ((keyStr = strstr(txt, "not changed")) != 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] ); 

  /* Get the finger print */

  GetFingerPrint(iKO);
}

/* ------------------------------------------------- */

void GetKeyID(struct ImportKeyObject *iKO) {
  
  char *strArgs[9];
  char Args0[100];
  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;
  int childRC;

  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");
    exit(1);
  }
  
  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);
      exit(1);
    }

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

  if (WIFEXITED(status) == 0)
    {
      fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
      printf ("gpg failure");
      exit(1);
    } else {
      /* Child exited, checking return code */
      childRC = (status & 0xF00) >> 8;
      if (childRC == 1) {
	fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	printf ("gpg failure\n");
	exit(1);
      }
    }


  /* 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) || 
	  ((keyStr = strstr(txt, "not changed")) != NULL)) {
	iKO->rc = iKO_UNCHANGED;
      }

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

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

}

/* ------------------------------------------------- */

void PA_RemoveKey(struct ImportKeyObject *iKO) {
  
  char *strArgs[9];
  char Args0[100]= "gpg";
  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;
  char txt[LINE_LENGTH];
  char *keyStr, *pos;
  const char lockFilename[] = ".PAlock";
  char keyRingLockFile[1000], keyRingPath[1000];
  time_t lockBirthDate;
  FILE *mystdin;
  int childRC;

  iKO->rc = iKO_GENERALFAILURE;

  GetKeyID(iKO);   /* getting key-id */

  /*   printf("Key id = %08lX\n", iKO->keyID); */

  if ((iKO->rc == iKO_OK) || (iKO->rc == iKO_UNCHANGED)) {    
    strcpy(Args1, "--batch");
    strcpy(Args2, "--yes");
    strcpy(Args3, "--no-secmem-warning");
    strcpy(Args4, "--keyring");
    strcpy(Args5, iKO->keyRing); 
    strcpy(Args6, "--delete-key");
    sprintf(Args7, "%08lX", iKO->keyID);

    strArgs[0] = Args0;  
    strArgs[1] = Args1;  
    strArgs[2] = Args2;  
    strArgs[3] = Args3;  
    strArgs[4] = Args4;  
    strArgs[5] = Args5;
    strArgs[6] = Args6;
    strArgs[7] = Args7;
    strArgs[8] = (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 ("/usr/local/bin/gpg", strArgs,
				&gpg_in_fd, &out_fd, &err_fd) ) < 0 ) {
      printf ("could not spawn gpg");
      exit(1);
    }

    /*    printf("Child pid = %d\n", gpg_pid); */
  
    if (waitpid (gpg_pid, &status, 0) < 0)
      {
	fprintf (stderr, "Error reaping child\t%s\n", ERRSTRING);
	printf ("could not reap gpg process");
	exit(1);
      }

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

    if (WIFEXITED(status) == 0)
      {
	fprintf (stderr, "Bad child status: %d\t%s\n", status, ERRSTRING);
	printf ("gpg failure");
	exit(1);
      }  else {
	/* Child exited, checking return code */
	childRC = (status & 0xF00) >> 8;
	if (childRC == 1) {
	  fprintf (stderr, "Fatal: gpg child return code: %d\n", childRC);
	  printf ("gpg failure\n");
	  exit(1);
	}
      }


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

	if ((keyStr = strstr(txt, "delete key failed")) != NULL) {
	  iKO->rc = iKO_GENERALFAILURE;
	}
	if ((keyStr = strstr(txt, "there is a secret key for this public key")) != NULL) {
	  iKO->rc = iKO_SECRET_KEY_PRESENT;
	}

      }

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

/* ------------------------------------------------- */


/* Get the next file line of an arbitrary length */

#define BUFSIZE 1024

char * GetLineFromFile3(FILE *fin) {
  int i;
  char buffer;
  static char line[BUFSIZE + 1];
  char *p = NULL;
  int p_size = BUFSIZE, eol = 0;

  i = 0;
  while (!eol && fread((void*) &buffer, 1, 1, fin)) {
    if (i < BUFSIZE ) {
      line[i] = buffer;
    } else
      if (i == BUFSIZE ) {
	
      } else
      if (i % BUFSIZE == 0) {
      p = realloc(p, p_size+BUFSIZE + 1);
      memcpy(p+p_size, line, BUFSIZE);
      p_size += BUFSIZE;
      p[i] = buffer;
    }
    i++;
    if (buffer  == '\n') eol = 1;
  }

  if (i == 0) return NULL;

  if (p != NULL) {
    p[i] = '\0';
    return p;
  } else {
    line[i] = '\0';
    return line;
  }
}

char * GetLineFromFile2(FILE *fin) {
  static char * p = NULL;
  static char buffer[BUFSIZE+1];
  static char line[BUFSIZE+1];
  static int eol_pos = -1, eof_pos = BUFSIZE+10;
  char *nl, *startStr;
  /* int i; */
  int strSize, nBytesRead;
  short eol = 0;

  
  buffer[BUFSIZE] = '\0';
  if (eol_pos == -1) {
    /* this occurs in the beginning of a file */
    nBytesRead = fread((void*) &buffer, 1, BUFSIZE, fin);
    if (nBytesRead < BUFSIZE) {
      eof_pos = nBytesRead;
    }
    
    startStr = buffer;
    nl = strchr(startStr, '\n');
    if ((nl != NULL) && (nl - startStr < nBytesRead)) {
      eol_pos = nl - startStr; 
      memcpy(line, startStr, eol_pos+1);
      line[eol_pos+1] = '\0';
      return line;
    } else 
      if ((nl == NULL) && (nl - startStr < nBytesRead)) {
	p = malloc(BUFSIZE);
	memcpy(p, buffer, BUFSIZE);
	strSize = BUFSIZE;
	while (!eol) {
	  nBytesRead = fread((void*) &buffer, 1, BUFSIZE, fin);
	  if (nBytesRead < BUFSIZE) {
	    eof_pos = nBytesRead;
	  }
	  startStr = buffer;
	  nl = strchr(startStr, '\n');
	  if ((nl == NULL) && (nl - startStr < nBytesRead)) {
	    p = realloc(p, strSize + BUFSIZE);
	    memcpy(p + strSize, buffer, BUFSIZE);
	    strSize +=  BUFSIZE;
	  } else
	    if ((nl != NULL) && (nl - startStr < nBytesRead)) {
	      p = realloc(p, strSize + (nl - startStr ));
	      memcpy(p + strSize, buffer, (nl - startStr + 1));
	      eol_pos = nl - buffer;
	      p[strSize + (nl - startStr )] = '\0';
	      return p;
	    } else {
	      p = realloc(p, strSize +  nBytesRead + 1);
	      memcpy(p + strSize, buffer, nBytesRead );
	      p[strSize + nBytesRead] = '\0';
	      return p;
	    }
	}
      } else {
	buffer[eof_pos]='\0';
	eol_pos = -1;
	return startStr;
      } 
  } else 
    if (eof_pos > eol_pos) { 
      startStr = buffer + eol_pos + 1;
      nl = strchr(startStr, '\n');
      if (nl == NULL) {
	strSize = BUFSIZE - (eol_pos + 1);
	if (p != NULL) free(p);
	p = malloc(strSize);
	memcpy(p, buffer + eol_pos + 1, strSize);
	
	/* Could not find '\n' on this block, proceed until find one */
	while (!eol) {
	  nBytesRead = fread((void*) &buffer, 1, BUFSIZE, fin);
	  if (nBytesRead < BUFSIZE) {
	    eof_pos = nBytesRead;
	  }
	  
	  startStr = buffer;
	  nl = strchr(startStr, '\n');
	  if ((nl == NULL) && (nl - startStr < nBytesRead)) {
	    p = realloc(p, strSize + BUFSIZE);
	    memcpy(p + strSize, buffer, BUFSIZE);
	    strSize +=  BUFSIZE;
	  } else 
	    if ((nl != NULL) && (nl - startStr < nBytesRead)) {
	      p = realloc(p, strSize + (nl - startStr ) + 1);
	      memcpy(p + strSize, buffer, (nl - startStr + 1));
	      eol_pos = nl - buffer;
	      p[strSize + (nl - startStr )] = '\0';
	      return p;
	    } else {
	      p = realloc(p, strSize + nBytesRead + 2);
	      memcpy(p + strSize, buffer, nBytesRead);
	      eol_pos = -1;
	      p[strSize + nBytesRead + 1] = '\0';
	      return p;
	    }
	}
      } else {
	if (p != NULL) free(p);
	eol_pos = nl - buffer; 
	memcpy(line, startStr, nl - startStr + 1);
	line[nl - startStr + 1] = '\0';
	return line;
      }
    } else { 
      /* EOF */
      eol_pos = -1;
      return NULL;
    }

  return NULL;

}

/* ------------------------------------------------- */
EPNodePtr PA_ParseMessage(EPNodePtr ptr) {

  /* Assumptions:
     - ptr is describing a text file, not MIME
     - input file is broken down to pieces, plain text or PGP blocks  
     - if input file is doesn't have any PGP block, this is a leaf
     - otherwise send each block to the proper handler.
  */

  FILE *fin, *fout;
  char txt[MAX_LINE_BUF], *strptr;
  /* char blockFilename[LINE_LENGTH]; */
  const char PGP_prefix_msg[] =       "-----BEGIN PGP MESSAGE";
  const char PGP_suffix_msg[] =       "-----END PGP MESSAGE";
  const char PGP_prefix_signed[] =    "-----BEGIN PGP SIGNED MESSAGE";
  const char PGP_suffix_signature[] = "-----END PGP SIGNATURE";
  int found_prefix = 0, found_suffix = 0;
  EPNodePtr p = ptr, prev = ptr;
  int end_of_fin = 0, text_block = 1;

  if ((fin = fopen(ptr->file, "r")) != NULL) { 

    do {
      /* this is needed because a text block parser ends when it finds
	 a PGP prefix, so we already have a txt buffer.   */ 
      
      if (!text_block || (prev == ptr)) {
	strptr = fgets(txt, MAX_LINE_BUF, fin);
	if (strptr == NULL ) end_of_fin = 1;
      }

      if (!end_of_fin && (found_prefix || (strstr(txt, PGP_prefix_msg) != NULL) ||
			  (strstr(txt, PGP_prefix_signed) != NULL))) {
	/* PGP block */
	found_prefix = 1;
	text_block = 0;
	
	p = EP_DefineNewNode(++EP_Node_ID, vS_TO_BE_PGPVERIFIED, 
			     ptr->MIMEContentType, ptr->strMIMEContentType, 0);
	
	if (prev != ptr)
	  prev->next = p;
	else
	  ptr->inner = p;
	
	if ((fout = fopen(p->file, "w")) != NULL ) {
	  fputs(txt, fout);
	  /* To be replaced by fwrite(), more efficient */
	  while ((found_prefix != found_suffix) && 
		 ((strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
	    if (strstr(txt, PGP_prefix_msg) != NULL) found_prefix++;
	    if (strstr(txt, PGP_prefix_signed) != NULL) found_prefix++;
	    if (strstr(txt, PGP_suffix_msg) != NULL) found_suffix++;
	    if (strstr(txt, PGP_suffix_signature) != NULL) found_suffix++;
	    fputs(txt, fout);
	  }
	  if (strptr == NULL ) end_of_fin = 1;
	  
	  fclose(fout);
	  
	  if (found_prefix == found_suffix) {
	    found_prefix = found_suffix = 0;
	    
	    VerifySignAndExplodeFile(p);
	    
	    /* Called form EP_ParseMail or EP_PArseText ? */
	    
	    if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
	      EP_MIMEParse(p);
	    else
	      PA_ParseMessage(p);

	    prev = p;
	  } else {
	    /* Wrong PGP delimiters order. */
	    p->isValidPGPSignature = vS_UNMATCHED_PGP_DELIMITERS;
	  }
	} else {
	  p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
	  return p;
	}
	
      } else {
	/* Clear text block */

	text_block = 1;

	if (strptr == NULL) end_of_fin = 1;
	else {
	  p = EP_DefineNewNode(++EP_Node_ID, vS_IS_NOT_PGP, 
			       ptr->MIMEContentType, 
			       ptr->strMIMEContentType, 0);
	
	  if (prev != ptr)
	    prev->next = p;
	  else
	    ptr->inner = p;

	  if ((fout = fopen(p->file, "w")) != NULL ) {
	    fputs(txt, fout);
	    /* To be replaced by fwrite(), more efficient */
	    while ((!found_prefix && 
		    (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL)) {
	      if ((strstr(txt, PGP_prefix_msg) != NULL) ||
		  (strstr(txt, PGP_prefix_signed) != NULL)) found_prefix++;
	      else 
		fputs(txt, fout);
	    }
	    if (strptr == NULL ) end_of_fin = 1;

	    fclose(fout);

	    /* Check if the blockfile is finished and this is the first
	       segment. If so this is a text leaf */
	    if (found_prefix || (prev != p)) {
	      if (prev->MIMEContentType == -1)
		{
		  if (strstr(EP_outputPrefix, "EPMtmp") != NULL)
		    EP_MIMEParse(p);
		  else
		    PA_ParseMessage(p);
		}
	    
	      prev = p;
	    }
	    
	  } else {
	    p->isValidPGPSignature = vS_UNABLE_TO_WRITE_FILE;
	    return p;
	  }
	}
      }
    } while (!end_of_fin);
  } else {
    p->isValidPGPSignature = vS_NO_IN_FILES;
  }

  return ptr;
}
