No issues found
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 |
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 }