evolution-3.6.4/modules/mail/e-mail-attachment-handler.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-attachment-handler.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-attachment-handler.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /*
  2  * e-mail-attachment-handler.c
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 19  *
 20  */
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include <config.h>
 24 #endif
 25 
 26 #include "e-mail-attachment-handler.h"
 27 
 28 #include <glib/gi18n.h>
 29 
 30 #include "libevolution-utils/e-alert-dialog.h"
 31 #include "mail/e-mail-backend.h"
 32 #include "mail/em-composer-utils.h"
 33 
 34 #define E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \
 35 	(G_TYPE_INSTANCE_GET_PRIVATE \
 36 	((obj), E_TYPE_MAIL_ATTACHMENT_HANDLER, EMailAttachmentHandlerPrivate))
 37 
 38 struct _EMailAttachmentHandlerPrivate {
 39 	EShell *shell;
 40 	EMailSession *session;
 41 };
 42 
 43 static gpointer parent_class;
 44 static GType mail_attachment_handler_type;
 45 
 46 static const gchar *ui =
 47 "<ui>"
 48 "  <popup name='context'>"
 49 "    <placeholder name='custom-actions'>"
 50 "      <menuitem action='mail-reply-sender'/>"
 51 "      <menuitem action='mail-reply-all'/>"
 52 "      <menuitem action='mail-forward'/>"
 53 "    </placeholder>"
 54 "  </popup>"
 55 "</ui>";
 56 
 57 /* Note: Do not use the info field. */
 58 static GtkTargetEntry target_table[] = {
 59 	{ (gchar *) "message/rfc822",	0, 0 },
 60 	{ (gchar *) "x-uid-list",	0, 0 }
 61 };
 62 
 63 static CamelMimeMessage *
 64 mail_attachment_handler_get_selected_message (EAttachmentHandler *handler)
 65 {
 66 	EAttachment *attachment;
 67 	EAttachmentView *view;
 68 	CamelMimePart *mime_part;
 69 	CamelDataWrapper *wrapper;
 70 	CamelMimeMessage *message = NULL;
 71 	CamelContentType *content_type;
 72 	GList *selected;
 73 
 74 	view = e_attachment_handler_get_view (handler);
 75 
 76 	selected = e_attachment_view_get_selected_attachments (view);
 77 	g_return_val_if_fail (g_list_length (selected) == 1, NULL);
 78 
 79 	attachment = E_ATTACHMENT (selected->data);
 80 	mime_part = e_attachment_get_mime_part (attachment);
 81 	wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
 82 
 83 	content_type = camel_data_wrapper_get_mime_type_field (wrapper);
 84 	if (content_type && camel_content_type_is (content_type, "message", "rfc822")) {
 85 		CamelDataWrapper *inner;
 86 		CamelContentType *inner_content_type;
 87 
 88 		inner = camel_medium_get_content (CAMEL_MEDIUM (wrapper));
 89 		inner_content_type = camel_data_wrapper_get_mime_type_field (inner);
 90 		if (!camel_content_type_is (inner_content_type, content_type->type, content_type->subtype)) {
 91 			CamelStream *mem;
 92 
 93 			/* Create a message copy in case the inner content-type doesn't match
 94 			   the mime_part's content type, which can happen for multipart/digest,
 95 			   where it confuses the formatter on reply, which skips all rfc822 subparts.
 96 			*/
 97 			mem = camel_stream_mem_new ();
 98 			camel_data_wrapper_write_to_stream_sync (CAMEL_DATA_WRAPPER (wrapper), mem, NULL, NULL);
 99 
100 			g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL);
101 			message = camel_mime_message_new ();
102 			if (!camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (message), mem, NULL, NULL)) {
103 				g_object_unref (message);
104 				message = NULL;
105 			}
106 
107 			g_object_unref (mem);
108 		}
109 	}
110 
111 	if (!message)
112 		message = g_object_ref (wrapper);
113 
114 	g_list_foreach (selected, (GFunc) g_object_unref, NULL);
115 	g_list_free (selected);
116 
117 	return message;
118 }
119 
120 static void
121 mail_attachment_handler_forward (GtkAction *action,
122                                  EAttachmentHandler *handler)
123 {
124 	EMailAttachmentHandlerPrivate *priv;
125 	EShellSettings *shell_settings;
126 	EMailForwardStyle style;
127 	CamelMimeMessage *message;
128 	const gchar *property_name;
129 
130 	priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
131 
132 	message = mail_attachment_handler_get_selected_message (handler);
133 	g_return_if_fail (message != NULL);
134 
135 	property_name = "mail-forward-style";
136 	shell_settings = e_shell_get_shell_settings (priv->shell);
137 	style = e_shell_settings_get_int (shell_settings, property_name);
138 
139 	em_utils_forward_message (
140 		priv->shell, CAMEL_SESSION (priv->session),
141 		message, style, NULL, NULL);
142 
143 	g_object_unref (message);
144 }
145 
146 static void
147 mail_attachment_handler_reply (EAttachmentHandler *handler,
148                                EMailReplyType reply_type)
149 {
150 	EMailAttachmentHandlerPrivate *priv;
151 	EShellSettings *shell_settings;
152 	EMailReplyStyle style;
153 	CamelMimeMessage *message;
154 	const gchar *property_name;
155 
156 	priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
157 
158 	message = mail_attachment_handler_get_selected_message (handler);
159 	g_return_if_fail (message != NULL);
160 
161 	property_name = "mail-reply-style";
162 	shell_settings = e_shell_get_shell_settings (priv->shell);
163 	style = e_shell_settings_get_int (shell_settings, property_name);
164 
165 	em_utils_reply_to_message (
166 		priv->shell, message,
167 		NULL, NULL, reply_type, style, NULL, NULL);
168 
169 	g_object_unref (message);
170 }
171 
172 static void
173 mail_attachment_handler_reply_all (GtkAction *action,
174                                    EAttachmentHandler *handler)
175 {
176 	mail_attachment_handler_reply (handler, E_MAIL_REPLY_TO_ALL);
177 }
178 
179 static void
180 mail_attachment_handler_reply_sender (GtkAction *action,
181                                       EAttachmentHandler *handler)
182 {
183 	mail_attachment_handler_reply (handler, E_MAIL_REPLY_TO_SENDER);
184 }
185 
186 static GtkActionEntry standard_entries[] = {
187 
188 	{ "mail-forward",
189 	  "mail-forward",
190 	  N_("_Forward"),
191 	  NULL,
192 	  NULL,  /* XXX Add a tooltip! */
193 	  G_CALLBACK (mail_attachment_handler_forward) },
194 
195 	{ "mail-reply-all",
196 	  "mail-reply-all",
197 	  N_("Reply to _All"),
198 	  NULL,
199 	  NULL,  /* XXX Add a tooltip! */
200 	  G_CALLBACK (mail_attachment_handler_reply_all) },
201 
202 	{ "mail-reply-sender",
203 	  "mail-reply-sender",
204 	  N_("_Reply to Sender"),
205 	  NULL,
206 	  NULL,  /* XXX Add a tooltip! */
207 	  G_CALLBACK (mail_attachment_handler_reply_sender) }
208 };
209 
210 static void
211 mail_attachment_handler_message_rfc822 (EAttachmentView *view,
212                                         GdkDragContext *drag_context,
213                                         gint x,
214                                         gint y,
215                                         GtkSelectionData *selection_data,
216                                         guint info,
217                                         guint time,
218                                         EAttachmentHandler *handler)
219 {
220 	static GdkAtom atom = GDK_NONE;
221 	EAttachmentStore *store;
222 	EAttachment *attachment;
223 	CamelMimeMessage *message;
224 	CamelDataWrapper *wrapper;
225 	CamelStream *stream;
226 	const gchar *data;
227 	gboolean success = FALSE;
228 	gpointer parent;
229 	gint length;
230 
231 	if (G_UNLIKELY (atom == GDK_NONE))
232 		atom = gdk_atom_intern_static_string ("message/rfc822");
233 
234 	if (gtk_selection_data_get_target (selection_data) != atom)
235 		return;
236 
237 	g_signal_stop_emission_by_name (view, "drag-data-received");
238 
239 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
240 	length = gtk_selection_data_get_length (selection_data);
241 
242 	stream = camel_stream_mem_new ();
243 	camel_stream_write (stream, data, length, NULL, NULL);
244 	g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
245 
246 	message = camel_mime_message_new ();
247 	wrapper = CAMEL_DATA_WRAPPER (message);
248 
249 	if (!camel_data_wrapper_construct_from_stream_sync (
250 		wrapper, stream, NULL, NULL))
251 		goto exit;
252 
253 	store = e_attachment_view_get_store (view);
254 
255 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
256 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
257 
258 	attachment = e_attachment_new_for_message (message);
259 	e_attachment_store_add_attachment (store, attachment);
260 	e_attachment_load_async (
261 		attachment, (GAsyncReadyCallback)
262 		e_attachment_load_handle_error, parent);
263 	g_object_unref (attachment);
264 
265 	success = TRUE;
266 
267 exit:
268 	g_object_unref (message);
269 	g_object_unref (stream);
270 
271 	gtk_drag_finish (drag_context, success, FALSE, time);
272 }
273 
274 static void
275 mail_attachment_handler_x_uid_list (EAttachmentView *view,
276                                     GdkDragContext *drag_context,
277                                     gint x,
278                                     gint y,
279                                     GtkSelectionData *selection_data,
280                                     guint info,
281                                     guint time,
282                                     EAttachmentHandler *handler)
283 {
284 	static GdkAtom atom = GDK_NONE;
285 	EMailAttachmentHandlerPrivate *priv;
286 	CamelDataWrapper *wrapper;
287 	CamelMimeMessage *message;
288 	CamelMultipart *multipart;
289 	CamelMimePart *mime_part;
290 	CamelFolder *folder = NULL;
291 	EAttachment *attachment;
292 	EAttachmentStore *store;
293 	GPtrArray *uids;
294 	const gchar *data;
295 	const gchar *cp, *end;
296 	gchar *description;
297 	gpointer parent;
298 	gint length;
299 	guint ii;
300 	GError *local_error = NULL;
301 
302 	if (G_UNLIKELY (atom == GDK_NONE))
303 		atom = gdk_atom_intern_static_string ("x-uid-list");
304 
305 	if (gtk_selection_data_get_target (selection_data) != atom)
306 		return;
307 
308 	store = e_attachment_view_get_store (view);
309 	priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
310 
311 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
312 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
313 
314 	uids = g_ptr_array_new ();
315 
316 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
317 	length = gtk_selection_data_get_length (selection_data);
318 
319 	/* The UID list is delimited by NUL characters.
320 	 * Brilliant.  So we can't use g_strsplit(). */
321 
322 	cp = data;
323 	end = data + length;
324 
325 	while (cp < end) {
326 		const gchar *start = cp;
327 
328 		while (cp < end && *cp != '\0')
329 			cp++;
330 
331 		/* Skip the first string. */
332 		if (start > data)
333 			g_ptr_array_add (uids, g_strndup (start, cp - start));
334 
335 		cp++;
336 	}
337 
338 	if (uids->len == 0)
339 		goto exit;
340 
341 	/* The first string is the folder URI. */
342 	/* FIXME Not passing a GCancellable here. */
343 	folder = e_mail_session_uri_to_folder_sync (
344 		priv->session, data, 0, NULL, &local_error);
345 	if (folder == NULL)
346 		goto exit;
347 
348 	/* Handle one message. */
349 	if (uids->len == 1) {
350 		const gchar *message_uid;
351 
352 		message_uid = g_ptr_array_index (uids, 0);
353 
354 		/* FIXME Not passing a GCancellable here. */
355 		message = camel_folder_get_message_sync (
356 			folder, message_uid, NULL, &local_error);
357 		if (message == NULL)
358 			goto exit;
359 
360 		attachment = e_attachment_new_for_message (message);
361 		e_attachment_store_add_attachment (store, attachment);
362 		e_attachment_load_async (
363 			attachment, (GAsyncReadyCallback)
364 			e_attachment_load_handle_error, parent);
365 		g_object_unref (attachment);
366 
367 		g_object_unref (message);
368 		goto exit;
369 	}
370 
371 	/* Build a multipart/digest message out of the UIDs. */
372 
373 	multipart = camel_multipart_new ();
374 	wrapper = CAMEL_DATA_WRAPPER (multipart);
375 	camel_data_wrapper_set_mime_type (wrapper, "multipart/digest");
376 	camel_multipart_set_boundary (multipart, NULL);
377 
378 	for (ii = 0; ii < uids->len; ii++) {
379 		/* FIXME Not passing a GCancellable here. */
380 		message = camel_folder_get_message_sync (
381 			folder, uids->pdata[ii], NULL, &local_error);
382 		if (message == NULL) {
383 			g_object_unref (multipart);
384 			goto exit;
385 		}
386 
387 		mime_part = camel_mime_part_new ();
388 		wrapper = CAMEL_DATA_WRAPPER (message);
389 		camel_mime_part_set_disposition (mime_part, "inline");
390 		camel_medium_set_content (
391 			CAMEL_MEDIUM (mime_part), wrapper);
392 		camel_mime_part_set_content_type (mime_part, "message/rfc822");
393 		camel_multipart_add_part (multipart, mime_part);
394 		g_object_unref (mime_part);
395 
396 		g_object_unref (message);
397 	}
398 
399 	mime_part = camel_mime_part_new ();
400 	wrapper = CAMEL_DATA_WRAPPER (multipart);
401 	camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper);
402 
403 	description = g_strdup_printf (
404 		ngettext (
405 			"%d attached message",
406 			"%d attached messages",
407 			uids->len),
408 		uids->len);
409 	camel_mime_part_set_description (mime_part, description);
410 	g_free (description);
411 
412 	attachment = e_attachment_new ();
413 	e_attachment_set_mime_part (attachment, mime_part);
414 	e_attachment_store_add_attachment (store, attachment);
415 	e_attachment_load_async (
416 		attachment, (GAsyncReadyCallback)
417 		e_attachment_load_handle_error, parent);
418 	g_object_unref (attachment);
419 
420 	g_object_unref (mime_part);
421 	g_object_unref (multipart);
422 
423 exit:
424 	if (local_error != NULL) {
425 		const gchar *folder_name = data;
426 
427 		if (folder != NULL)
428 			folder_name = camel_folder_get_display_name (folder);
429 
430 		e_alert_run_dialog_for_args (
431 			parent, "mail-composer:attach-nomessages",
432 			folder_name, local_error->message, NULL);
433 
434 		g_clear_error (&local_error);
435 	}
436 
437 	if (folder != NULL)
438 		g_object_unref (folder);
439 
440 	g_ptr_array_free (uids, TRUE);
441 
442 	g_signal_stop_emission_by_name (view, "drag-data-received");
443 }
444 
445 static void
446 mail_attachment_handler_update_actions (EAttachmentView *view,
447                                         EAttachmentHandler *handler)
448 {
449 	EAttachment *attachment;
450 	CamelMimePart *mime_part;
451 	CamelDataWrapper *wrapper;
452 	GtkActionGroup *action_group;
453 	GList *selected;
454 	gboolean visible = FALSE;
455 
456 	selected = e_attachment_view_get_selected_attachments (view);
457 
458 	if (g_list_length (selected) != 1)
459 		goto exit;
460 
461 	attachment = E_ATTACHMENT (selected->data);
462 
463 	if (e_attachment_get_loading (attachment) ||
464 	    e_attachment_get_saving (attachment))
465 		goto exit;
466 
467 	mime_part = e_attachment_get_mime_part (attachment);
468 
469 	if (!CAMEL_IS_MIME_PART (mime_part))
470 		goto exit;
471 
472 	wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
473 
474 	visible = CAMEL_IS_MIME_MESSAGE (wrapper);
475 
476 exit:
477 	action_group = e_attachment_view_get_action_group (view, "mail");
478 	gtk_action_group_set_visible (action_group, visible);
479 
480 	g_list_foreach (selected, (GFunc) g_object_unref, NULL);
481 	g_list_free (selected);
482 }
483 
484 static void
485 mail_attachment_handler_dispose (GObject *object)
486 {
487 	EMailAttachmentHandlerPrivate *priv;
488 
489 	priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (object);
490 
491 	if (priv->shell != NULL) {
492 		g_object_unref (priv->shell);
493 		priv->shell = NULL;
494 	}
495 
496 	if (priv->session != NULL) {
497 		g_object_unref (priv->session);
498 		priv->session = NULL;
499 	}
500 
501 	/* Chain up to parent's dispose() method. */
502 	G_OBJECT_CLASS (parent_class)->dispose (object);
503 }
504 
505 static void
506 mail_attachment_handler_constructed (GObject *object)
507 {
508 	EMailAttachmentHandlerPrivate *priv;
509 	EShell *shell;
510 	EShellBackend *shell_backend;
511 	EAttachmentHandler *handler;
512 	EAttachmentView *view;
513 	EMailSession *session;
514 	GtkActionGroup *action_group;
515 	GtkUIManager *ui_manager;
516 	GError *error = NULL;
517 
518 	handler = E_ATTACHMENT_HANDLER (object);
519 	priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (object);
520 
521 	/* Chain up to parent's constructed() method. */
522 	G_OBJECT_CLASS (parent_class)->constructed (object);
523 
524 	shell = e_shell_get_default ();
525 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
526 	session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
527 
528 	priv->shell = g_object_ref (shell);
529 	priv->session = g_object_ref (session);
530 
531 	view = e_attachment_handler_get_view (handler);
532 
533 	action_group = e_attachment_view_add_action_group (view, "mail");
534 	gtk_action_group_add_actions (
535 		action_group, standard_entries,
536 		G_N_ELEMENTS (standard_entries), handler);
537 
538 	ui_manager = e_attachment_view_get_ui_manager (view);
539 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
540 
541 	if (error != NULL) {
542 		g_warning ("%s", error->message);
543 		g_error_free (error);
544 	}
545 
546 	g_signal_connect (
547 		view, "update-actions",
548 		G_CALLBACK (mail_attachment_handler_update_actions),
549 		handler);
550 
551 	g_signal_connect (
552 		view, "drag-data-received",
553 		G_CALLBACK (mail_attachment_handler_message_rfc822),
554 		handler);
555 
556 	g_signal_connect (
557 		view, "drag-data-received",
558 		G_CALLBACK (mail_attachment_handler_x_uid_list),
559 		handler);
560 }
561 
562 static GdkDragAction
563 mail_attachment_handler_get_drag_actions (EAttachmentHandler *handler)
564 {
565 	return GDK_ACTION_COPY;
566 }
567 
568 static const GtkTargetEntry *
569 mail_attachment_handler_get_target_table (EAttachmentHandler *handler,
570                                           guint *n_targets)
571 {
572 	if (n_targets != NULL)
573 		*n_targets = G_N_ELEMENTS (target_table);
574 
575 	return target_table;
576 }
577 
578 static void
579 mail_attachment_handler_class_init (EMailAttachmentHandlerClass *class)
580 {
581 	GObjectClass *object_class;
582 	EAttachmentHandlerClass *handler_class;
583 
584 	parent_class = g_type_class_peek_parent (class);
585 	g_type_class_add_private (class, sizeof (EMailAttachmentHandlerPrivate));
586 
587 	object_class = G_OBJECT_CLASS (class);
588 	object_class->dispose = mail_attachment_handler_dispose;
589 	object_class->constructed = mail_attachment_handler_constructed;
590 
591 	handler_class = E_ATTACHMENT_HANDLER_CLASS (class);
592 	handler_class->get_drag_actions = mail_attachment_handler_get_drag_actions;
593 	handler_class->get_target_table = mail_attachment_handler_get_target_table;
594 }
595 
596 static void
597 mail_attachment_handler_init (EMailAttachmentHandler *handler)
598 {
599 	handler->priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
600 }
601 
602 GType
603 e_mail_attachment_handler_get_type (void)
604 {
605 	return mail_attachment_handler_type;
606 }
607 
608 void
609 e_mail_attachment_handler_register_type (GTypeModule *type_module)
610 {
611 	static const GTypeInfo type_info = {
612 		sizeof (EMailAttachmentHandlerClass),
613 		(GBaseInitFunc) NULL,
614 		(GBaseFinalizeFunc) NULL,
615 		(GClassInitFunc) mail_attachment_handler_class_init,
616 		(GClassFinalizeFunc) NULL,
617 		NULL,  /* class_data */
618 		sizeof (EMailAttachmentHandler),
619 		0,     /* n_preallocs */
620 		(GInstanceInitFunc) mail_attachment_handler_init,
621 		NULL   /* value_table */
622 	};
623 
624 	mail_attachment_handler_type = g_type_module_register_type (
625 		type_module, E_TYPE_ATTACHMENT_HANDLER,
626 		"EMailAttachmentHandler", &type_info, 0);
627 }