4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * The #EMailPart is a wrapper around #CamelMimePart which holds additional
22 * information about the mime part, like it's ID, encryption type etc.
24 * Each #EMailPart must have a unique ID. The ID is a dot-separated
25 * hierarchical description of the location of the part within the email
29 #include "evolution-config.h"
31 #include "e-mail-part.h"
35 #include "e-mail-part-attachment.h"
36 #include "e-mail-part-list.h"
38 #define E_MAIL_PART_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE \
40 ((obj), E_TYPE_MAIL_PART, EMailPartPrivate))
42 struct _EMailPartPrivate
{
44 CamelMimePart
*mime_part
;
50 gboolean is_attachment
;
51 gboolean converted_to_utf8
;
57 PROP_CONVERTED_TO_UTF8
,
65 G_DEFINE_TYPE_WITH_CODE (
69 G_IMPLEMENT_INTERFACE (
70 E_TYPE_EXTENSIBLE
, NULL
))
73 mail_part_validity_pair_free (gpointer ptr
)
75 EMailPartValidityPair
*pair
= ptr
;
80 camel_cipher_validity_free (pair
->validity
);
85 mail_part_set_id (EMailPart
*part
,
88 g_return_if_fail (part
->priv
->id
== NULL
);
90 part
->priv
->id
= g_strdup (id
);
94 mail_part_set_mime_part (EMailPart
*part
,
95 CamelMimePart
*mime_part
)
97 g_return_if_fail (part
->priv
->mime_part
== NULL
);
99 /* The CamelMimePart is optional. */
100 if (mime_part
!= NULL
)
101 part
->priv
->mime_part
= g_object_ref (mime_part
);
105 mail_part_set_property (GObject
*object
,
110 switch (property_id
) {
112 e_mail_part_set_cid (
113 E_MAIL_PART (object
),
114 g_value_get_string (value
));
117 case PROP_CONVERTED_TO_UTF8
:
118 e_mail_part_set_converted_to_utf8 (
119 E_MAIL_PART (object
),
120 g_value_get_boolean (value
));
125 E_MAIL_PART (object
),
126 g_value_get_string (value
));
129 case PROP_IS_ATTACHMENT
:
130 e_mail_part_set_is_attachment (
131 E_MAIL_PART (object
),
132 g_value_get_boolean (value
));
136 mail_part_set_mime_part (
137 E_MAIL_PART (object
),
138 g_value_get_object (value
));
142 e_mail_part_set_mime_type (
143 E_MAIL_PART (object
),
144 g_value_get_string (value
));
148 e_mail_part_set_part_list (
149 E_MAIL_PART (object
),
150 g_value_get_object (value
));
154 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
158 mail_part_get_property (GObject
*object
,
163 switch (property_id
) {
167 e_mail_part_get_cid (
168 E_MAIL_PART (object
)));
171 case PROP_CONVERTED_TO_UTF8
:
172 g_value_set_boolean (
174 e_mail_part_get_converted_to_utf8 (
175 E_MAIL_PART (object
)));
182 E_MAIL_PART (object
)));
185 case PROP_IS_ATTACHMENT
:
186 g_value_set_boolean (
188 e_mail_part_get_is_attachment (
189 E_MAIL_PART (object
)));
193 g_value_take_object (
195 e_mail_part_ref_mime_part (
196 E_MAIL_PART (object
)));
202 e_mail_part_get_mime_type (
203 E_MAIL_PART (object
)));
207 g_value_take_object (
209 e_mail_part_ref_part_list (
210 E_MAIL_PART (object
)));
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
218 mail_part_dispose (GObject
*object
)
220 EMailPartPrivate
*priv
;
222 priv
= E_MAIL_PART_GET_PRIVATE (object
);
224 g_weak_ref_set (&priv
->part_list
, NULL
);
226 g_clear_object (&priv
->mime_part
);
228 /* Chain up to parent's dispose() method. */
229 G_OBJECT_CLASS (e_mail_part_parent_class
)->dispose (object
);
233 mail_part_finalize (GObject
*object
)
235 EMailPart
*part
= E_MAIL_PART (object
);
236 EMailPartValidityPair
*pair
;
238 g_free (part
->priv
->id
);
239 g_free (part
->priv
->cid
);
240 g_free (part
->priv
->mime_type
);
242 while ((pair
= g_queue_pop_head (&part
->validities
)) != NULL
)
243 mail_part_validity_pair_free (pair
);
245 /* Chain up to parent's finalize() method. */
246 G_OBJECT_CLASS (e_mail_part_parent_class
)->finalize (object
);
250 mail_part_constructed (GObject
*object
)
252 /* Chain up to parent's constructed() method. */
253 G_OBJECT_CLASS (e_mail_part_parent_class
)->constructed (object
);
255 e_extensible_load_extensions (E_EXTENSIBLE (object
));
259 e_mail_part_class_init (EMailPartClass
*class)
261 GObjectClass
*object_class
;
263 g_type_class_add_private (class, sizeof (EMailPartPrivate
));
265 object_class
= G_OBJECT_CLASS (class);
266 object_class
->set_property
= mail_part_set_property
;
267 object_class
->get_property
= mail_part_get_property
;
268 object_class
->dispose
= mail_part_dispose
;
269 object_class
->finalize
= mail_part_finalize
;
270 object_class
->constructed
= mail_part_constructed
;
272 g_object_class_install_property (
275 g_param_spec_string (
278 "The MIME Content-ID",
281 G_PARAM_STATIC_STRINGS
));
283 g_object_class_install_property (
285 PROP_CONVERTED_TO_UTF8
,
286 g_param_spec_boolean (
289 "Whether the part content was already converted to UTF-8",
292 G_PARAM_STATIC_STRINGS
));
294 g_object_class_install_property (
297 g_param_spec_string (
303 G_PARAM_CONSTRUCT_ONLY
|
304 G_PARAM_STATIC_STRINGS
));
306 g_object_class_install_property (
309 g_param_spec_boolean (
312 "Format the part as an attachment",
316 G_PARAM_STATIC_STRINGS
));
318 g_object_class_install_property (
321 g_param_spec_object (
325 CAMEL_TYPE_MIME_PART
,
327 G_PARAM_CONSTRUCT_ONLY
|
328 G_PARAM_STATIC_STRINGS
));
330 g_object_class_install_property (
333 g_param_spec_string (
339 G_PARAM_STATIC_STRINGS
));
341 g_object_class_install_property (
344 g_param_spec_object (
347 "The part list that owns the part",
348 E_TYPE_MAIL_PART_LIST
,
350 G_PARAM_STATIC_STRINGS
));
354 e_mail_part_init (EMailPart
*part
)
356 part
->priv
= E_MAIL_PART_GET_PRIVATE (part
);
361 * @mime_part: (allow-none) a #CamelMimePart or %NULL
364 * Creates a new #EMailPart for the given @mime_part.
366 * Return value: a new #EMailPart
369 e_mail_part_new (CamelMimePart
*mime_part
,
372 g_return_val_if_fail (id
!= NULL
, NULL
);
374 return g_object_new (
376 "id", id
, "mime-part", mime_part
, NULL
);
380 e_mail_part_get_id (EMailPart
*part
)
382 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
384 return part
->priv
->id
;
388 e_mail_part_get_cid (EMailPart
*part
)
390 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
392 return part
->priv
->cid
;
396 e_mail_part_set_cid (EMailPart
*part
,
399 g_return_if_fail (E_IS_MAIL_PART (part
));
401 g_free (part
->priv
->cid
);
402 part
->priv
->cid
= g_strdup (cid
);
404 g_object_notify (G_OBJECT (part
), "cid");
408 e_mail_part_id_has_prefix (EMailPart
*part
,
411 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
412 g_return_val_if_fail (prefix
!= NULL
, FALSE
);
414 return g_str_has_prefix (part
->priv
->id
, prefix
);
418 e_mail_part_id_has_suffix (EMailPart
*part
,
421 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
422 g_return_val_if_fail (suffix
!= NULL
, FALSE
);
424 return g_str_has_suffix (part
->priv
->id
, suffix
);
428 e_mail_part_id_has_substr (EMailPart
*part
,
431 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
432 g_return_val_if_fail (substr
!= NULL
, FALSE
);
434 return (strstr (part
->priv
->id
, substr
) != NULL
);
438 e_mail_part_ref_mime_part (EMailPart
*part
)
440 CamelMimePart
*mime_part
= NULL
;
442 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
444 if (part
->priv
->mime_part
!= NULL
)
445 mime_part
= g_object_ref (part
->priv
->mime_part
);
451 e_mail_part_get_mime_type (EMailPart
*part
)
453 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
455 return part
->priv
->mime_type
;
459 e_mail_part_set_mime_type (EMailPart
*part
,
460 const gchar
*mime_type
)
462 g_return_if_fail (E_IS_MAIL_PART (part
));
464 if (g_strcmp0 (mime_type
, part
->priv
->mime_type
) == 0)
467 g_free (part
->priv
->mime_type
);
468 part
->priv
->mime_type
= g_strdup (mime_type
);
470 g_object_notify (G_OBJECT (part
), "mime-type");
474 e_mail_part_get_converted_to_utf8 (EMailPart
*part
)
476 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
478 return part
->priv
->converted_to_utf8
;
482 e_mail_part_set_converted_to_utf8 (EMailPart
*part
,
483 gboolean converted_to_utf8
)
485 g_return_if_fail (E_IS_MAIL_PART (part
));
487 if (converted_to_utf8
== part
->priv
->converted_to_utf8
)
490 part
->priv
->converted_to_utf8
= converted_to_utf8
;
492 g_object_notify (G_OBJECT (part
), "converted-to-utf8");
496 e_mail_part_should_show_inline (EMailPart
*part
)
498 CamelMimePart
*mime_part
;
499 const CamelContentDisposition
*disposition
;
500 gboolean res
= FALSE
;
502 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
504 /* Automatically expand attachments that have inline
505 * disposition or the EMailParts have specific
506 * force_inline flag set. */
508 if (part
->force_collapse
)
511 if (part
->force_inline
)
514 if (E_IS_MAIL_PART_ATTACHMENT (part
)) {
515 EMailPartAttachment
*empa
= E_MAIL_PART_ATTACHMENT (part
);
517 if (g_strcmp0 (empa
->snoop_mime_type
, "message/rfc822") == 0)
521 mime_part
= e_mail_part_ref_mime_part (part
);
525 disposition
= camel_mime_part_get_content_disposition (mime_part
);
526 if (disposition
&& disposition
->disposition
&&
527 g_ascii_strncasecmp (disposition
->disposition
, "inline", 6) == 0) {
530 settings
= e_util_ref_settings ("org.gnome.evolution.mail");
531 res
= g_settings_get_boolean (settings
, "display-content-disposition-inline");
532 g_clear_object (&settings
);
535 g_object_unref (mime_part
);
541 e_mail_part_ref_part_list (EMailPart
*part
)
543 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
545 return g_weak_ref_get (&part
->priv
->part_list
);
549 e_mail_part_set_part_list (EMailPart
*part
,
550 EMailPartList
*part_list
)
552 g_return_if_fail (E_IS_MAIL_PART (part
));
554 if (part_list
!= NULL
)
555 g_return_if_fail (E_IS_MAIL_PART_LIST (part_list
));
557 g_weak_ref_set (&part
->priv
->part_list
, part_list
);
559 g_object_notify (G_OBJECT (part
), "part-list");
563 e_mail_part_get_is_attachment (EMailPart
*part
)
565 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
567 return part
->priv
->is_attachment
;
571 e_mail_part_set_is_attachment (EMailPart
*part
,
572 gboolean is_attachment
)
574 g_return_if_fail (E_IS_MAIL_PART (part
));
576 if (is_attachment
== part
->priv
->is_attachment
)
579 part
->priv
->is_attachment
= is_attachment
;
581 g_object_notify (G_OBJECT (part
), "is-attachment");
585 e_mail_part_bind_dom_element (EMailPart
*part
,
588 const gchar
*element_id
)
590 EMailPartClass
*class;
592 g_return_if_fail (E_IS_MAIL_PART (part
));
593 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
594 g_return_if_fail (page_id
!= 0);
595 g_return_if_fail (element_id
&& *element_id
);
597 class = E_MAIL_PART_GET_CLASS (part
);
599 if (class->bind_dom_element
!= NULL
)
600 class->bind_dom_element (part
, web_view
, page_id
, element_id
);
604 e_mail_part_web_view_loaded (EMailPart
*part
,
607 EMailPartClass
*klass
;
609 g_return_if_fail (E_IS_MAIL_PART (part
));
610 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
612 klass
= E_MAIL_PART_GET_CLASS (part
);
614 if (klass
->web_view_loaded
)
615 klass
->web_view_loaded (part
, web_view
);
618 static EMailPartValidityPair
*
619 mail_part_find_validity_pair (EMailPart
*part
,
620 EMailPartValidityFlags validity_type
)
624 head
= g_queue_peek_head_link (&part
->validities
);
626 for (link
= head
; link
!= NULL
; link
= g_list_next (link
)) {
627 EMailPartValidityPair
*pair
= link
->data
;
632 if ((pair
->validity_type
& validity_type
) == validity_type
)
640 * e_mail_part_update_validity:
641 * @part: An #EMailPart
642 * @validity: a #CamelCipherValidity
643 * @validity_type: E_MAIL_PART_VALIDITY_* flags
645 * Updates validity of the @part. When the part already has some validity
646 * set, the new @validity and @validity_type are just appended, preserving
647 * the original validity. Validities of the same type (PGP or S/MIME) are
651 e_mail_part_update_validity (EMailPart
*part
,
652 CamelCipherValidity
*validity
,
653 EMailPartValidityFlags validity_type
)
655 EMailPartValidityPair
*pair
;
656 EMailPartValidityFlags mask
;
658 g_return_if_fail (E_IS_MAIL_PART (part
));
659 g_return_if_fail (validity
!= NULL
);
661 mask
= E_MAIL_PART_VALIDITY_PGP
| E_MAIL_PART_VALIDITY_SMIME
;
663 pair
= mail_part_find_validity_pair (part
, validity_type
& mask
);
665 pair
->validity_type
|= validity_type
;
666 camel_cipher_validity_envelope (pair
->validity
, validity
);
668 pair
= g_new0 (EMailPartValidityPair
, 1);
669 pair
->validity_type
= validity_type
;
670 pair
->validity
= camel_cipher_validity_clone (validity
);
672 g_queue_push_tail (&part
->validities
, pair
);
677 * e_mail_part_get_validity:
678 * @part: An #EMailPart
679 * @validity_type: E_MAIL_PART_VALIDITY_* flags
681 * Returns, validity of @part contains any validity with the same bits
682 * as @validity_type set. It should contain all bits of it.
684 * Returns: a #CamelCipherValidity of the given type, %NULL if not found
688 CamelCipherValidity
*
689 e_mail_part_get_validity (EMailPart
*part
,
690 EMailPartValidityFlags validity_type
)
692 EMailPartValidityPair
*pair
;
694 g_return_val_if_fail (E_IS_MAIL_PART (part
), NULL
);
696 pair
= mail_part_find_validity_pair (part
, validity_type
);
698 return (pair
!= NULL
) ? pair
->validity
: NULL
;
702 e_mail_part_has_validity (EMailPart
*part
)
704 g_return_val_if_fail (E_IS_MAIL_PART (part
), FALSE
);
706 return !g_queue_is_empty (&part
->validities
);
709 EMailPartValidityFlags
710 e_mail_part_get_validity_flags (EMailPart
*part
)
712 EMailPartValidityFlags flags
= 0;
715 g_return_val_if_fail (E_IS_MAIL_PART (part
), 0);
717 head
= g_queue_peek_head_link (&part
->validities
);
719 for (link
= head
; link
!= NULL
; link
= g_list_next (link
)) {
720 EMailPartValidityPair
*pair
= link
->data
;
723 flags
|= pair
->validity_type
;
730 from_matches_signers_alt_emails (CamelInternetAddress
*from_address
,
731 CamelCipherCertInfo
*cinfo
)
734 gboolean matches
= FALSE
;
736 for (props_link
= cinfo
->properties
; props_link
&& !matches
; props_link
= g_slist_next (props_link
)) {
737 const CamelCipherCertInfoProperty
*prop
= props_link
->data
;
739 if (prop
&& g_strcmp0 (prop
->name
, CAMEL_CIPHER_CERT_INFO_PROPERTY_SIGNERS_ALT_EMAILS
) == 0 && prop
->value
) {
740 CamelInternetAddress
*address
;
743 address
= camel_internet_address_new ();
744 count
= camel_address_unformat (CAMEL_ADDRESS (address
), prop
->value
);
745 for (ii
= 0; ii
< count
&& !matches
; ii
++) {
746 const gchar
*email
= NULL
;
748 if (camel_internet_address_get (address
, ii
, NULL
, &email
) && email
&& *email
) {
749 matches
= camel_internet_address_find_address (from_address
, email
, NULL
) >= 0;
752 g_object_unref (address
);
761 e_mail_part_verify_validity_sender (EMailPart
*part
,
762 CamelInternetAddress
*from_address
)
766 g_return_if_fail (E_IS_MAIL_PART (part
));
771 for (link
= g_queue_peek_head_link (&part
->validities
); link
; link
= g_list_next (link
)) {
772 EMailPartValidityPair
*pair
= link
->data
;
774 if (pair
&& pair
->validity
&& !(pair
->validity_type
& E_MAIL_PART_VALIDITY_VERIFIED
)) {
775 pair
->validity_type
|= E_MAIL_PART_VALIDITY_VERIFIED
;
777 if (pair
->validity
->sign
.status
!= CAMEL_CIPHER_VALIDITY_SIGN_NONE
) {
779 gboolean from_matches_signer
= FALSE
;
781 for (link2
= g_queue_peek_head_link (&pair
->validity
->sign
.signers
); link2
&& !from_matches_signer
; link2
= g_list_next (link2
)) {
782 CamelCipherCertInfo
*cinfo
= link2
->data
;
784 if (cinfo
->email
&& *cinfo
->email
) {
785 from_matches_signer
= from_matches_signer
||
786 (from_address
&& camel_internet_address_find_address (from_address
, cinfo
->email
, NULL
) >= 0) ||
787 (from_address
&& from_matches_signers_alt_emails (from_address
, cinfo
));
791 if (!from_matches_signer
)
792 pair
->validity_type
|= E_MAIL_PART_VALIDITY_SENDER_SIGNER_MISMATCH
;