if (length > 0 && line[length-1] == LF) length--; if (length > 0 && line[length-1] == CR) length--;
if (length > 0 && line[length-1] == nsCRT::LF) length--; if (length > 0 && line[length-1] == nsCRT::CR) length--;
MimeMultipartSigned_parse_line (char *line, PRInt32 length, MimeObject *obj){  MimeMultipart *mult = (MimeMultipart *) obj;  MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;  MimeMultipartParseState old_state = mult->state;  PRBool hash_line_p = PR_TRUE;  PRBool no_headers_p = PR_FALSE;  int status = 0;  /* First do the parsing for normal multipart/ objects by handing it off to	 the superclass method.  This includes calling the create_child and	 close_child methods.   */  status = (((MimeObjectClass *)(&MIME_SUPERCLASS))			->parse_line (line, length, obj));  if (status < 0) return status;  /* The instance variable MimeMultipartClass->state tracks motion through	 the various stages of multipart/ parsing.  The instance variable	 MimeMultipartSigned->state tracks the difference between the first	 part (the body) and the second part (the signature.)  This second,	 more specific state variable is updated by noticing the transitions	 of the first, more general state variable.   */  if (old_state != mult->state)  /* there has been a state change */	{	  switch (mult->state)		{		case MimeMultipartPreamble:		  PR_ASSERT(0);  /* can't move *in* to preamble state. */		  sig->state = MimeMultipartSignedPreamble;		  break;		case MimeMultipartHeaders:		  /* If we're moving in to the Headers state, then that means			 that this line is the preceeding boundary string (and we			 should ignore it.)		   */		  hash_line_p = PR_FALSE;		  if (sig->state == MimeMultipartSignedPreamble)			sig->state = MimeMultipartSignedBodyFirstHeader;		  else if (sig->state == MimeMultipartSignedBodyFirstLine ||				   sig->state == MimeMultipartSignedBodyLine)			sig->state = MimeMultipartSignedSignatureHeaders;		  else if (sig->state == MimeMultipartSignedSignatureFirstLine ||				   sig->state == MimeMultipartSignedSignatureLine)			sig->state = MimeMultipartSignedEpilogue;		  break;		case MimeMultipartPartFirstLine:		  if (sig->state == MimeMultipartSignedBodyFirstHeader)			{						  sig->state = MimeMultipartSignedBodyFirstLine;			  no_headers_p = PR_TRUE;			}		  else if (sig->state == MimeMultipartSignedBodyHeaders)			sig->state = MimeMultipartSignedBodyFirstLine;		  else if (sig->state == MimeMultipartSignedSignatureHeaders)			sig->state = MimeMultipartSignedSignatureFirstLine;		  else			sig->state = MimeMultipartSignedEpilogue;		  break;		case MimeMultipartPartLine:		  PR_ASSERT(sig->state == MimeMultipartSignedBodyFirstLine ||					sig->state == MimeMultipartSignedBodyLine ||					sig->state == MimeMultipartSignedSignatureFirstLine ||					sig->state == MimeMultipartSignedSignatureLine);		  if (sig->state == MimeMultipartSignedBodyFirstLine)			sig->state = MimeMultipartSignedBodyLine;		  else if (sig->state == MimeMultipartSignedSignatureFirstLine)			sig->state = MimeMultipartSignedSignatureLine;		  break;		case MimeMultipartEpilogue:		  sig->state = MimeMultipartSignedEpilogue;		  break;		default:  /* bad state */		  PR_ASSERT(0);		  return -1;		  break;		}	}  /* Perform multipart/signed-related actions on this line based on the state	 of the parser.   */  switch (sig->state)	{	case MimeMultipartSignedPreamble:	  /* Do nothing. */	  break;	case MimeMultipartSignedBodyFirstLine:	  /* We have just moved out of the MimeMultipartSignedBodyHeaders		 state, so cache away the headers that apply only to the body part.	   */	  PR_ASSERT(mult->hdrs);	  PR_ASSERT(!sig->body_hdrs);	  sig->body_hdrs = mult->hdrs;	  mult->hdrs = 0;	  /* fall through. */	case MimeMultipartSignedBodyFirstHeader:	case MimeMultipartSignedBodyHeaders:	case MimeMultipartSignedBodyLine:	  if (!sig->xlation_closure)		{		  /* Set error change */		  PR_SetError(0, 0);		  /* Initialize the signature verification library. */		  sig->xlation_closure = (((MimeMultipartSignedClass *) obj->clazz)								 ->xlation_init) (obj);		  if (!sig->xlation_closure)			{			  status = PR_GetError();			  PR_ASSERT(status < 0);			  if (status >= 0) status = -1;			  return status;			}		}	  if (hash_line_p)		{		  /* this is the first hashed line if this is the first header			 (that is, if it's the first line in the header state after			 a state change.)		   */		  PRBool first_line_p			= (no_headers_p ||			   sig->state == MimeMultipartSignedBodyFirstHeader);		  if (sig->state == MimeMultipartSignedBodyFirstHeader)			sig->state = MimeMultipartSignedBodyHeaders;		  /* The newline issues here are tricky, since both the newlines			 before and after the boundary string are to be considered part			 of the boundary: this is so that a part can be specified such			 that it does not end in a trailing newline.			 To implement this, we send a newline *before* each line instead			 of after, except for the first line, which is not preceeded by a			 newline.			 For purposes of xlationgraphic hashing, we always hash line			 breaks as CRLF -- the canonical, on-the-wire linebreaks, since			 we have no idea of knowing what line breaks were used on the			 originating system (SMTP rightly destroys that information.)		   */		  /* Remove the trailing newline... */		  if (length > 0 && line[length-1] == LF) length--;		  if (length > 0 && line[length-1] == CR) length--;		  PR_ASSERT(sig->xlation_closure);		  if (!first_line_p)			{			  /* Push out a preceeding newline... */			  char nl[] = CRLF;			  status = (((MimeMultipartSignedClass *) obj->clazz)						->xlation_data_hash (nl, 2, sig->xlation_closure));			  if (status < 0) return status;			}		  /* Now push out the line sans trailing newline. */		  if (length > 0)			status = (((MimeMultipartSignedClass *) obj->clazz)					  ->xlation_data_hash (line,length, sig->xlation_closure));		  if (status < 0) return status;		}	  break;	case MimeMultipartSignedSignatureHeaders:	  if (sig->xlation_closure &&		  old_state != mult->state)		{		  /* We have just moved out of the MimeMultipartSignedBodyLine			 state, so tell the signature verification library that we've			 reached the end of the signed data.		   */		  status = (((MimeMultipartSignedClass *) obj->clazz)					->xlation_data_eof) (sig->xlation_closure, PR_FALSE);		  if (status < 0) return status;		}	  break;	case MimeMultipartSignedSignatureFirstLine:	  /* We have just moved out of the MimeMultipartSignedSignatureHeaders		 state, so cache away the headers that apply only to the sig part.	   */	  PR_ASSERT(mult->hdrs);	  PR_ASSERT(!sig->sig_hdrs);	  sig->sig_hdrs = mult->hdrs;	  mult->hdrs = 0;	  /* If the signature block has an encoding, set up a decoder for it.		 (Similar logic is in MimeLeafClass->parse_begin.)	   */	  {		MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32,void*), void*) = 0;		char *encoding = MimeHeaders_get (sig->sig_hdrs,										  HEADER_CONTENT_TRANSFER_ENCODING,										  PR_TRUE, PR_FALSE);		if (!encoding)		  ;		else if (!nsCRT::strcasecmp(encoding, ENCODING_BASE64))		  fn = &MimeB64DecoderInit;		else if (!nsCRT::strcasecmp(encoding, ENCODING_QUOTED_PRINTABLE))		  fn = &MimeQPDecoderInit;		else if (!nsCRT::strcasecmp(encoding, ENCODING_UUENCODE) ||				 !nsCRT::strcasecmp(encoding, ENCODING_UUENCODE2) ||				 !nsCRT::strcasecmp(encoding, ENCODING_UUENCODE3) ||				 !nsCRT::strcasecmp(encoding, ENCODING_UUENCODE4))		  fn = &MimeUUDecoderInit;		if (fn)		  {			sig->sig_decoder_data =			  fn (((nsresult (*) (const char *, PRInt32, void *))				   (((MimeMultipartSignedClass *) obj->clazz)					->xlation_signature_hash)),				  sig->xlation_closure);			if (!sig->sig_decoder_data)			  return MIME_OUT_OF_MEMORY;		  }	  }	  /* Show these headers to the xlation module. */	  if (hash_line_p)		{		  status = (((MimeMultipartSignedClass *) obj->clazz)					->xlation_signature_init) (sig->xlation_closure,											  obj, sig->sig_hdrs);		  if (status < 0) return status;		}	  /* fall through. */	case MimeMultipartSignedSignatureLine:	  if (hash_line_p)		{		  /* Feed this line into the signature verification routines. */		  if (sig->sig_decoder_data)			status = MimeDecoderWrite (sig->sig_decoder_data, line, length);		  else			status = (((MimeMultipartSignedClass *) obj->clazz)					  ->xlation_signature_hash (line, length,											   sig->xlation_closure));		  if (status < 0) return status;		}	  break;	case MimeMultipartSignedEpilogue:	  /* Nothing special to do here. */	  break;	default:  /* bad state */	  PR_ASSERT(0);	  return -1;	}  return status;}