/** * g_mime_stream_flush: * @stream: a #GMimeStream * * Sync's the stream to disk. * * Returns: %0 on success or %-1 on fail. **/ int g_mime_stream_flush (GMimeStream *stream) { g_return_val_if_fail (GMIME_IS_STREAM (stream), -1); return GMIME_STREAM_GET_CLASS (stream)->flush (stream); }
/** * g_mime_stream_write_string: * @stream: a #GMimeStream * @str: string to write * * Writes @string to @stream. * * Returns: the number of bytes written or %-1 on fail. **/ ssize_t g_mime_stream_write_string (GMimeStream *stream, const char *str) { g_return_val_if_fail (GMIME_IS_STREAM (stream), -1); g_return_val_if_fail (str != NULL, -1); return g_mime_stream_write (stream, str, strlen (str)); }
/** * g_mime_stream_eos: * @stream: a #GMimeStream * * Tests the end-of-stream indicator for @stream. * * Returns: %TRUE on EOS or %FALSE otherwise. **/ gboolean g_mime_stream_eos (GMimeStream *stream) { g_return_val_if_fail (GMIME_IS_STREAM (stream), TRUE); if (stream->bound_end != -1 && stream->position >= stream->bound_end) return TRUE; return GMIME_STREAM_GET_CLASS (stream)->eos (stream); }
/** * g_mime_stream_write: * @stream: a #GMimeStream * @buf: buffer * @len: buffer length * * Attempts to write up to @len bytes of @buf to @stream. * * Returns: the number of bytes written or %-1 on fail. **/ ssize_t g_mime_stream_write (GMimeStream *stream, const char *buf, size_t len) { g_return_val_if_fail (GMIME_IS_STREAM (stream), -1); g_return_val_if_fail (buf != NULL, -1); if (len == 0) return 0; return GMIME_STREAM_GET_CLASS (stream)->write (stream, buf, len); }
/** * g_mime_stream_reset: * @stream: a #GMimeStream * * Resets the stream. * * Returns: %0 on success or %-1 on fail. **/ int g_mime_stream_reset (GMimeStream *stream) { int rv; g_return_val_if_fail (GMIME_IS_STREAM (stream), -1); if ((rv = GMIME_STREAM_GET_CLASS (stream)->reset (stream)) == 0) stream->position = stream->bound_start; return rv; }
/** * g_mime_stream_set_bounds: * @stream: a #GMimeStream * @start: start boundary * @end: end boundary * * Set the bounds on a stream. **/ void g_mime_stream_set_bounds (GMimeStream *stream, gint64 start, gint64 end) { g_return_if_fail (GMIME_IS_STREAM (stream)); stream->bound_start = start; stream->bound_end = end; if (stream->position < start) stream->position = start; else if (stream->position > end && end != -1) stream->position = end; }
/** * g_mime_stream_substream: * @stream: a #GMimeStream * @start: start boundary * @end: end boundary * * Creates a new substream of @stream with bounds @start and @end. * * Returns: a substream of @stream with bounds @start and @end. **/ GMimeStream * g_mime_stream_substream (GMimeStream *stream, gint64 start, gint64 end) { GMimeStream *sub; g_return_val_if_fail (GMIME_IS_STREAM (stream), NULL); if ((sub = GMIME_STREAM_GET_CLASS (stream)->substream (stream, start, end))) { sub->super_stream = stream; g_object_ref (stream); } return sub; }
/** * g_mime_header_list_set_stream: * @headers: a #GMimeHeaderList * @stream: a #GMimeStream * * Set the raw header stream. **/ void g_mime_header_list_set_stream (GMimeHeaderList *headers, GMimeStream *stream) { g_return_if_fail (stream == NULL || GMIME_IS_STREAM (stream)); g_return_if_fail (headers != NULL); if (headers->stream == stream) return; if (stream) g_object_ref (stream); if (headers->stream) g_object_unref (headers->stream); headers->stream = stream; g_mime_event_emit (headers->changed, NULL); }
gboolean mux_message_part_write (MuxMessagePart *self, GMimeStream *ostream, GError **err) { ssize_t bytes; g_return_val_if_fail (MUX_IS_MESSAGE_PART(self), FALSE); g_return_val_if_fail (GMIME_IS_STREAM(ostream), FALSE); if (GMIME_IS_PART(self->mime_object)) { GMimeDataWrapper *wrapper; wrapper = get_data_wrapper (self->mime_object, err); if (!wrapper) return FALSE; bytes = g_mime_data_wrapper_write_to_stream ( wrapper, ostream); } else { GMimeStream *istream; istream = get_mime_stream (self->mime_object, err); if (!istream) return FALSE; bytes = g_mime_stream_write_to_stream (istream, ostream); } if (bytes == -1) { g_set_error (err, G_IO_ERROR, G_IO_ERROR_FAILED, "failed to write part to stream"); return FALSE; } bytes = g_mime_stream_flush (ostream); if (bytes == -1) { g_set_error (err, G_IO_ERROR, G_IO_ERROR_FAILED, "failed to flush stream"); return FALSE; } return TRUE; }
/** * g_mime_stream_printf: * @stream: a #GMimeStream * @fmt: format * @Varargs: arguments * * Write formatted output to a stream. * * Returns: the number of bytes written or %-1 on fail. **/ ssize_t g_mime_stream_printf (GMimeStream *stream, const char *fmt, ...) { va_list args; char *string; ssize_t ret; g_return_val_if_fail (GMIME_IS_STREAM (stream), -1); g_return_val_if_fail (fmt != NULL, -1); va_start (args, fmt); string = g_strdup_vprintf (fmt, args); va_end (args); if (!string) return -1; ret = g_mime_stream_write (stream, string, strlen (string)); g_free (string); return ret; }
static void print_body (GMimeMessage *msg) { GMimeObject *body; GMimeDataWrapper *wrapper; GMimeStream *stream; body = g_mime_message_get_body (msg); if (GMIME_IS_MULTIPART(body)) body = g_mime_multipart_get_part (GMIME_MULTIPART(body), 0); if (!GMIME_IS_PART(body)) return; wrapper = g_mime_part_get_content_object (GMIME_PART(body)); if (!GMIME_IS_DATA_WRAPPER(wrapper)) return; stream = g_mime_data_wrapper_get_stream (wrapper); if (!GMIME_IS_STREAM(stream)) return; do { char buf[512]; ssize_t len; len = g_mime_stream_read (stream, buf, sizeof(buf)); if (len == -1) break; if (write (fileno(stdout), buf, len) == -1) break; if (len < (int)sizeof(buf)) break; } while (1); }
/** * libbalsa_mime_stream_shared_unlock: * @stream: shared stream * * Unlock the shared stream **/ void libbalsa_mime_stream_shared_unlock(GMimeStream * stream) { LibBalsaMimeStreamShared *stream_shared; LibBalsaMimeStreamSharedLock *lock; g_return_if_fail(GMIME_IS_STREAM(stream)); if (GMIME_IS_STREAM_FILTER(stream)) stream = ((GMimeStreamFilter *) stream)->source; if (!LIBBALSA_IS_MIME_STREAM_SHARED(stream)) return; stream_shared = (LibBalsaMimeStreamShared *) stream; lock = stream_shared->lock; g_return_if_fail(lock->count > 0); g_mutex_lock(&lbmss_mutex); if (--lock->count == 0) g_cond_signal(&lbmss_cond); g_mutex_unlock(&lbmss_mutex); }
gboolean write_part_to_fd (GMimePart *part, int fd, GError **err) { GMimeStream *stream; GMimeDataWrapper *wrapper; gboolean rv; stream = g_mime_stream_fs_new (fd); if (!GMIME_IS_STREAM(stream)) { g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME, "failed to create stream"); return FALSE; } g_mime_stream_fs_set_owner (GMIME_STREAM_FS(stream), FALSE); wrapper = g_mime_part_get_content_object (part); if (!GMIME_IS_DATA_WRAPPER(wrapper)) { g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME, "failed to create wrapper"); g_object_unref (stream); return FALSE; } g_object_ref (part); /* FIXME: otherwise, the unrefs below * give errors...*/ if (g_mime_data_wrapper_write_to_stream (wrapper, stream) == -1) { rv = FALSE; g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME, "failed to write to stream"); } else rv = TRUE; g_object_unref (wrapper); g_object_unref (stream); return rv; }
/** \brief Decrypt data * * \param istream GMime input (encrypted) stream. * \param ostream GMime output (decrypted) stream. * \param protocol GpgME crypto protocol to use. * \param parent Parent window to be passed to the passphrase callback * function. * \param error Filled with error information on error. * \return A new signature status object on success, or NULL on error. * * Decrypt and -if applicable- verify the signature of the passed data * stream. If the input is not signed the returned signature status will * be GPG_ERR_NOT_SIGNED. */ GMimeGpgmeSigstat * libbalsa_gpgme_decrypt(GMimeStream * crypted, GMimeStream * plain, gpgme_protocol_t protocol, GtkWindow * parent, GError ** error) { gpgme_ctx_t ctx; gpgme_error_t err; gpgme_data_t plain_data; gpgme_data_t crypt_data; GMimeGpgmeSigstat *result; struct gpgme_data_cbs cbs = { (gpgme_data_read_cb_t) g_mime_gpgme_stream_rd, /* read method */ (gpgme_data_write_cb_t) g_mime_gpgme_stream_wr, /* write method */ NULL, /* seek method */ cb_data_release /* release method */ }; /* paranoia checks */ g_return_val_if_fail(GMIME_IS_STREAM(crypted), NULL); g_return_val_if_fail(GMIME_IS_STREAM(plain), NULL); g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP || protocol == GPGME_PROTOCOL_CMS, NULL); /* create the GpgME context */ if ((err = gpgme_new_with_protocol(&ctx, protocol, parent, error)) != GPG_ERR_NO_ERROR) return NULL; /* create the data streams */ if ((err = gpgme_data_new_from_cbs(&crypt_data, &cbs, crypted)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_release(ctx); return NULL; } if ((err = gpgme_data_new_from_cbs(&plain_data, &cbs, plain)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not create new data object")); gpgme_data_release(crypt_data); gpgme_release(ctx); return NULL; } /* try to decrypt */ if ((err = gpgme_op_decrypt_verify(ctx, crypt_data, plain_data)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("decryption failed")); result = NULL; } else { /* decryption successful, check for signature */ result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx); } /* clean up */ gpgme_data_release(plain_data); gpgme_data_release(crypt_data); gpgme_release(ctx); return result; }
/** \brief Encrypt data * * \param recipients Array of User ID for which the matter shall be * encrypted using their public keys. * \param sign_for User ID of the signer or NULL if the matter shall not be * signed. Note that combined signing and encryption is allowed \em * only in OpenPGP single-part (i.e. RFC 2440) mode. * \param istream GMime input stream. * \param ostream GMime output stream. * \param protocol GpgME crypto protocol to use for encryption. * \param singlepart_mode TRUE indicates single-part mode (integrated * signature), FALSE a detached signature. * \param trust_all_keys TRUE if all low-truct keys shall be accepted for * encryption. Otherwise, the function will use the global callback * to ask the user whether a low-trust key shall be accepted. * \param parent Parent window to be passed to the callback functions. * \param error Filled with error information on error. * \return 0 on success, or -1 on error. * * Encrypt the passed matter and write the result to the output stream. * Combined signing and encryption is allowed for single-part OpenPGP mode * only. */ int libbalsa_gpgme_encrypt(GPtrArray * recipients, const char *sign_for, GMimeStream * istream, GMimeStream * ostream, gpgme_protocol_t protocol, gboolean singlepart_mode, gboolean trust_all_keys, GtkWindow * parent, GError ** error) { gpgme_ctx_t ctx; gpgme_error_t err; gpgme_key_t *rcpt_keys; gpgme_data_t plain; gpgme_data_t crypt; struct gpgme_data_cbs cbs = { (gpgme_data_read_cb_t) g_mime_gpgme_stream_rd, /* read method */ (gpgme_data_write_cb_t) g_mime_gpgme_stream_wr, /* write method */ NULL, /* seek method */ cb_data_release /* release method */ }; /* paranoia checks */ g_return_val_if_fail(recipients != NULL, -1); g_return_val_if_fail(GMIME_IS_STREAM(istream), -1); g_return_val_if_fail(GMIME_IS_STREAM(ostream), GPGME_MD_NONE); g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP || protocol == GPGME_PROTOCOL_CMS, -1); /* create the GpgME context */ if ((err = gpgme_new_with_protocol(&ctx, protocol, parent, error)) != GPG_ERR_NO_ERROR) return -1; /* sign & encrypt is valid only for single-part OpenPGP */ if (sign_for != NULL && (!singlepart_mode || protocol != GPGME_PROTOCOL_OpenPGP)) { if (error) g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_INV_ENGINE, _ ("combined signing and encryption is defined only for RFC 2440")); gpgme_release(ctx); return -1; } /* if requested, find the secret key for "userid" */ if (sign_for && !gpgme_add_signer(ctx, sign_for, parent, error)) { gpgme_release(ctx); return -1; } /* build the list of recipients */ if (! (rcpt_keys = gpgme_build_recipients(ctx, recipients, trust_all_keys, parent, error))) { gpgme_release(ctx); return -1; } /* create the data objects */ if (protocol == GPGME_PROTOCOL_OpenPGP) { gpgme_set_armor(ctx, 1); gpgme_set_textmode(ctx, singlepart_mode); } else { gpgme_set_armor(ctx, 0); gpgme_set_textmode(ctx, 0); } if ((err = gpgme_data_new_from_cbs(&plain, &cbs, istream)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); release_keylist(rcpt_keys); gpgme_release(ctx); return -1; } if ((err = gpgme_data_new_from_cbs(&crypt, &cbs, ostream)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not create new data object")); release_keylist(rcpt_keys); gpgme_data_release(plain); gpgme_release(ctx); return -1; } /* do the encrypt or sign and encrypt operation * Note: we set "always trust" here, as if we detected an untrusted key * earlier, the user already accepted it */ if (sign_for) err = gpgme_op_encrypt_sign(ctx, rcpt_keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, crypt); else err = gpgme_op_encrypt(ctx, rcpt_keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, crypt); release_keylist(rcpt_keys); gpgme_data_release(plain); gpgme_data_release(crypt); gpgme_release(ctx); if (err != GPG_ERR_NO_ERROR) { if (sign_for) g_set_error_from_gpgme(error, err, _("signing and encryption failed")); else g_set_error_from_gpgme(error, err, _("encryption failed")); return -1; } else return 0; }
/** \brief Sign data * * \param userid User ID of the signer. * \param istream GMime input stream. * \param ostream GMime output stream. * \param protocol GpgME crypto protocol of the signature. * \param singlepart_mode TRUE indicates single-part mode (integrated * signature), FALSE a detached signature. * \param parent Parent window to be passed to the passphrase callback * function. * \param error Filled with error information on error. * \return The hash algorithm used for creating the signature, or * GPGME_MD_NONE on error. * * Sign the passed matter and write the detached signature or the signed * input and the signature, respectively, to the output stream. The global * callback to read the passphrase for the user's private key will be * called by GpgME if no GPG Agent is running. */ gpgme_hash_algo_t libbalsa_gpgme_sign(const gchar * userid, GMimeStream * istream, GMimeStream * ostream, gpgme_protocol_t protocol, gboolean singlepart_mode, GtkWindow * parent, GError ** error) { gpgme_error_t err; gpgme_ctx_t ctx; gpgme_sig_mode_t sig_mode; gpgme_data_t in; gpgme_data_t out; gpgme_hash_algo_t hash_algo; struct gpgme_data_cbs cbs = { (gpgme_data_read_cb_t) g_mime_gpgme_stream_rd, /* read method */ (gpgme_data_write_cb_t) g_mime_gpgme_stream_wr, /* write method */ NULL, /* seek method */ cb_data_release /* release method */ }; /* paranoia checks */ g_return_val_if_fail(GMIME_IS_STREAM(istream), GPGME_MD_NONE); g_return_val_if_fail(GMIME_IS_STREAM(ostream), GPGME_MD_NONE); g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP || protocol == GPGME_PROTOCOL_CMS, GPGME_MD_NONE); /* create the GpgME context */ if ((err = gpgme_new_with_protocol(&ctx, protocol, parent, error)) != GPG_ERR_NO_ERROR) return GPGME_MD_NONE; /* set the signature mode */ if (singlepart_mode) { if (protocol == GPGME_PROTOCOL_OpenPGP) sig_mode = GPGME_SIG_MODE_CLEAR; else sig_mode = GPGME_SIG_MODE_NORMAL; } else sig_mode = GPGME_SIG_MODE_DETACH; /* find the secret key for the "sign_for" address */ if (!gpgme_add_signer(ctx, userid, parent, error)) { gpgme_release(ctx); return GPGME_MD_NONE; } /* OpenPGP signatures are ASCII armored */ gpgme_set_armor(ctx, protocol == GPGME_PROTOCOL_OpenPGP); /* create gpgme data objects */ if ((err = gpgme_data_new_from_cbs(&in, &cbs, istream)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_release(ctx); return GPGME_MD_NONE; } if ((err = gpgme_data_new_from_cbs(&out, &cbs, ostream)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not create new data object")); gpgme_data_release(in); gpgme_release(ctx); return GPGME_MD_NONE; } /* sign and get the used hash algorithm */ err = gpgme_op_sign(ctx, in, out, sig_mode); if (err != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("signing failed")); hash_algo = GPGME_MD_NONE; } else hash_algo = gpgme_op_sign_result(ctx)->signatures->hash_algo; /* clean up */ gpgme_data_release(in); gpgme_data_release(out); gpgme_release(ctx); return hash_algo; }
/** \brief Verify a signature * * \param content GMime stream of the signed matter. * \param sig_plain GMime signature stream for a detached signature, or the * output stream for the checked matter in single-part mode. * \param protocol GpgME crypto protocol of the signature. * \param singlepart_mode TRUE indicates single-part mode (i.e. sig_plain * an output stream). * \param error Filled with error information on error. * \return A new signature status object on success, or NULL on error. * * Verify a signature by calling GpgME on the passed streams, and create a * new signature object on success. */ GMimeGpgmeSigstat * libbalsa_gpgme_verify(GMimeStream * content, GMimeStream * sig_plain, gpgme_protocol_t protocol, gboolean singlepart_mode, GError ** error) { gpgme_error_t err; gpgme_ctx_t ctx; struct gpgme_data_cbs cbs = { (gpgme_data_read_cb_t) g_mime_gpgme_stream_rd, /* read method */ (gpgme_data_write_cb_t) g_mime_gpgme_stream_wr, /* write method */ NULL, /* seek method */ cb_data_release /* release method */ }; gpgme_data_t cont_data; gpgme_data_t sig_plain_data; GMimeGpgmeSigstat *result; /* paranoia checks */ g_return_val_if_fail(GMIME_IS_STREAM(content), NULL); g_return_val_if_fail(GMIME_IS_STREAM(sig_plain), NULL); g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP || protocol == GPGME_PROTOCOL_CMS, NULL); /* create the GpgME context */ if ((err = gpgme_new_with_protocol(&ctx, protocol, NULL, error)) != GPG_ERR_NO_ERROR) return NULL; /* create the message stream */ if ((err = gpgme_data_new_from_cbs(&cont_data, &cbs, content)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_release(ctx); return NULL; } /* create data object for the detached signature stream or the * "decrypted" plaintext */ if ((err = gpgme_data_new_from_cbs(&sig_plain_data, &cbs, sig_plain)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_data_release(cont_data); gpgme_release(ctx); return NULL; } /* verify the signature */ if (singlepart_mode) err = gpgme_op_verify(ctx, cont_data, NULL, sig_plain_data); else err = gpgme_op_verify(ctx, sig_plain_data, cont_data, NULL); if (err != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("signature verification failed")); result = g_mime_gpgme_sigstat_new(); result->status = err; result->protocol = gpgme_get_protocol(ctx); } else result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx); /* release gmgme data buffers, destroy the context and return the * signature object */ gpgme_data_release(cont_data); gpgme_data_release(sig_plain_data); gpgme_release(ctx); return result; }