/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is the Netscape security libraries.
 * 
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are 
 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
 * Rights Reserved.
 * 
 * Contributor(s):
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL"), in which case the provisions of the GPL are applicable 
 * instead of those above.  If you wish to allow use of your 
 * version of this file only under the terms of the GPL and not to
 * allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by
 * the GPL.  If you do not delete the provisions above, a recipient
 * may use your version of this file under either the MPL or the
 * GPL.
 */

#ifndef __JAR_h_
#define __JAR_h_

/*
 *  In general, any functions that return pointers
 *  have memory owned by the caller.
 *
 */

/* security includes */
#include "cert.h"
#include "hasht.h"

/* nspr 2.0 includes */
#include "prio.h"

#ifndef ZHUGEP
#ifdef XP_WIN16
#define ZHUGEP __huge
#else
#define ZHUGEP
#endif
#endif

#include <stdio.h>

/* various types */

typedef enum
  {
  jarTypeMF = 2,
  jarTypeSF = 3,
  jarTypeMeta = 6,
  jarTypePhy = 7,
  jarTypeSign = 10,
  jarTypeSect = 11,
  jarTypeOwner = 13
  }
jarType;

/* void data in ZZList's contain JAR_Item type */

typedef struct JAR_Item_
  {
  char *pathname;        /* relative. inside zip file */
  jarType type;          /* various types */
  size_t size;           /* size of data below */
  void *data;            /* totally opaque */
  }
JAR_Item;


/* hashes */

typedef enum
  {
  jarHashNone = 0,
  jarHashBad = 1,
  jarHashPresent = 2
  }
jarHash;

typedef struct JAR_Digest_
  {
  jarHash md5_status;
  unsigned char md5 [MD5_LENGTH];
  jarHash sha1_status;
  unsigned char sha1 [SHA1_LENGTH];
  }
JAR_Digest;


/* physical archive formats */

typedef enum
  {
  jarArchGuess = 0,
  jarArchNone = 1,
  jarArchZip = 2,
  jarArchTar = 3
  }
jarArch;


#include "jar-ds.h"

/* jar object */

typedef struct JAR_
  {
  jarArch format;       /* physical archive format */ 
  char *url;            /* Where it came from */
  char *filename;       /* Disk location */
  FILE *fp;             /* For multiple extractions */    /* JAR_FILE */

  /* various linked lists */

  ZZList *manifest;     /* Digests of MF sections */
  ZZList *hashes;       /* Digests of actual signed files */
  ZZList *phy;          /* Physical layout of JAR file */
  ZZList *metainfo;     /* Global metainfo */

  JAR_Digest *globalmeta;  /* digest of .MF global portion */

  /* Below will change to a linked list to support multiple sigs */

  int pkcs7;            /* Enforced opaqueness */
  int valid;            /* PKCS7 signature validated */

  ZZList *signers;      /* the above, per signer */

  /* Window context, very necessary for PKCS11 now */

  void *mw;             /* MWContext window context */

  /* Signal callback function */

  int (*signal) (int status, struct JAR_ *jar, 
     const char *metafile, char *pathname, char *errorstring);
  }
JAR;


/*
 *  Iterator
 *
 *  Context for iterative operations. Certain operations
 *  require iterating multiple linked lists because of
 *  multiple signers. "nextsign" is used for this purpose.
 *
 */

typedef struct JAR_Context_
  {
  JAR *jar;             /* Jar we are searching */
  char *pattern;        /* Regular expression */
  jarType finding;      /* Type of item to find */
  ZZLink *next;         /* Next item in find */
  ZZLink *nextsign;     /* Next signer, sometimes */
  }
JAR_Context;

typedef struct JAR_Signer_
  {
  int pkcs7;            /* Enforced opaqueness */
  int valid;            /* PKCS7 signature validated */
  char *owner;          /* name of .RSA file */
  JAR_Digest *digest;   /* of .SF file */
  ZZList *sf;           /* Linked list of .SF file contents */
  ZZList *certs;        /* Signing information */
  }
JAR_Signer;


/* Meta informaton, or "policy", from the manifest file.
   Right now just one tuple per JAR_Item. */

