Beispiel #1
0
static void
save_snapshot_get_message_cb (EMsgComposer *composer,
                              GAsyncResult *result,
                              GSimpleAsyncResult *simple)
{
	SaveContext *context;
	CamelMimeMessage *message;
	GInputStream *input_stream;
	CamelStream *camel_stream;
	GByteArray *buffer;
	GError *local_error = NULL;

	context = g_simple_async_result_get_op_res_gpointer (simple);

	message = e_msg_composer_get_message_draft_finish (
		composer, result, &local_error);

	if (local_error != NULL) {
		g_warn_if_fail (message == NULL);
		g_simple_async_result_take_error (simple, local_error);
		g_simple_async_result_complete (simple);
		g_object_unref (simple);
		return;
	}

	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));

	/* Decode the message to an in-memory buffer.  We have to do this
	 * because CamelStreams are synchronous-only, and using threads is
	 * dangerous because CamelDataWrapper is not reentrant. */
	buffer = g_byte_array_new ();
	camel_stream = camel_stream_mem_new ();
	camel_stream_mem_set_byte_array (
		CAMEL_STREAM_MEM (camel_stream), buffer);
	camel_data_wrapper_decode_to_stream_sync (
		CAMEL_DATA_WRAPPER (message), camel_stream, NULL, NULL);
	g_object_unref (camel_stream);

	g_object_unref (message);

	/* Load the buffer into a GMemoryInputStream. */
	input_stream = g_memory_input_stream_new ();
	if (buffer->len > 0)
		g_memory_input_stream_add_data (
			G_MEMORY_INPUT_STREAM (input_stream),
			buffer->data, (gssize) buffer->len,
			(GDestroyNotify) g_free);
	g_byte_array_free (buffer, FALSE);

	/* Splice the input and output streams. */
	g_output_stream_splice_async (
		context->output_stream, input_stream,
		G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
		G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
		G_PRIORITY_DEFAULT, context->cancellable,
		(GAsyncReadyCallback) save_snapshot_splice_cb,
		simple);

	g_object_unref (input_stream);
}
/**
 * camel_stream_mem_set_buffer:
 * @mem: a #CamelStreamMem object
 * @buffer: a memory buffer
 * @len: length of @buffer
 *
 * Set @buffer to be the backing data to the existing #CamelStreamMem, @mem.
 *
 * Note: @buffer will be copied into an internal #GByteArray structure
 * and so may have resource implications to consider.
 **/
