extern MimeObjectClass mimeEncryptedClass;
static void *MimeMultCMS_init (MimeObject *);static int MimeMultCMS_data_hash (char *, PRInt32, void *);static int MimeMultCMS_sig_hash  (char *, PRInt32, void *);static int MimeMultCMS_data_eof (void *, PRBool);static int MimeMultCMS_sig_eof  (void *, PRBool);static int MimeMultCMS_sig_init (void *, MimeObject *, MimeHeaders *);static char * MimeMultCMS_generate (void *);static void MimeMultCMS_free (void *);static void MimeMultCMS_get_content_info (MimeObject *,											nsICMSMessage **,											char **, PRInt32 *, PRInt32 *, PRBool *);extern int SEC_ERROR_CERT_ADDR_MISMATCH;static intMimeMultipartSignedCMSClassInitialize(MimeMultipartSignedCMSClass *clazz){  MimeObjectClass          *oclass = (MimeObjectClass *)    clazz;  MimeMultipartSignedClass *sclass = (MimeMultipartSignedClass *) clazz;  oclass->initialize  = MimeMultipartSignedCMS_initialize;  sclass->crypto_init           = MimeMultCMS_init;  sclass->crypto_data_hash      = MimeMultCMS_data_hash;  sclass->crypto_data_eof       = MimeMultCMS_data_eof;  sclass->crypto_signature_init = MimeMultCMS_sig_init;  sclass->crypto_signature_hash = MimeMultCMS_sig_hash;  sclass->crypto_signature_eof  = MimeMultCMS_sig_eof;  sclass->crypto_generate_html  = MimeMultCMS_generate;  sclass->crypto_free           = MimeMultCMS_free;  clazz->get_content_info	    = MimeMultCMS_get_content_info;  PR_ASSERT(!oclass->class_initialized);  return 0;}static intMimeMultipartSignedCMS_initialize (MimeObject *object){  return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object);}typedef struct MimeMultCMSdata{  PRInt16 hash_type;  nsCOMPtr<nsIHash> data_hash_context;  nsCOMPtr<nsICMSDecoder> sig_decoder_context;  nsCOMPtr<nsICMSMessage> content_info;  char *sender_addr;  PRInt32 decode_error;  PRInt32 verify_error;  unsigned char* item_data;  PRUint32 item_len;  MimeObject *self;  PRBool parent_is_encrypted_p;  PRBool parent_holds_stamp_p;  nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;    MimeMultCMSdata()  :hash_type(0),  sender_addr(nsnull),  decode_error(0),  verify_error(0),  item_data(nsnull),  self(nsnull),  parent_is_encrypted_p(PR_FALSE),  parent_holds_stamp_p(PR_FALSE)  {  }    ~MimeMultCMSdata()  {    PR_FREEIF(sender_addr);    // Do a graceful shutdown of the nsICMSDecoder and release the nsICMSMessage //    if (sig_decoder_context)    {	    nsCOMPtr<nsICMSMessage> cinfo;      sig_decoder_context->Finish(getter_AddRefs(cinfo));    }    delete [] item_data;  }} MimeMultCMSdata;extern MimeObjectClass mimeEncryptedClass;static voidMimeMultCMS_get_content_info(MimeObject *obj,							   nsICMSMessage **content_info_ret,							   char **sender_email_addr_return,							   PRInt32 *decode_error_ret,							   PRInt32 *verify_error_ret,                               PRBool *ci_is_encrypted){  MimeMultipartSigned *msig = (MimeMultipartSigned *) obj;  if (msig && msig->crypto_closure)	{	  MimeMultCMSdata *data = (MimeMultCMSdata *) msig->crypto_closure;	  *decode_error_ret = data->decode_error;	  *verify_error_ret = data->verify_error;	  *content_info_ret = data->content_info;      *ci_is_encrypted     = PR_FALSE;	  if (sender_email_addr_return)		*sender_email_addr_return = (data->sender_addr                   ? nsCRT::strdup(data->sender_addr)									 : 0);	}}/* #### MimeEncryptedCMS and MimeMultipartSignedCMS have a sleazy,        incestuous, dysfunctional relationship. */extern PRBool MimeEncryptedCMS_encrypted_p (MimeObject *obj);extern PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj,											 nsICMSMessage *,											 char **);extern char *MimeCMS_MakeSAURL(MimeObject *obj);extern char *IMAP_CreateReloadAllPartsUrl(const char *url);static void *MimeMultCMS_init (MimeObject *obj){  MimeHeaders *hdrs = obj->headers;  MimeMultCMSdata *data = 0;  char *ct, *micalg;  PRInt16 hash_type;  nsresult rv;  ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);  if (!ct) return 0; /* #### bogus message?  out of memory? */  micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL);  PR_Free(ct);  ct = 0;  if (!micalg) return 0; /* #### bogus message?  out of memory? */  if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_MD5))	hash_type = nsIHash::HASH_AlgMD5;  else if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1) ||		   !nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||		   !nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||		   !nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||		   !nsCRT::strcasecmp(micalg, PARAM_MICALG_SHA1_5))	hash_type = nsIHash::HASH_AlgSHA1;  else if (!nsCRT::strcasecmp(micalg, PARAM_MICALG_MD2))	hash_type = nsIHash::HASH_AlgMD2;  else	hash_type = nsIHash::HASH_AlgNULL;  PR_Free(micalg);  micalg = 0;  if (hash_type == nsIHash::HASH_AlgNULL) return 0; /* #### bogus message? */  data = new MimeMultCMSdata;  if (!data)    return 0;  data->self = obj;  data->hash_type = hash_type;  data->data_hash_context = do_CreateInstance(NS_HASH_CONTRACTID, &rv);  if (NS_FAILED(rv)) return 0;  rv = data->data_hash_context->Create(data->hash_type);  if (NS_FAILED(rv)) return 0;  PR_SetError(0,0);  data->data_hash_context->Begin();  if (!data->decode_error)	{	  data->decode_error = PR_GetError();	  if (data->decode_error)		{		  delete data;		  return 0;		}	}  data->parent_holds_stamp_p =	(obj->parent && mime_crypto_stamped_p(obj->parent));  data->parent_is_encrypted_p =	(obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));  /* If the parent of this object is a crypto-blob, then it's the grandparent	 who would have written out the headers and prepared for a stamp...	 (This s##t s$%#s.)   */  if (data->parent_is_encrypted_p &&	  !data->parent_holds_stamp_p &&	  obj->parent && obj->parent->parent)	data->parent_holds_stamp_p =	  mime_crypto_stamped_p (obj->parent->parent);  mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);  if (msd)  {    nsIChannel *channel = msd->channel;  // note the lack of ref counting...    if (channel)    {      nsCOMPtr<nsIURI> uri;      nsCOMPtr<nsIMsgWindow> msgWindow;      nsCOMPtr<nsIMsgHeaderSink> headerSink;      nsCOMPtr<nsIMsgMailNewsUrl> msgurl;      nsCOMPtr<nsISupports> securityInfo;      channel->GetURI(getter_AddRefs(uri));      if (uri)        msgurl = do_QueryInterface(uri);      if (msgurl)        msgurl->GetMsgWindow(getter_AddRefs(msgWindow));      if (msgWindow)        msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));      if (headerSink)        headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));      if (securityInfo)        data->smimeHeaderSink = do_QueryInterface(securityInfo);    } // if channel  } // if msd  return data;}