typedef struct JAR_Metainfo_
  {
  char *header;
  char *info;
  }
JAR_Metainfo;

/* This should not be global */

typedef struct JAR_Physical_
  {
  unsigned char compression;
  unsigned long offset;
  unsigned long length;
  unsigned long uncompressed_length;
#if defined(XP_UNIX) || defined(XP_BEOS)
  uint16 mode;
#endif
  }
JAR_Physical;

typedef struct JAR_Cert_
  {
  size_t length;
  void *key;
  CERTCertificate *cert;
  }
JAR_Cert;


/* certificate stuff */

typedef enum
  {
  jarCertCompany = 1,
  jarCertCA = 2,
  jarCertSerial = 3,
  jarCertExpires = 4,
  jarCertNickname = 5,
  jarCertFinger = 6,
  jarCertJavaHack = 100
  }
jarCert;

/* callback types */

#define JAR_CB_SIGNAL	1


/* 
 *  This is the base for the JAR error codes. It will
 *  change when these are incorporated into allxpstr.c,
 *  but right now they won't let me put them there.
 *
 */

#ifndef SEC_ERR_BASE
#define SEC_ERR_BASE		(-0x2000)
#endif
 
#define JAR_BASE		SEC_ERR_BASE + 300

/* Jar specific error definitions */

#define JAR_ERR_GENERAL         (JAR_BASE + 1)
#define JAR_ERR_FNF		(JAR_BASE + 2)
#define JAR_ERR_CORRUPT		(JAR_BASE + 3)
#define JAR_ERR_MEMORY		(JAR_BASE + 4)
#define JAR_ERR_DISK		(JAR_BASE + 5)
#define JAR_ERR_ORDER           (JAR_BASE + 6)
#define JAR_ERR_SIG		(JAR_BASE + 7)
#define JAR_ERR_METADATA        (JAR_BASE + 8)
#define JAR_ERR_ENTRY		(JAR_BASE + 9)
#define JAR_ERR_HASH		(JAR_BASE + 10)
#define JAR_ERR_PK7		(JAR_BASE + 11)
#define JAR_ERR_PNF		(JAR_BASE + 12)


/*
 *  Birth and death 
 *
 */

extern JAR *JAR_new (void);

extern void PR_CALLBACK JAR_destroy (JAR *jar);

extern char *JAR_get_error (int status);

extern int JAR_set_callback (int type, JAR *jar, 
  int (*fn) (int status, JAR *jar, 
  const char *metafile, char *pathname, char *errortext));

extern void JAR_init_callbacks
  ( char *(*string_cb)(int), void *(*find_cx)(void), void *(*init_cx)(void) );

/*
 *  JAR_set_context
 *
 *  PKCS11 may require a password to be entered by the user
 *  before any crypto routines may be called. This will require
 *  a window context if used from inside Mozilla.
 *
 *  Call this routine with your context before calling 
 *  verifying or signing. If you have no context, call with NULL
 *  and one will be chosen for you.
 *
 */

int JAR_set_context (JAR *jar, void /*MWContext*/ *mw);

/*
 *  Iterative operations
 *
 *  JAR_find sets up for repeated calls with JAR_find_next.
 *  I never liked findfirst and findnext, this is nicer.
 *
 *  Pattern contains a relative pathname to match inside the
 *  archive. It is currently assumed to be "*".
 *
 *  To use:
 *
 *     JAR_Item *item;
 *     JAR_find (jar, "*.class", jarTypeMF);
 *     while (JAR_find_next (jar, &item) >= 0) 
 *       { do stuff }
 *
 */


/* Replacement functions with an external context */

extern JAR_Context *JAR_find (JAR *jar, char *pattern, jarType type);

extern int JAR_find_next (JAR_Context *ctx, JAR_Item **it);

extern void JAR_find_end (JAR_Context *ctx);


