static int MimeLeaf_parse_buffer (const char *buffer, PRInt32 size, MimeObject *obj) { MimeLeaf *leaf = (MimeLeaf *) obj; NS_ASSERTION(!obj->closed_p, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); if (obj->closed_p) return -1; /* If we're not supposed to write this object, bug out now. */ if (!obj->output_p || !obj->options || !obj->options->output_fn) return 0; int rv; if (leaf->sizeSoFar == -1) leaf->sizeSoFar = 0; if (leaf->decoder_data && obj->options && obj->options->format_out != nsMimeOutput::nsMimeMessageDecrypt && obj->options->format_out != nsMimeOutput::nsMimeMessageAttach) { int outSize = 0; rv = MimeDecoderWrite (leaf->decoder_data, buffer, size, &outSize); leaf->sizeSoFar += outSize; } else { rv = ((MimeLeafClass *)obj->clazz)->parse_decoded_buffer (buffer, size, obj); leaf->sizeSoFar += size; } return rv; }
NS_METHOD nsEnigMimeListener::Transmit(const char* buf, PRUint32 count, nsIRequest* aRequest, nsISupports* aContext) { DEBUG_LOG(("nsEnigMimeListener::Transmit: (%p) %d\n", this, count)); if (!mDecoderData) { return SendStream(buf, count, aRequest, aContext); } // Decode data before transmitting to listener int status = MimeDecoderWrite(mDecoderData, buf, count); return (status == 0) ? NS_OK : NS_ERROR_FAILURE; }
static int MimeEncrypted_parse_buffer (const char *buffer, PRInt32 size, MimeObject *obj) { /* (Duplicated from MimeLeaf, see comments in mimecryp.h.) */ MimeEncrypted *enc = (MimeEncrypted *) obj; if (obj->closed_p) return -1; /* Don't consult output_p here, since at this point we're behaving as a simple container object -- the output_p decision should be made by the child of this object. */ if (enc->decoder_data) return MimeDecoderWrite (enc->decoder_data, buffer, size); else return ((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer (buffer, size, obj); }
static int MimeMultipartSigned_parse_line (const char *line, PRInt32 length, MimeObject *obj) { MimeMultipart *mult = (MimeMultipart *) obj; MimeMultipartSigned *sig = (MimeMultipartSigned *) obj; MimeMultipartParseState old_state = mult->state; bool hash_line_p = true; bool no_headers_p = 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 = 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 = 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 */ NS_ERROR("bad state in MultipartSigned parse line"); 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. */ NS_ASSERTION(mult->hdrs, "null multipart hdrs"); NS_ASSERTION(!sig->body_hdrs, "signed part shouldn't have already have body_hdrs"); sig->body_hdrs = mult->hdrs; mult->hdrs = 0; /* fall through. */ case MimeMultipartSignedBodyFirstHeader: case MimeMultipartSignedBodyHeaders: case MimeMultipartSignedBodyLine: if (!sig->crypto_closure) { /* Set error change */ PR_SetError(0, 0); /* Initialize the signature verification library. */ sig->crypto_closure = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_init) (obj); if (!sig->crypto_closure) { status = PR_GetError(); NS_ASSERTION(status < 0, "got non-negative status"); 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.) */ bool 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 cryptographic 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] == '\n') length--; if (length > 0 && line[length-1] == '\r') length--; PR_ASSERT(sig->crypto_closure); if (!first_line_p) { /* Push out a preceeding newline... */ char nl[] = CRLF; status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_data_hash (nl, 2, sig->crypto_closure)); if (status < 0) return status; } /* Now push out the line sans trailing newline. */ if (length > 0) status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_data_hash (line,length, sig->crypto_closure)); if (status < 0) return status; } break; case MimeMultipartSignedSignatureHeaders: if (sig->crypto_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) ->crypto_data_eof) (sig->crypto_closure, 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; nsCString encoding; encoding.Adopt(MimeHeaders_get (sig->sig_hdrs, HEADER_CONTENT_TRANSFER_ENCODING, true, false)); if (encoding.IsEmpty()) ; else if (!PL_strcasecmp(encoding.get(), ENCODING_BASE64)) fn = &MimeB64DecoderInit; else if (!PL_strcasecmp(encoding.get(), ENCODING_QUOTED_PRINTABLE)) { sig->sig_decoder_data = MimeQPDecoderInit (((nsresult (*) (const char *, PRInt32, void *)) (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash)), sig->crypto_closure); if (!sig->sig_decoder_data) return MIME_OUT_OF_MEMORY; } else if (!PL_strcasecmp(encoding.get(), ENCODING_UUENCODE) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE2) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE3) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE4)) fn = &MimeUUDecoderInit; else if (!PL_strcasecmp(encoding.get(), ENCODING_YENCODE)) fn = &MimeYDecoderInit; if (fn) { sig->sig_decoder_data = fn (((nsresult (*) (const char *, PRInt32, void *)) (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash)), sig->crypto_closure); if (!sig->sig_decoder_data) return MIME_OUT_OF_MEMORY; } } /* Show these headers to the crypto module. */ if (hash_line_p) { status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_init) (sig->crypto_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, nsnull); else status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash (line, length, sig->crypto_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; }