void
camel_stream_mem_set_buffer (CamelStreamMem *mem, const char *buffer, size_t len)
{
	GByteArray *ba;

	ba = g_byte_array_new ();
	g_byte_array_append(ba, (const guint8 *)buffer, len);
	camel_stream_mem_set_byte_array(mem, ba);
	mem->owner = TRUE;
}
void
test_message_set_content_simple (CamelMimePart *part,
                                 gint how,
                                 const gchar *type,
                                 const gchar *text,
                                 gint len)
{
	CamelStreamMem *content = NULL;
	CamelDataWrapper *dw;
	static GByteArray *ba;

	switch (how) {
	case 0:
		camel_mime_part_set_content (part, text, len, type);
		break;
	case 1:
		content = (CamelStreamMem *) camel_stream_mem_new_with_buffer (text, len);
		break;
	case 2:
		content = (CamelStreamMem *) camel_stream_mem_new ();
		camel_stream_mem_set_buffer (content, text, len);
		break;
	case 3:
		ba = g_byte_array_new ();
		g_byte_array_append (ba, (guint8 *) text, len);

		content = (CamelStreamMem *) camel_stream_mem_new_with_byte_array (ba);
		ba = NULL;
		break;
	case 4:
		ba = g_byte_array_new ();
		g_byte_array_append (ba, (guint8 *) text, len);

		content = (CamelStreamMem *) camel_stream_mem_new ();
		camel_stream_mem_set_byte_array (content, ba);

		g_object_weak_ref (
			G_OBJECT (content), (GWeakNotify)
			content_weak_notify, ba);
		break;
	}

	if (content != 0) {
		dw = camel_data_wrapper_new ();
		camel_data_wrapper_set_mime_type (dw, type);

		camel_data_wrapper_construct_from_stream_sync (
			dw, (CamelStream *) content, NULL, NULL);
		camel_medium_set_content ((CamelMedium *) part, dw);

		check_unref (content, 2);
		check_unref (dw, 2);
	}
}
static gboolean
data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
                                         CamelStream *stream,
                                         GCancellable *cancellable,
                                         GError **error)
{
	CamelStream *memory_stream;
	gssize bytes_written;

	camel_data_wrapper_lock (
		data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);

	/* Check for cancellation after locking. */
	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
		camel_data_wrapper_unlock (
			data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
		return FALSE;
	}

	if (G_IS_SEEKABLE (stream)) {
		if (!g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, error)) {
			camel_data_wrapper_unlock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
			return FALSE;
		}
	}

	/* Wipe any previous contents from our byte array. */
	g_byte_array_set_size (data_wrapper->priv->byte_array, 0);

	memory_stream = camel_stream_mem_new ();

	/* We retain ownership of the byte array. */
	camel_stream_mem_set_byte_array (
		CAMEL_STREAM_MEM (memory_stream),
		data_wrapper->priv->byte_array);

	/* Transfer incoming contents to our byte array. */
	bytes_written = camel_stream_write_to_stream (
		stream, memory_stream, cancellable, error);

	g_object_unref (memory_stream);

	camel_data_wrapper_unlock (
		data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);

	return (bytes_written >= 0);
}
static gssize
data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
                                   CamelStream *stream,
                                   GCancellable *cancellable,
                                   GError **error)
{
	CamelStream *memory_stream;
	gssize ret;

	camel_data_wrapper_lock (
		data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);

	/* Check for cancellation after locking. */
	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
		camel_data_wrapper_unlock (
			data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
		return -1;
	}

	memory_stream = camel_stream_mem_new ();

	/* We retain ownership of the byte array. */
	camel_stream_mem_set_byte_array (
		CAMEL_STREAM_MEM (memory_stream),
		data_wrapper->priv->byte_array);

	ret = camel_stream_write_to_stream (
		memory_stream, stream, cancellable, error);

	g_object_unref (memory_stream);

	camel_data_wrapper_unlock (
		data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);

	return ret;
}
Beispiel #6
0
static int
pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer, GError **error)
{
	int result, status, errnosav, fds[2], out_fds[2];
	CamelStream *stream;
	char *program;
	pid_t pid;


	if (camel_debug_start ("junk")) {
		int i;

		printf ("pipe_to_sa ");
		for (i = 0; argv[i]; i++)
			printf ("%s ", argv[i]);
		printf ("\n");
		camel_debug_end ();
	}

	program = g_find_program_in_path (argv [0]);
	if (program == NULL) {
		d(printf ("program not found, returning %d\n", rv_err));
		g_set_error (error, EM_JUNK_ERROR, rv_err, _("SpamAssassin not found, code: %d"), rv_err);
		return rv_err;
	}
	g_free (program);

	if (pipe (fds) == -1) {
		errnosav = errno;
		d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
		g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav));
		errno = errnosav;
		return rv_err;
	}

	if (output_buffer && pipe (out_fds) == -1) {
		errnosav = errno;
		d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
		g_set_error (error, EM_JUNK_ERROR, errnosav, _("Failed to create pipe: %s"), strerror (errnosav));
		close (fds [0]);
		close (fds [1]);
		errno = errnosav;
		return rv_err;
	}

	if (!(pid = fork ())) {
		/* child process */
		int maxfd, fd, nullfd;

		nullfd = open ("/dev/null", O_WRONLY);

		if (dup2 (fds[0], STDIN_FILENO) == -1 ||
		    dup2 (nullfd, STDERR_FILENO) == -1 ||
		    (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) ||
		    (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1))
			_exit (rv_err & 0377);
		close (fds [0]);
		if (output_buffer)
			close (out_fds [1]);

		setsid ();

		maxfd = sysconf (_SC_OPEN_MAX);
		for (fd = 3; fd < maxfd; fd++)
			fcntl (fd, F_SETFD, FD_CLOEXEC);

		execvp (argv[0], argv);
		_exit (rv_err & 0377);
	} else if (pid < 0) {
		errnosav = errno;
		close (fds[0]);
		close (fds[1]);
		if (output_buffer) {
			close (out_fds [0]);
			close (out_fds [1]);
		}
		if (errnosav != 0 && errnosav != -1)
			g_set_error (error, EM_JUNK_ERROR, errnosav, _("Error after fork: %s"), strerror (errnosav));
		errno = errnosav;
		return rv_err;
	}

	/* parent process */
	close (fds[0]);
	if (output_buffer)
		close (out_fds [1]);

	if (msg) {
		stream = camel_stream_fs_new_with_fd (fds[1]);

		camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream);
		camel_stream_flush (stream);
		camel_stream_close (stream);
		camel_object_unref (stream);
	} else if (in) {
		camel_write (fds[1], in, strlen (in));
		close (fds[1]);
	}

	if (output_buffer) {
		CamelStreamMem *memstream;

		stream = camel_stream_fs_new_with_fd (out_fds[0]);

		memstream = (CamelStreamMem *) camel_stream_mem_new ();
		camel_stream_mem_set_byte_array (memstream, output_buffer);

		camel_stream_write_to_stream (stream, (CamelStream *) memstream);
		camel_object_unref (stream);
		g_byte_array_append (output_buffer, (unsigned char *)"", 1);

		d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len));
	}

	if (wait_for_termination) {
		int res;

		d(printf ("wait for child %d termination\n", pid));
		result = waitpid (pid, &status, 0);

		d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status)));

		if (result == -1 && errno == EINTR) {
			/* child process is hanging... */
			kill (pid, SIGTERM);
			sleep (1);
			result = waitpid (pid, &status, WNOHANG);
			if (result == 0) {
				/* ...still hanging, set phasers to KILL */
				kill (pid, SIGKILL);
				sleep (1);
				result = waitpid (pid, &status, WNOHANG);
					g_set_error (error, EM_JUNK_ERROR, -2, _("SpamAssassin child process does not respond, killing..."));
			} else
				g_set_error (error, EM_JUNK_ERROR, -3, _("Wait for Spamassassin child process interrupted, terminating..."));
		}

		if (result != -1 && WIFEXITED (status))
			res = WEXITSTATUS (status);
		else
			res = rv_err;

		if (res != 0)
			g_set_error (error, EM_JUNK_ERROR, res, _("Pipe to SpamAssassin failed, error code: %d"), res);

		return res;
	} else
		return 0;
}
static void
attachment_button_expand_drag_data_get_cb (EAttachmentButton *button,
                                           GdkDragContext *context,
                                           GtkSelectionData *selection,
                                           guint info,
                                           guint time)
{
	EAttachmentView *view;
	EAttachment *attachment;
	gchar *mime_type = NULL;

	attachment = e_attachment_button_get_attachment (button);

	if (attachment != NULL)
		mime_type = e_attachment_dup_mime_type (attachment);

	if (mime_type != NULL) {
		gboolean processed = FALSE;
		GdkAtom atom;
		gchar *atom_name;

		atom = gtk_selection_data_get_target (selection);
		atom_name = gdk_atom_name (atom);

		if (g_strcmp0 (atom_name, mime_type) == 0) {
			CamelMimePart *mime_part;

			mime_part = e_attachment_ref_mime_part (attachment);

			if (mime_part != NULL) {
				CamelDataWrapper *wrapper;
				CamelStream *stream;
				GByteArray *buffer;

				buffer = g_byte_array_new ();
				stream = camel_stream_mem_new ();
				camel_stream_mem_set_byte_array (
					CAMEL_STREAM_MEM (stream),
					buffer);
				wrapper = camel_medium_get_content (
					CAMEL_MEDIUM (mime_part));
				camel_data_wrapper_decode_to_stream_sync (
					wrapper, stream, NULL, NULL);
				g_object_unref (stream);

				gtk_selection_data_set (
					selection, atom, 8,
					buffer->data, buffer->len);
				processed = TRUE;

				g_byte_array_free (buffer, TRUE);

				g_object_unref (mime_part);
			}
		}

		g_free (atom_name);
		g_free (mime_type);

		if (processed)
			return;
	}

	view = e_attachment_button_get_view (button);

	e_attachment_view_drag_data_get (
		view, context, selection, info, time);
}
static CamelMimePart *
multipart_signed_get_part (CamelMultipart *multipart,
                           guint index)
{
	CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart;
	CamelDataWrapper *data_wrapper;
	CamelStream *stream;
	GByteArray *byte_array;

	data_wrapper = CAMEL_DATA_WRAPPER (multipart);
	byte_array = camel_data_wrapper_get_byte_array (data_wrapper);

	switch (index) {
	case CAMEL_MULTIPART_SIGNED_CONTENT:
		if (mps->content)
			return mps->content;
		if (mps->contentraw) {
			g_return_val_if_fail (
				G_IS_SEEKABLE (mps->contentraw), NULL);
			stream = g_object_ref (mps->contentraw);
		} else if (mps->start1 == -1
			   && multipart_signed_parse_content (mps) == -1
			   && byte_array->len == 0) {
			g_warning ("Trying to get content on an invalid multipart/signed");
			return NULL;
		} else if (byte_array->len == 0) {
			return NULL;
		} else if (mps->start1 == -1) {
			stream = camel_stream_mem_new ();
			camel_stream_mem_set_byte_array (
				CAMEL_STREAM_MEM (stream), byte_array);
		} else {
			stream = multipart_signed_clip_stream (
				mps, mps->start1, mps->end1);
		}
		g_seekable_seek (
			G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
		mps->content = camel_mime_part_new ();
		camel_data_wrapper_construct_from_stream_sync (
			CAMEL_DATA_WRAPPER (mps->content), stream, NULL, NULL);
		g_object_unref (stream);
		return mps->content;
	case CAMEL_MULTIPART_SIGNED_SIGNATURE:
		if (mps->signature)
			return mps->signature;
		if (mps->start1 == -1
		    && multipart_signed_parse_content (mps) == -1) {
			g_warning ("Trying to get signature on invalid multipart/signed");
			return NULL;
		} else if (byte_array->len == 0) {
			return NULL;
		}
		stream = multipart_signed_clip_stream (
			mps, mps->start2, mps->end2);
		g_seekable_seek (
			G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
		mps->signature = camel_mime_part_new ();
		camel_data_wrapper_construct_from_stream_sync (
			CAMEL_DATA_WRAPPER (mps->signature),
			stream, NULL, NULL);
		g_object_unref (stream);
		return mps->signature;
	default:
		g_warning ("trying to get object out of bounds for multipart");
	}

	return NULL;
}
static gint
multipart_signed_parse_content (CamelMultipartSigned *mps)
{
	CamelMimeParser *cmp;
	CamelMultipart *mp = (CamelMultipart *) mps;
	CamelDataWrapper *data_wrapper;
	GByteArray *byte_array;
	CamelStream *stream;
	const gchar *boundary;
	gchar *buf;
	gsize len;
	gint state;

	boundary = camel_multipart_get_boundary (mp);
	g_return_val_if_fail (boundary != NULL, -1);

	data_wrapper = CAMEL_DATA_WRAPPER (mps);
	byte_array = camel_data_wrapper_get_byte_array (data_wrapper);

	stream = camel_stream_mem_new ();

	/* Do not give the stream ownership of the byte array. */
	camel_stream_mem_set_byte_array (
		CAMEL_STREAM_MEM (stream), byte_array);

	/* This is all seriously complex.
	 * This is so we can parse all cases properly, without altering the content.
	 * All we are doing is finding part offsets. */

	cmp = camel_mime_parser_new ();
	camel_mime_parser_init_with_stream (cmp, stream, NULL);
	camel_mime_parser_push_state (cmp, CAMEL_MIME_PARSER_STATE_MULTIPART, boundary);

	mps->start1 = -1;
	mps->end1 = -1;
	mps->start2 = -1;
	mps->end2 = -1;

	while ((state = camel_mime_parser_step (cmp, &buf, &len)) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
		if (mps->start1 == -1) {
			mps->start1 = camel_mime_parser_tell_start_headers (cmp);
		} else if (mps->start2 == -1) {
			mps->start2 = camel_mime_parser_tell_start_headers (cmp);
			mps->end1 = camel_mime_parser_tell_start_boundary (cmp);
			if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\n')
				mps->end1--;
			if (mps->end1 > mps->start1 && byte_array->data[mps->end1 - 1] == '\r')
				mps->end1--;
		} else {
			g_warning ("multipart/signed has more than 2 parts, remaining parts ignored");
			state = CAMEL_MIME_PARSER_STATE_MULTIPART_END;
			break;
		}

		if (multipart_signed_skip_content (cmp) == -1)
			break;
	}

	if (state == CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
		mps->end2 = camel_mime_parser_tell_start_boundary (cmp);

		camel_multipart_set_preface (mp, camel_mime_parser_preface (cmp));
		camel_multipart_set_postface (mp, camel_mime_parser_postface (cmp));
	}

	g_object_unref (cmp);
	g_object_unref (stream);

	if (mps->end2 == -1 || mps->start2 == -1) {
		if (mps->end1 == -1)
			mps->start1 = -1;

		return -1;
	}

	return 0;
}