/*
 *  Function to parse manifest file:
 *
 *  Many signatures may be attached to a single filename located
 *  inside the zip file. We only support one.
 *
 *  Several manifests may be included in the zip file. 
 *
 *  You must pass the MANIFEST.MF file before any .SF files.
 *
 *  Right now this returns a big ole list, privately in the jar structure.
 *  If you need to traverse it, use JAR_find if possible.
 *
 *  The path is needed to determine what type of binary signature is
 *  being passed, though it is technically not needed for manifest files.
 *
 *  When parsing an ASCII file, null terminate the ASCII raw_manifest
 *  prior to sending it, and indicate a length of 0. For binary digital
 *  signatures only, indicate the true length of the signature.
 *  (This is legacy behavior.)
 *
 *  You may free the manifest after parsing it.
 *
 */

extern int JAR_parse_manifest 
    (JAR *jar, char ZHUGEP *raw_manifest, 
       long length, const char *path, const char *url);

/*
 *  Verify data (nonstreaming). The signature is actually
 *  checked by JAR_parse_manifest or JAR_pass_archive.
 *
 */

extern JAR_Digest * PR_CALLBACK JAR_calculate_digest 
    (void ZHUGEP *data, long length);

extern int PR_CALLBACK JAR_verify_digest
    (JAR *jar, const char *name, JAR_Digest *dig);

extern int JAR_digest_file (char *filename, JAR_Digest *dig);

/*
 *  Get attribute from certificate:
 *
 *  Returns any special signed attribute associated with this cert
 *  or signature (passed in "data"). Attributes jarCert*. Most of the time
 *  this will return a zero terminated string.
 *
 */

extern int PR_CALLBACK JAR_cert_attribute
    (JAR *jar, jarCert attrib, long keylen, void *key, 
       void **result, unsigned long *length);

/*
 *  Meta information
 *
 *  Currently, since this call does not support passing of an owner
 *  (certificate, or physical name of the .sf file), it is restricted to
 *  returning information located in the manifest.mf file. 
 *
 *  Meta information is a name/value pair inside the archive file. Here,
 *  the name is passed in *header and value returned in **info.
 *
 *  Pass a NULL as the name to retrieve metainfo from the global section.
 *
 *  Data is returned in **info, of size *length. The return value
 *  will indicate if no data was found.
 *
 */

extern int JAR_get_metainfo
    (JAR *jar, char *name, char *header, void **info, unsigned long *length);

extern char *JAR_get_filename (JAR *jar);

extern char *JAR_get_url (JAR *jar);

/*
 *  Return an HTML mockup of a certificate or signature.
 *
 *  Returns a zero terminated ascii string
 *  in raw HTML format.
 *
 */

extern char *JAR_cert_html
    (JAR *jar, int style, long keylen, void *key, int *result);

/* save the certificate with this fingerprint in persistent
   storage, somewhere, for retrieval in a future session when there 
   is no corresponding JAR structure. */

extern int PR_CALLBACK JAR_stash_cert
        (JAR *jar, long keylen, void *key);

/* retrieve a certificate presumably stashed with the above
   function, but may be any certificate. Type is &CERTCertificate */

void *JAR_fetch_cert (long length, void *key);

/*
 *  New functions to handle archives alone
 *    (call JAR_new beforehand)
 *
 *  JAR_pass_archive acts much like parse_manifest. Certificates
 *  are returned in the JAR structure but as opaque data. When calling 
 *  JAR_verified_extract you still need to decide which of these 
 *  certificates to honor. 
 *
 *  Code to examine a JAR structure is in jarbert.c. You can obtain both 
 *  a list of filenames and certificates from traversing the linked list.
 *
 */

extern int JAR_pass_archive
    (JAR *jar, jarArch format, char *filename, const char *url);

/*
 * Same thing, but don't check signatures
 */
extern int JAR_pass_archive_unverified
    (JAR *jar, jarArch format, char *filename, const char *url);

/*
 *  Extracts a relative pathname from the archive and places it
 *  in the filename specified. 
 * 
 *  Call JAR_set_nailed if you want to keep the file descriptors
 *  open between multiple calls to JAR_verify_extract.
 *
 */

extern int JAR_verified_extract
    (JAR *jar, char *path, char *outpath);

/*
 *  JAR_extract does no crypto checking. This can be used if you
 *  need to extract a manifest file or signature, etc.
 *
 */

extern int JAR_extract
    (JAR *jar, char *path, char *outpath);


#endif /* __JAR_h_ */ 
