evolution-3.6.4/em-format/e-mail-formatter.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-formatter.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-formatter.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-formatter.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 
  19 #include "e-mail-formatter.h"
  20 
  21 #include <camel/camel.h>
  22 
  23 #include "e-mail-formatter-extension.h"
  24 #include "e-mail-formatter-utils.h"
  25 #include "e-mail-part.h"
  26 
  27 #include "e-mail-format-extensions.h"
  28 
  29 #include <e-util/e-util.h>
  30 #include <libebackend/libebackend.h>
  31 #include <gdk/gdk.h>
  32 #include <glib/gi18n.h>
  33 
  34 #define d(x)
  35 
  36 struct _EMailFormatterPrivate {
  37 	EMailImageLoadingPolicy image_loading_policy;
  38 
  39 	guint only_local_photos	: 1;
  40 	guint show_sender_photo	: 1;
  41 	guint show_real_date	: 1;
  42         guint animate_images    : 1;
  43 
  44 	gchar *charset;
  45 	gchar *default_charset;
  46 
  47 	GQueue *header_list;
  48 };
  49 
  50 #define E_MAIL_FORMATTER_GET_PRIVATE(obj) \
  51 	(G_TYPE_INSTANCE_GET_PRIVATE \
  52 	((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\
  53 
  54 static gpointer e_mail_formatter_parent_class = 0;
  55 
  56 enum {
  57 	PROP_0,
  58 	PROP_BODY_COLOR,
  59 	PROP_CITATION_COLOR,
  60 	PROP_CONTENT_COLOR,
  61 	PROP_FRAME_COLOR,
  62 	PROP_HEADER_COLOR,
  63 	PROP_TEXT_COLOR,
  64 	PROP_IMAGE_LOADING_POLICY,
  65 	PROP_FORCE_IMAGE_LOADING,
  66 	PROP_MARK_CITATIONS,
  67 	PROP_ONLY_LOCAL_PHOTOS,
  68 	PROP_SHOW_SENDER_PHOTO,
  69 	PROP_SHOW_REAL_DATE,
  70         PROP_ANIMATE_IMAGES,
  71 	PROP_CHARSET,
  72 	PROP_DEFAULT_CHARSET
  73 };
  74 
  75 enum {
  76 	NEED_REDRAW,
  77 	LAST_SIGNAL
  78 };
  79 
  80 static gint signals[LAST_SIGNAL];
  81 
  82 static void
  83 mail_formatter_run (EMailFormatter *formatter,
  84                     EMailFormatterContext *context,
  85                     CamelStream *stream,
  86                     GCancellable *cancellable)
  87 {
  88 	GSList *iter;
  89 	gchar *hdr;
  90 
  91 	hdr = e_mail_formatter_get_html_header (formatter);
  92 	camel_stream_write_string (stream, hdr, cancellable, NULL);
  93 	g_free (hdr);
  94 
  95 	for (iter = context->parts; iter; iter = iter->next) {
  96 
  97 		EMailPart *part;
  98 		gboolean ok;
  99 
 100 		if (g_cancellable_is_cancelled (cancellable))
 101 			break;
 102 
 103 		part = iter->data;
 104 		if (!part)
 105 			continue;
 106 
 107 		if (part->is_hidden && !part->is_error) {
 108 			if (g_str_has_suffix (part->id, ".rfc822")) {
 109 				iter = e_mail_formatter_find_rfc822_end_iter (iter);
 110 			}
 111 
 112 			if (!iter)
 113 				break;
 114 
 115 			continue;
 116 		}
 117 
 118 		/* Force formatting as source if needed */
 119 		if (context->mode != E_MAIL_FORMATTER_MODE_SOURCE) {
 120 
 121 			if (!part->mime_type)
 122 				continue;
 123 
 124 			ok = e_mail_formatter_format_as (
 125 				formatter, context, part, stream,
 126 				part->mime_type, cancellable);
 127 
 128 			/* If the written part was message/rfc822 then
 129 			 * jump to the end of the message, because content
 130 			 * of the whole message has been formatted by
 131 			 * message_rfc822 formatter */
 132 			if (ok && g_str_has_suffix (part->id, ".rfc822")) {
 133 				iter = e_mail_formatter_find_rfc822_end_iter (iter);
 134 
 135 				if (!iter)
 136 					break;
 137 
 138 				continue;
 139 			}
 140 
 141 		} else {
 142 			ok = FALSE;
 143 		}
 144 
 145 		if (!ok) {
 146 			/* We don't want to source these */
 147 			if (g_str_has_suffix (part->id, ".headers") ||
 148 			    g_str_has_suffix (part->id, "attachment-bar"))
 149 				continue;
 150 
 151 			e_mail_formatter_format_as (
 152 				formatter, context, part, stream,
 153 				"application/vnd.evolution.source", cancellable);
 154 
 155 			/* .message is the entire message. There's nothing more
 156 			 * to be written. */
 157 			if (g_strcmp0 (part->id, ".message") == 0)
 158 				break;
 159 
 160 			/* If we just wrote source of a rfc822 message, then jump
 161 			 * behind the message (otherwise source of all parts
 162 			 * would be rendered twice) */
 163 			if (g_str_has_suffix (part->id, ".rfc822")) {
 164 
 165 				do {
 166 					part = iter->data;
 167 					if (part && g_str_has_suffix (part->id, ".rfc822.end"))
 168 						break;
 169 
 170 					iter = iter->next;
 171 				} while (iter);
 172 			}
 173 		}
 174 	}
 175 
 176 	camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
 177 }
 178 
 179 static EMailFormatterContext *
 180 mail_formatter_create_context (EMailFormatter *formatter)
 181 {
 182 	EMailFormatterClass *formatter_class;
 183 
 184 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
 185 
 186 	if (formatter_class->create_context) {
 187 		if (!formatter_class->free_context) {
 188 			g_warning (
 189 				"%s implements create_context() but "
 190 				"does not implement free_context()!",
 191 				G_OBJECT_TYPE_NAME (formatter));
 192 		}
 193 
 194 		return formatter_class->create_context (formatter);
 195 	}
 196 
 197 	return g_new0 (EMailFormatterContext, 1);
 198 }
 199 
 200 static void
 201 mail_formatter_free_context (EMailFormatter *formatter,
 202                              EMailFormatterContext *context)
 203 {
 204 	EMailFormatterClass *formatter_class;
 205 
 206 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
 207 
 208 	if (formatter_class->free_context) {
 209 		formatter_class->free_context (formatter, context);
 210 	} else {
 211 		g_free (context);
 212 	}
 213 }
 214 
 215 static void
 216 mail_formatter_set_style (EMailFormatter *formatter,
 217                           GtkStyle *style,
 218                           GtkStateType state)
 219 {
 220 	GdkColor *color;
 221 	EMailFormatterColorType type;
 222 
 223 	g_object_freeze_notify (G_OBJECT (formatter));
 224 
 225 	color = &style->bg[state];
 226 	type = E_MAIL_FORMATTER_COLOR_BODY;
 227 	e_mail_formatter_set_color (formatter, type, color);
 228 
 229 	color = &style->base[GTK_STATE_NORMAL];
 230 	type = E_MAIL_FORMATTER_COLOR_CONTENT;
 231 	e_mail_formatter_set_color  (formatter, type, color);
 232 
 233 	color = &style->dark[state];
 234 	type = E_MAIL_FORMATTER_COLOR_FRAME;
 235 	e_mail_formatter_set_color  (formatter, type, color);
 236 
 237 	color = &style->fg[state];
 238 	type = E_MAIL_FORMATTER_COLOR_HEADER;
 239 	e_mail_formatter_set_color  (formatter, type, color);
 240 
 241 	color = &style->text[state];
 242 	type = E_MAIL_FORMATTER_COLOR_TEXT;
 243 	e_mail_formatter_set_color  (formatter, type, color);
 244 
 245 	g_object_thaw_notify (G_OBJECT (formatter));
 246 }
 247 
 248 static void
 249 e_mail_formatter_set_property (GObject *object,
 250                                guint property_id,
 251                                const GValue *value,
 252                                GParamSpec *pspec)
 253 {
 254 	switch (property_id) {
 255 		case PROP_BODY_COLOR:
 256 			e_mail_formatter_set_color (
 257 				E_MAIL_FORMATTER (object),
 258 				E_MAIL_FORMATTER_COLOR_BODY,
 259 				g_value_get_boxed (value));
 260 			return;
 261 
 262 		case PROP_CITATION_COLOR:
 263 			e_mail_formatter_set_color (
 264 				E_MAIL_FORMATTER (object),
 265 				E_MAIL_FORMATTER_COLOR_CITATION,
 266 				g_value_get_boxed (value));
 267 			return;
 268 
 269 		case PROP_CONTENT_COLOR:
 270 			e_mail_formatter_set_color (
 271 				E_MAIL_FORMATTER (object),
 272 				E_MAIL_FORMATTER_COLOR_CONTENT,
 273 				g_value_get_boxed (value));
 274 			return;
 275 
 276 		case PROP_FRAME_COLOR:
 277 			e_mail_formatter_set_color (
 278 				E_MAIL_FORMATTER (object),
 279 				E_MAIL_FORMATTER_COLOR_FRAME,
 280 				g_value_get_boxed (value));
 281 			return;
 282 
 283 		case PROP_HEADER_COLOR:
 284 			e_mail_formatter_set_color (
 285 				E_MAIL_FORMATTER (object),
 286 				E_MAIL_FORMATTER_COLOR_HEADER,
 287 				g_value_get_boxed (value));
 288 			return;
 289 
 290 		case PROP_IMAGE_LOADING_POLICY:
 291 			e_mail_formatter_set_image_loading_policy (
 292 				E_MAIL_FORMATTER (object),
 293 				g_value_get_int (value));
 294 			return;
 295 
 296 		case PROP_MARK_CITATIONS:
 297 			e_mail_formatter_set_mark_citations (
 298 				E_MAIL_FORMATTER (object),
 299 				g_value_get_boolean (value));
 300 			return;
 301 
 302 		case PROP_ONLY_LOCAL_PHOTOS:
 303 			e_mail_formatter_set_only_local_photos (
 304 				E_MAIL_FORMATTER (object),
 305 				g_value_get_boolean (value));
 306 			return;
 307 
 308 		case PROP_SHOW_SENDER_PHOTO:
 309 			e_mail_formatter_set_show_sender_photo (
 310 				E_MAIL_FORMATTER (object),
 311 				g_value_get_boolean (value));
 312 			return;
 313 
 314 		case PROP_SHOW_REAL_DATE:
 315 			e_mail_formatter_set_show_real_date (
 316 				E_MAIL_FORMATTER (object),
 317 				g_value_get_boolean (value));
 318 			return;
 319 
 320 		case PROP_TEXT_COLOR:
 321 			e_mail_formatter_set_color (
 322 				E_MAIL_FORMATTER (object),
 323 				E_MAIL_FORMATTER_COLOR_TEXT,
 324 				g_value_get_boxed (value));
 325 			return;
 326 
 327 		case PROP_ANIMATE_IMAGES:
 328 			e_mail_formatter_set_animate_images (
 329 				E_MAIL_FORMATTER (object),
 330 				g_value_get_boolean (value));
 331 			return;
 332 
 333 		case PROP_CHARSET:
 334 			e_mail_formatter_set_charset (
 335 				E_MAIL_FORMATTER (object),
 336 				g_value_get_string (value));
 337 			return;
 338 
 339 		case PROP_DEFAULT_CHARSET:
 340 			e_mail_formatter_set_default_charset (
 341 				E_MAIL_FORMATTER (object),
 342 				g_value_get_string (value));
 343 			return;
 344 	}
 345 
 346 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 347 }
 348 
 349 static void
 350 e_mail_formatter_get_property (GObject *object,
 351                              guint property_id,
 352                              GValue *value,
 353                              GParamSpec *pspec)
 354 {
 355 	switch (property_id) {
 356 		case PROP_BODY_COLOR:
 357 			g_value_set_boxed (
 358 				value,
 359 				e_mail_formatter_get_color (
 360 				E_MAIL_FORMATTER (object),
 361 				E_MAIL_FORMATTER_COLOR_BODY));
 362 			return;
 363 
 364 		case PROP_CITATION_COLOR:
 365 			g_value_set_boxed (
 366 				value,
 367 				e_mail_formatter_get_color (
 368 				E_MAIL_FORMATTER (object),
 369 				E_MAIL_FORMATTER_COLOR_CITATION));
 370 			return;
 371 
 372 		case PROP_CONTENT_COLOR:
 373 			g_value_set_boxed (
 374 				value,
 375 				e_mail_formatter_get_color (
 376 				E_MAIL_FORMATTER (object),
 377 				E_MAIL_FORMATTER_COLOR_CONTENT));
 378 			return;
 379 
 380 		case PROP_FRAME_COLOR:
 381 			g_value_set_boxed (
 382 				value,
 383 				e_mail_formatter_get_color (
 384 				E_MAIL_FORMATTER (object),
 385 				E_MAIL_FORMATTER_COLOR_FRAME));
 386 			return;
 387 
 388 		case PROP_HEADER_COLOR:
 389 			g_value_set_boxed (
 390 				value,
 391 				e_mail_formatter_get_color (
 392 				E_MAIL_FORMATTER (object),
 393 				E_MAIL_FORMATTER_COLOR_HEADER));
 394 			return;
 395 
 396 		case PROP_IMAGE_LOADING_POLICY:
 397 			g_value_set_int (
 398 				value,
 399 				e_mail_formatter_get_image_loading_policy (
 400 				E_MAIL_FORMATTER (object)));
 401 			return;
 402 
 403 		case PROP_MARK_CITATIONS:
 404 			g_value_set_boolean (
 405 				value,
 406 				e_mail_formatter_get_mark_citations (
 407 				E_MAIL_FORMATTER (object)));
 408 			return;
 409 
 410 		case PROP_ONLY_LOCAL_PHOTOS:
 411 			g_value_set_boolean (
 412 				value,
 413 				e_mail_formatter_get_only_local_photos (
 414 				E_MAIL_FORMATTER (object)));
 415 			return;
 416 
 417 		case PROP_SHOW_SENDER_PHOTO:
 418 			g_value_set_boolean (
 419 				value,
 420 				e_mail_formatter_get_show_sender_photo (
 421 				E_MAIL_FORMATTER (object)));
 422 			return;
 423 
 424 		case PROP_SHOW_REAL_DATE:
 425 			g_value_set_boolean (
 426 				value,
 427 				e_mail_formatter_get_show_real_date (
 428 				E_MAIL_FORMATTER (object)));
 429 			return;
 430 
 431 		case PROP_TEXT_COLOR:
 432 			g_value_set_boxed (
 433 				value,
 434 				e_mail_formatter_get_color (
 435 				E_MAIL_FORMATTER (object),
 436 				E_MAIL_FORMATTER_COLOR_TEXT));
 437 			return;
 438 
 439 		case PROP_ANIMATE_IMAGES:
 440 			g_value_set_boolean (
 441 				value,
 442 				e_mail_formatter_get_animate_images (
 443 				E_MAIL_FORMATTER (object)));
 444 			return;
 445 
 446 		case PROP_CHARSET:
 447 			g_value_set_string (
 448 				value,
 449 				e_mail_formatter_get_charset (
 450 				E_MAIL_FORMATTER (object)));
 451 			return;
 452 
 453 		case PROP_DEFAULT_CHARSET:
 454 			g_value_set_string (
 455 				value,
 456 				e_mail_formatter_get_default_charset (
 457 				E_MAIL_FORMATTER (object)));
 458 			return;
 459 	}
 460 
 461 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 462 }
 463 
 464 static void
 465 e_mail_formatter_init (EMailFormatter *formatter)
 466 {
 467 	formatter->priv = E_MAIL_FORMATTER_GET_PRIVATE (formatter);
 468 
 469 	formatter->priv->header_list = g_queue_new ();
 470 	e_mail_formatter_set_default_headers (formatter);
 471 }
 472 
 473 static void
 474 e_mail_formatter_finalize (GObject *object)
 475 {
 476 	EMailFormatterPrivate *priv;
 477 
 478 	priv = E_MAIL_FORMATTER (object)->priv;
 479 
 480 	if (priv->charset) {
 481 		g_free (priv->charset);
 482 		priv->charset = NULL;
 483 	}
 484 
 485 	if (priv->default_charset) {
 486 		g_free (priv->default_charset);
 487 		priv->default_charset = NULL;
 488 	}
 489 
 490 	if (priv->header_list) {
 491 		e_mail_formatter_clear_headers (E_MAIL_FORMATTER (object));
 492 		g_queue_free (priv->header_list);
 493 		priv->header_list = NULL;
 494 	}
 495 
 496 	/* Chain up to parent's finalize() */
 497 	G_OBJECT_CLASS (e_mail_formatter_parent_class)->finalize (object);
 498 }
 499 
 500 static void
 501 e_mail_formatter_base_init (EMailFormatterClass *class)
 502 {
 503 	class->extension_registry = g_object_new (
 504 		E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL);
 505 
 506 	e_mail_formatter_internal_extensions_load (
 507 			E_MAIL_EXTENSION_REGISTRY (class->extension_registry));
 508 
 509 	e_extensible_load_extensions (
 510 		E_EXTENSIBLE (class->extension_registry));
 511 
 512 	class->text_html_flags =
 513 		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
 514 		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
 515 		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
 516 		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES |
 517 		CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
 518 }
 519 
 520 static void
 521 e_mail_formatter_base_finalize (EMailFormatterClass *class)
 522 {
 523 	g_object_unref (class->extension_registry);
 524 }
 525 
 526 static void
 527 e_mail_formatter_constructed (GObject *object)
 528 {
 529 	G_OBJECT_CLASS (e_mail_formatter_parent_class)->constructed (object);
 530 
 531 	e_extensible_load_extensions (E_EXTENSIBLE (object));
 532 }
 533 
 534 static void
 535 e_mail_formatter_class_init (EMailFormatterClass *class)
 536 {
 537 	GObjectClass *object_class;
 538 	GdkColor *color;
 539 
 540 	e_mail_formatter_parent_class = g_type_class_peek_parent (class);
 541 	g_type_class_add_private (class, sizeof (EMailFormatterPrivate));
 542 
 543 	class->run = mail_formatter_run;
 544 
 545 	/* EMailFormatter calls these directly */
 546 	class->create_context = NULL;
 547 	class->free_context = NULL;
 548 	class->set_style = mail_formatter_set_style;
 549 
 550 	color = &class->colors[E_MAIL_FORMATTER_COLOR_BODY];
 551 	gdk_color_parse ("#eeeeee", color);
 552 
 553 	color = &class->colors[E_MAIL_FORMATTER_COLOR_CONTENT];
 554 	gdk_color_parse ("#ffffff", color);
 555 
 556 	color = &class->colors[E_MAIL_FORMATTER_COLOR_FRAME];
 557 	gdk_color_parse ("#3f3f3f", color);
 558 
 559 	color = &class->colors[E_MAIL_FORMATTER_COLOR_HEADER];
 560 	gdk_color_parse ("#eeeeee", color);
 561 
 562 	color = &class->colors[E_MAIL_FORMATTER_COLOR_TEXT];
 563 	gdk_color_parse ("#000000", color);
 564 
 565 	object_class = G_OBJECT_CLASS (class);
 566 	object_class->constructed = e_mail_formatter_constructed;
 567 	object_class->get_property = e_mail_formatter_get_property;
 568 	object_class->set_property = e_mail_formatter_set_property;
 569 	object_class->finalize = e_mail_formatter_finalize;
 570 
 571 	g_object_class_install_property (
 572 		object_class,
 573 		PROP_BODY_COLOR,
 574 		g_param_spec_boxed (
 575 			"body-color",
 576 			"Body Color",
 577 			NULL,
 578 			GDK_TYPE_COLOR,
 579 			G_PARAM_READWRITE));
 580 
 581 	g_object_class_install_property (
 582 		object_class,
 583 		PROP_CITATION_COLOR,
 584 		g_param_spec_boxed (
 585 			"citation-color",
 586 			"Citation Color",
 587 			NULL,
 588 			GDK_TYPE_COLOR,
 589 			G_PARAM_READWRITE));
 590 
 591 	g_object_class_install_property (
 592 		object_class,
 593 		PROP_CONTENT_COLOR,
 594 		g_param_spec_boxed (
 595 			"content-color",
 596 			"Content Color",
 597 			NULL,
 598 			GDK_TYPE_COLOR,
 599 			G_PARAM_READWRITE));
 600 
 601 	g_object_class_install_property (
 602 		object_class,
 603 		PROP_FRAME_COLOR,
 604 		g_param_spec_boxed (
 605 			"frame-color",
 606 			"Frame Color",
 607 			NULL,
 608 			GDK_TYPE_COLOR,
 609 			G_PARAM_READWRITE));
 610 
 611 	g_object_class_install_property (
 612 		object_class,
 613 		PROP_HEADER_COLOR,
 614 		g_param_spec_boxed (
 615 			"header-color",
 616 			"Header Color",
 617 			NULL,
 618 			GDK_TYPE_COLOR,
 619 			G_PARAM_READWRITE));
 620 
 621 	/* FIXME Make this a proper enum property. */
 622 	g_object_class_install_property (
 623 		object_class,
 624 		PROP_IMAGE_LOADING_POLICY,
 625 		g_param_spec_int (
 626 			"image-loading-policy",
 627 			"Image Loading Policy",
 628 			NULL,
 629 			E_MAIL_IMAGE_LOADING_POLICY_NEVER,
 630 			E_MAIL_IMAGE_LOADING_POLICY_ALWAYS,
 631 			E_MAIL_IMAGE_LOADING_POLICY_NEVER,
 632 			G_PARAM_READWRITE));
 633 
 634 	g_object_class_install_property (
 635 		object_class,
 636 		PROP_MARK_CITATIONS,
 637 		g_param_spec_boolean (
 638 			"mark-citations",
 639 			"Mark Citations",
 640 			NULL,
 641 			TRUE,
 642 			G_PARAM_READWRITE));
 643 
 644 	g_object_class_install_property (
 645 		object_class,
 646 		PROP_ONLY_LOCAL_PHOTOS,
 647 		g_param_spec_boolean (
 648 			"only-local-photos",
 649 			"Only Local Photos",
 650 			NULL,
 651 			TRUE,
 652 			G_PARAM_READWRITE |
 653 			G_PARAM_CONSTRUCT));
 654 
 655 	g_object_class_install_property (
 656 		object_class,
 657 		PROP_SHOW_SENDER_PHOTO,
 658 		g_param_spec_boolean (
 659 			"show-sender-photo",
 660 			"Show Sender Photo",
 661 			NULL,
 662 			FALSE,
 663 			G_PARAM_READWRITE |
 664 			G_PARAM_CONSTRUCT));
 665 
 666 	g_object_class_install_property (
 667 		object_class,
 668 		PROP_SHOW_REAL_DATE,
 669 		g_param_spec_boolean (
 670 			"show-real-date",
 671 			"Show real Date header value",
 672 			NULL,
 673 			TRUE,
 674 			G_PARAM_READWRITE |
 675 			G_PARAM_CONSTRUCT));
 676 
 677 	g_object_class_install_property (
 678 		object_class,
 679 		PROP_TEXT_COLOR,
 680 		g_param_spec_boxed (
 681 			"text-color",
 682 			"Text Color",
 683 			NULL,
 684 			GDK_TYPE_COLOR,
 685 			G_PARAM_READWRITE));
 686 
 687 	g_object_class_install_property (
 688 		object_class,
 689 		PROP_ANIMATE_IMAGES,
 690 		g_param_spec_boolean (
 691 			"animate-images",
 692 			"Animate images",
 693 			NULL,
 694 			FALSE,
 695 			G_PARAM_READWRITE));
 696 
 697 	g_object_class_install_property (
 698 		object_class,
 699 		PROP_CHARSET,
 700 		g_param_spec_string (
 701 			"charset",
 702 			NULL,
 703 			NULL,
 704 			NULL,
 705 			G_PARAM_READWRITE));
 706 
 707 	g_object_class_install_property (
 708 		object_class,
 709 		PROP_DEFAULT_CHARSET,
 710 		g_param_spec_string (
 711 			"default-charset",
 712 			NULL,
 713 			NULL,
 714 			NULL,
 715 			G_PARAM_READWRITE));
 716 
 717 	signals[NEED_REDRAW] = g_signal_new (
 718 				"need-redraw",
 719 				E_TYPE_MAIL_FORMATTER,
 720 				G_SIGNAL_RUN_FIRST,
 721 				G_STRUCT_OFFSET (EMailFormatterClass, need_redraw),
 722 				NULL,
 723 				NULL,
 724 				g_cclosure_marshal_VOID__VOID,
 725 				G_TYPE_NONE,  0, NULL);
 726 }
 727 
 728 static void
 729 e_mail_formatter_extensible_interface_init (EExtensibleInterface *interface)
 730 {
 731 
 732 }
 733 
 734 EMailFormatter *
 735 e_mail_formatter_new (void)
 736 {
 737 	return g_object_new (E_TYPE_MAIL_FORMATTER, NULL);
 738 }
 739 
 740 GType
 741 e_mail_formatter_get_type (void)
 742 {
 743 	static GType type = 0;
 744 
 745 	if (G_UNLIKELY (type == 0)) {
 746 		const GTypeInfo type_info = {
 747 			sizeof (EMailFormatterClass),
 748 			(GBaseInitFunc) e_mail_formatter_base_init,
 749 			(GBaseFinalizeFunc) e_mail_formatter_base_finalize,
 750 			(GClassInitFunc) e_mail_formatter_class_init,
 751 			(GClassFinalizeFunc) NULL,
 752 			NULL,	/* class_data */
 753 			sizeof (EMailFormatter),
 754 			0,	/* n_preallocs */
 755 			(GInstanceInitFunc) e_mail_formatter_init,
 756 			NULL	/* value_table */
 757 		};
 758 
 759 		const GInterfaceInfo e_extensible_interface_info = {
 760 			(GInterfaceInitFunc) e_mail_formatter_extensible_interface_init
 761 		};
 762 
 763 		type = g_type_register_static (
 764 			G_TYPE_OBJECT,
 765 			"EMailFormatter", &type_info, 0);
 766 
 767 		g_type_add_interface_static (
 768 			type, E_TYPE_EXTENSIBLE, &e_extensible_interface_info);
 769 	}
 770 
 771 	return type;
 772 }
 773 
 774 void
 775 e_mail_formatter_format_sync (EMailFormatter *formatter,
 776                               EMailPartList *parts,
 777                               CamelStream *stream,
 778                               guint32 flags,
 779                               EMailFormatterMode mode,
 780                               GCancellable *cancellable)
 781 {
 782 	EMailFormatterContext *context;
 783 	EMailFormatterClass *formatter_class;
 784 
 785 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
 786 	g_return_if_fail (CAMEL_IS_STREAM (stream));
 787 
 788 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
 789 	g_return_if_fail (formatter_class->run != NULL);
 790 
 791 	context = mail_formatter_create_context (formatter);
 792 	context->message = parts->message;
 793 	context->folder = parts->folder;
 794 	context->message_uid = parts->message_uid;
 795 	context->parts = parts->list;
 796 	context->flags = flags;
 797 	context->mode = mode;
 798 
 799 	formatter_class->run (
 800 		formatter, context, stream, cancellable);
 801 
 802 	mail_formatter_free_context (formatter, context);
 803 }
 804 
 805 static void
 806 mail_format_async_prepare (GSimpleAsyncResult *result,
 807                            GObject *object,
 808                            GCancellable *cancellable)
 809 {
 810 	EMailFormatterContext *context;
 811 	EMailFormatterClass *formatter_class;
 812 	CamelStream *stream;
 813 
 814 	context = g_object_get_data (G_OBJECT (result), "context");
 815 	stream = g_object_get_data (G_OBJECT (result), "stream");
 816 
 817 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (object);
 818 	formatter_class->run (
 819 		E_MAIL_FORMATTER (object), context, stream, cancellable);
 820 }
 821 
 822 void
 823 e_mail_formatter_format (EMailFormatter *formatter,
 824                          EMailPartList *parts,
 825                          CamelStream *stream,
 826                          guint32 flags,
 827                          EMailFormatterMode mode,
 828                          GAsyncReadyCallback callback,
 829                          GCancellable *cancellable,
 830                          gpointer user_data)
 831 {
 832 	GSimpleAsyncResult *simple;
 833 	EMailFormatterContext *context;
 834 	EMailFormatterClass *formatter_class;
 835 
 836 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
 837 	g_return_if_fail (CAMEL_IS_STREAM (stream));
 838 
 839 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
 840 	g_return_if_fail (formatter_class->run != NULL);
 841 
 842 	simple = g_simple_async_result_new (
 843 		G_OBJECT (formatter), callback,
 844 		user_data, e_mail_formatter_format);
 845 
 846 	g_simple_async_result_set_check_cancellable (simple, cancellable);
 847 
 848 	if (!parts && callback) {
 849 		callback (G_OBJECT (formatter), G_ASYNC_RESULT (simple), user_data);
 850 		g_object_unref (simple);
 851 		return;
 852 	}
 853 
 854 	context = mail_formatter_create_context (formatter);
 855 	context->message = g_object_ref (parts->message);
 856 	context->folder = g_object_ref (parts->folder);
 857 	context->message_uid = g_strdup (parts->message_uid);
 858 	context->parts = g_slist_copy (parts->list);
 859 	g_slist_foreach (context->parts, (GFunc) e_mail_part_ref, NULL);
 860 	context->flags = flags;
 861 	context->mode = mode;
 862 
 863 	g_object_set_data (G_OBJECT (simple), "context", context);
 864 	g_object_set_data (G_OBJECT (simple), "stream", stream);
 865 
 866 	g_simple_async_result_run_in_thread (
 867 		simple, mail_format_async_prepare,
 868 		G_PRIORITY_DEFAULT, cancellable);
 869 
 870 	g_object_unref (simple);
 871 }
 872 
 873 CamelStream *
 874 e_mail_formatter_format_finished (EMailFormatter *formatter,
 875                                   GAsyncResult *result,
 876                                   GError *error)
 877 {
 878 	EMailFormatterContext *context;
 879 
 880 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
 881 	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
 882 
 883 	context = g_object_get_data (G_OBJECT (result), "context");
 884 
 885 	g_free (context->message_uid);
 886 	g_object_unref (context->message);
 887 	g_object_unref (context->folder);
 888 	g_slist_foreach (context->parts, (GFunc) e_mail_part_unref, NULL);
 889 	g_slist_free (context->parts);
 890 	mail_formatter_free_context (formatter, context);
 891 
 892 	return g_object_get_data (G_OBJECT (result), "stream");
 893 }
 894 
 895 /**
 896  * e_mail_formatter_format_as:
 897  * @formatter: an #EMailFormatter
 898  * @context: an #EMailFormatterContext
 899  * @part: an #EMailPart
 900  * @stream: a #CamelStream
 901  * @as_mime_type: (allow-none) mime-type to use for formatting, or %NULL
 902  * @cancellable: (allow-none) an optional #GCancellable
 903  *
 904  * Formats given @part using a @formatter extension for given mime type. When
 905  * the mime type is %NULL, the function will try to lookup the best formatter
 906  * for given @part by it's default mime type.
 907  *
 908  * Return Value: %TRUE on success, %FALSE when no suitable formatter is found or
 909  * when it fails to format the part. 
 910  */
 911 gboolean
 912 e_mail_formatter_format_as (EMailFormatter *formatter,
 913                             EMailFormatterContext *context,
 914                             EMailPart *part,
 915                             CamelStream *stream,
 916                             const gchar *as_mime_type,
 917                             GCancellable *cancellable)
 918 {
 919 	EMailExtensionRegistry *reg;
 920 	GQueue *formatters;
 921 	GList *iter;
 922 	gboolean ok;
 923 	d (
 924 		gint _call_i;
 925 		static gint _call = 0;
 926 		G_LOCK_DEFINE_STATIC (_call);
 927 		G_LOCK (_call);
 928 		_call++;
 929 		_call_i = _call;
 930 		G_UNLOCK (_call)
 931 	);
 932 
 933 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
 934 	g_return_val_if_fail (part, FALSE);
 935 	g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
 936 
 937 	if (!as_mime_type || !*as_mime_type)
 938 		as_mime_type = part->mime_type;
 939 
 940 	if (!as_mime_type || !*as_mime_type)
 941 		return FALSE;
 942 
 943 	reg = e_mail_formatter_get_extension_registry (formatter);
 944 	formatters = e_mail_extension_registry_get_for_mime_type (
 945 			reg, as_mime_type);
 946 	if (!formatters) {
 947 		formatters = e_mail_extension_registry_get_fallback (
 948 			reg, as_mime_type);
 949 	}
 950 
 951 	ok = FALSE;
 952 
 953 	d (
 954 		printf ("(%d) Formatting for part %s of type %s (found %d formatters)\n",
 955 		_call_i, part->id, as_mime_type,
 956 		formatters ? g_queue_get_length (formatters) : 0));
 957 
 958 	if (formatters) {
 959 		for (iter = formatters->head; iter; iter = iter->next) {
 960 
 961 			EMailFormatterExtension *extension;
 962 
 963 			extension = iter->data;
 964 			if (!extension)
 965 				continue;
 966 
 967 			ok = e_mail_formatter_extension_format (
 968 					extension, formatter, context,
 969 					part, stream, cancellable);
 970 
 971 			d (
 972 				printf (
 973 					"\t(%d) trying %s...%s\n", _call_i,
 974 					G_OBJECT_TYPE_NAME (extension),
 975 					ok ? "OK" : "failed"));
 976 
 977 			if (ok)
 978 				break;
 979 		}
 980 	}
 981 
 982 	return ok;
 983 }
 984 
 985 /**
 986  * em_format_format_text:
 987  * @part: an #EMailPart to decode
 988  * @formatter: an #EMailFormatter
 989  * @stream: Where to write the converted text
 990  * @cancellable: optional #GCancellable object, or %NULL
 991  *
 992  * Decode/output a part's content to @stream.
 993  **/
 994 void
 995 e_mail_formatter_format_text (EMailFormatter *formatter,
 996                               EMailPart *part,
 997                               CamelStream *stream,
 998                               GCancellable *cancellable)
 999 {
1000 	CamelStream *filter_stream;
1001 	CamelMimeFilter *filter;
1002 	const gchar *charset = NULL;
1003 	CamelMimeFilterWindows *windows = NULL;
1004 	CamelStream *mem_stream = NULL;
1005 	CamelDataWrapper *dw;
1006 
1007 	if (g_cancellable_is_cancelled (cancellable))
1008 		return;
1009 
1010 	dw = CAMEL_DATA_WRAPPER (part->part);
1011 
1012 	if (formatter->priv->charset) {
1013 		charset = formatter->priv->charset;
1014 	} else if (dw->mime_type
1015 		   && (charset = camel_content_type_param (dw->mime_type, "charset"))
1016 		   && g_ascii_strncasecmp (charset, "iso-8859-", 9) == 0) {
1017 		CamelStream *null;
1018 
1019 		/* Since a few Windows mailers like to claim they sent
1020 		 * out iso-8859-# encoded text when they really sent
1021 		 * out windows-cp125#, do some simple sanity checking
1022 		 * before we move on... */
1023 
1024 		null = camel_stream_null_new ();
1025 		filter_stream = camel_stream_filter_new (null);
1026 		g_object_unref (null);
1027 
1028 		windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset);
1029 		camel_stream_filter_add (
1030 			CAMEL_STREAM_FILTER (filter_stream),
1031 			CAMEL_MIME_FILTER (windows));
1032 
1033 		camel_data_wrapper_decode_to_stream_sync (
1034 			dw, (CamelStream *) filter_stream, cancellable, NULL);
1035 		camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
1036 		g_object_unref (filter_stream);
1037 
1038 		charset = camel_mime_filter_windows_real_charset (windows);
1039 	} else if (charset == NULL) {
1040 		charset = formatter->priv->default_charset;
1041 	}
1042 
1043 	mem_stream = (CamelStream *) camel_stream_mem_new ();
1044 	filter_stream = camel_stream_filter_new (mem_stream);
1045 
1046 	if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
1047 		camel_stream_filter_add (
1048 			CAMEL_STREAM_FILTER (filter_stream),
1049 			CAMEL_MIME_FILTER (filter));
1050 		g_object_unref (filter);
1051 	}
1052 
1053 	camel_data_wrapper_decode_to_stream_sync (
1054 			camel_medium_get_content ((CamelMedium *) dw),
1055 			(CamelStream *) filter_stream, cancellable, NULL);
1056 	camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
1057 	g_object_unref (filter_stream);
1058 
1059 	g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL);
1060 
1061 	camel_stream_write_to_stream (
1062 		mem_stream, (CamelStream *) stream, cancellable, NULL);
1063 	camel_stream_flush ((CamelStream *) mem_stream, cancellable, NULL);
1064 
1065 	if (windows) {
1066 		g_object_unref (windows);
1067 	}
1068 
1069 	g_object_unref (mem_stream);
1070 }
1071 
1072 gchar *
1073 e_mail_formatter_get_html_header (EMailFormatter *formatter)
1074 {
1075 	return g_strdup_printf (
1076 		"<!DOCTYPE HTML>\n<html>\n"
1077 		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n"
1078 		"<title>Evolution Mail Display</title>\n"
1079 		"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n"
1080 		"<style type=\"text/css\">\n"
1081 		"  table th { color: #%06x; font-weight: bold; }\n"
1082 		"</style>\n"
1083 		"</head><body bgcolor=\"#%06x\" text=\"#%06x\">",
1084 		e_color_to_value ((GdkColor *)
1085 			e_mail_formatter_get_color (
1086 				formatter, E_MAIL_FORMATTER_COLOR_HEADER)),
1087 		e_color_to_value ((GdkColor *)
1088 			e_mail_formatter_get_color (
1089 				formatter, E_MAIL_FORMATTER_COLOR_BODY)),
1090 		e_color_to_value ((GdkColor *)
1091 			e_mail_formatter_get_color (
1092 				formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
1093 }
1094 
1095 EMailExtensionRegistry *
1096 e_mail_formatter_get_extension_registry (EMailFormatter *formatter)
1097 {
1098 	EMailFormatterClass * formatter_class;
1099 
1100 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
1101 
1102 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
1103 	return E_MAIL_EXTENSION_REGISTRY (formatter_class->extension_registry);
1104 }
1105 
1106 guint32
1107 e_mail_formatter_get_text_format_flags (EMailFormatter *formatter)
1108 {
1109 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
1110 
1111 	return E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
1112 }
1113 
1114 const GdkColor *
1115 e_mail_formatter_get_color (EMailFormatter *formatter,
1116                             EMailFormatterColorType type)
1117 {
1118 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
1119 	g_return_val_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES, NULL);
1120 
1121 	return &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
1122 }
1123 
1124 void
1125 e_mail_formatter_set_color (EMailFormatter *formatter,
1126                             EMailFormatterColorType type,
1127                             const GdkColor *color)
1128 {
1129 	GdkColor *format_color;
1130 	const gchar *property_name;
1131 
1132 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1133 	g_return_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES);
1134 	g_return_if_fail (color != NULL);
1135 
1136 	format_color = &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
1137 
1138 	if (gdk_color_equal (color, format_color))
1139 		return;
1140 
1141 	format_color->red   = color->red;
1142 	format_color->green = color->green;
1143 	format_color->blue  = color->blue;
1144 
1145 	switch (type) {
1146 		case E_MAIL_FORMATTER_COLOR_BODY:
1147 			property_name = "body-color";
1148 			break;
1149 		case E_MAIL_FORMATTER_COLOR_CITATION:
1150 			property_name = "citation-color";
1151 			break;
1152 		case E_MAIL_FORMATTER_COLOR_CONTENT:
1153 			property_name = "content-color";
1154 			break;
1155 		case E_MAIL_FORMATTER_COLOR_FRAME:
1156 			property_name = "frame-color";
1157 			break;
1158 		case E_MAIL_FORMATTER_COLOR_HEADER:
1159 			property_name = "header-color";
1160 			break;
1161 		case E_MAIL_FORMATTER_COLOR_TEXT:
1162 			property_name = "text-color";
1163 			break;
1164 		default:
1165 			g_return_if_reached ();
1166 	}
1167 
1168 	g_object_notify (G_OBJECT (formatter), property_name);
1169 }
1170 
1171 void
1172 e_mail_formatter_set_style (EMailFormatter *formatter,
1173                             GtkStyle *style,
1174                             GtkStateType state)
1175 {
1176 	EMailFormatterClass *formatter_class;
1177 
1178 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1179 	g_return_if_fail (GTK_IS_STYLE (style));
1180 
1181 	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
1182 	g_return_if_fail (formatter_class->set_style != NULL);
1183 
1184 	formatter_class->set_style (formatter, style, state);
1185 }
1186 
1187 EMailImageLoadingPolicy
1188 e_mail_formatter_get_image_loading_policy (EMailFormatter *formatter)
1189 {
1190 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
1191 
1192 	return formatter->priv->image_loading_policy;
1193 }
1194 
1195 void
1196 e_mail_formatter_set_image_loading_policy (EMailFormatter *formatter,
1197                                            EMailImageLoadingPolicy policy)
1198 {
1199 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1200 
1201 	if (policy == formatter->priv->image_loading_policy)
1202 		return;
1203 
1204 	formatter->priv->image_loading_policy = policy;
1205 
1206 	g_object_notify (G_OBJECT (formatter), "image-loading-policy");
1207 }
1208 
1209 gboolean
1210 e_mail_formatter_get_mark_citations (EMailFormatter *formatter)
1211 {
1212 	guint32 flags;
1213 
1214 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
1215 
1216 	flags = E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
1217 
1218 	return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
1219 }
1220 
1221 void
1222 e_mail_formatter_set_mark_citations (EMailFormatter *formatter,
1223                                      gboolean mark_citations)
1224 {
1225 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1226 
1227 	if (mark_citations)
1228 		E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags |=
1229 			CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
1230 	else
1231 		E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags &=
1232 			~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
1233 
1234 	g_object_notify (G_OBJECT (formatter), "mark-citations");
1235 }
1236 
1237 gboolean
1238 e_mail_formatter_get_only_local_photos (EMailFormatter *formatter)
1239 {
1240 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
1241 
1242 	return formatter->priv->only_local_photos;
1243 }
1244 
1245 void
1246 e_mail_formatter_set_only_local_photos (EMailFormatter *formatter,
1247                                         gboolean only_local_photos)
1248 {
1249 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1250 
1251 	if (formatter->priv->only_local_photos == only_local_photos)
1252 		return;
1253 
1254 	formatter->priv->only_local_photos = only_local_photos;
1255 
1256 	g_object_notify (G_OBJECT (formatter), "only-local-photos");
1257 }
1258 
1259 gboolean
1260 e_mail_formatter_get_show_sender_photo (EMailFormatter *formatter)
1261 {
1262 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
1263 
1264 	return formatter->priv->show_sender_photo;
1265 }
1266 
1267 void
1268 e_mail_formatter_set_show_sender_photo (EMailFormatter *formatter,
1269                                         gboolean show_sender_photo)
1270 {
1271 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1272 
1273 	if (formatter->priv->show_sender_photo == show_sender_photo)
1274 		return;
1275 
1276 	formatter->priv->show_sender_photo = show_sender_photo;
1277 
1278 	g_object_notify (G_OBJECT (formatter), "show-sender-photo");
1279 }
1280 
1281 gboolean
1282 e_mail_formatter_get_show_real_date (EMailFormatter *formatter)
1283 {
1284 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
1285 
1286 	return formatter->priv->show_real_date;
1287 }
1288 
1289 void
1290 e_mail_formatter_set_show_real_date (EMailFormatter *formatter,
1291                                      gboolean show_real_date)
1292 {
1293 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1294 
1295 	if (formatter->priv->show_real_date == show_real_date)
1296 		return;
1297 
1298 	formatter->priv->show_real_date = show_real_date;
1299 
1300 	g_object_notify (G_OBJECT (formatter), "show-real-date");
1301 }
1302 
1303 gboolean
1304 e_mail_formatter_get_animate_images (EMailFormatter *formatter)
1305 {
1306 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
1307 
1308 	return formatter->priv->animate_images;
1309 }
1310 
1311 void
1312 e_mail_formatter_set_animate_images (EMailFormatter *formatter,
1313                                      gboolean animate_images)
1314 {
1315 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1316 
1317 	if (formatter->priv->animate_images == animate_images)
1318 		return;
1319 
1320 	formatter->priv->animate_images = animate_images;
1321 
1322 	g_object_notify (G_OBJECT (formatter), "animate-images");
1323 }
1324 
1325 const gchar *
1326 e_mail_formatter_get_charset (EMailFormatter *formatter)
1327 {
1328 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
1329 
1330 	return formatter->priv->charset;
1331 }
1332 
1333 void
1334 e_mail_formatter_set_charset (EMailFormatter *formatter,
1335                               const gchar *charset)
1336 {
1337 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1338 
1339 	if (g_strcmp0 (formatter->priv->charset, charset) == 0)
1340 		return;
1341 
1342 	g_free (formatter->priv->charset);
1343 
1344 	if (!charset) {
1345 		formatter->priv->charset = NULL;
1346 	} else {
1347 		formatter->priv->charset = g_strdup (charset);
1348 	}
1349 
1350 	g_object_notify (G_OBJECT (formatter), "charset");
1351 }
1352 
1353 const gchar *
1354 e_mail_formatter_get_default_charset (EMailFormatter *formatter)
1355 {
1356 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
1357 
1358 	return formatter->priv->default_charset;
1359 }
1360 
1361 void
1362 e_mail_formatter_set_default_charset (EMailFormatter *formatter,
1363                                       const gchar *default_charset)
1364 {
1365 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1366 	g_return_if_fail (default_charset && *default_charset);
1367 
1368 	if (g_strcmp0 (formatter->priv->default_charset, default_charset) == 0)
1369 		return;
1370 
1371 	g_free (formatter->priv->default_charset);
1372 	formatter->priv->default_charset = g_strdup (default_charset);
1373 
1374 	g_object_notify (G_OBJECT (formatter), "default-charset");
1375 }
1376 
1377 /* note: also copied in em-mailer-prefs.c */
1378 static const struct {
1379 	const gchar *name;
1380 	guint32 flags;
1381 } default_headers[] = {
1382 	{ N_("From"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1383 	{ N_("Reply-To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1384 	{ N_("To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1385 	{ N_("Cc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1386 	{ N_("Bcc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1387 	{ N_("Subject"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1388 	{ N_("Date"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1389 	{ N_("Newsgroups"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
1390 	{ N_("Face"), 0 },
1391 };
1392 
1393 /**
1394  * e_mail_formatter_get_headers:
1395  * @formatter: an #EMailFormatter
1396  *
1397  * Returns list of currently set headers.
1398  *
1399  * Return Value: A #GQueue of headers which you should not modify or unref
1400  */
1401 const GQueue *
1402 e_mail_formatter_get_headers (EMailFormatter *formatter)
1403 {
1404 	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
1405 
1406 	return formatter->priv->header_list;
1407 }
1408 
1409 /**
1410  * e_mail_formatter_clear_headers:
1411  * @formatter: an #EMailFormatter
1412  *
1413  * Clear the list of headers to be displayed.  This will force all headers to
1414  * be shown.
1415  **/
1416 void
1417 e_mail_formatter_clear_headers (EMailFormatter *formatter)
1418 {
1419 	EMailFormatterHeader *header;
1420 
1421 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1422 
1423 	while ((header = g_queue_pop_head (formatter->priv->header_list)) != NULL) {
1424 		e_mail_formatter_header_free (header);
1425 	}
1426 }
1427 
1428 /**
1429  * e_mail_formatter_set_default_headers:
1430  * @formatter: an #EMailFormatter
1431  *
1432  * Clear the list of headers and sets the default ones, e.g. "To", "From", "Cc"
1433  * "Subject", etc...
1434  */
1435 void
1436 e_mail_formatter_set_default_headers (EMailFormatter *formatter)
1437 {
1438 	gint ii;
1439 
1440 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1441 
1442 	/* Set the default headers */
1443 	e_mail_formatter_clear_headers (formatter);
1444 	for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) {
1445 		e_mail_formatter_add_header (
1446 			formatter, default_headers[ii].name, NULL,
1447 			default_headers[ii].flags);
1448 	}
1449 }
1450 
1451 /**
1452  * e_mail_formatter_add_header:
1453  * @formatter:
1454  * @name: The name of the header, as it will appear during output.
1455  * @value: Value of the header. Can be %NULL.
1456  * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
1457  *
1458  * Add a specific header to show.  If any headers are set, they will
1459  * be displayed in the order set by this function.  Certain known
1460  * headers included in this list will be shown using special
1461  * formatting routines.
1462  **/
1463 void
1464 e_mail_formatter_add_header (EMailFormatter *formatter,
1465                              const gchar *name,
1466                              const gchar *value,
1467                              guint32 flags)
1468 {
1469 	EMailFormatterHeader *h;
1470 
1471 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1472 	g_return_if_fail (name && *name);
1473 
1474 	h = e_mail_formatter_header_new (name, value);
1475 	h->flags = flags;
1476 	g_queue_push_tail (formatter->priv->header_list, h);
1477 
1478 	g_signal_emit (formatter, signals[NEED_REDRAW], 0, NULL);
1479 }
1480 
1481 void
1482 e_mail_formatter_add_header_struct (EMailFormatter *formatter,
1483                                     const EMailFormatterHeader *header)
1484 {
1485 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1486 	g_return_if_fail (header && header->name);
1487 
1488 	e_mail_formatter_add_header (formatter, header->name, header->value, header->flags);
1489 }
1490 
1491 void e_mail_formatter_remove_header (EMailFormatter *formatter,
1492 				     const gchar *name,
1493 				     const gchar *value)
1494 {
1495 	GList *iter = NULL;
1496 
1497 	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
1498 	g_return_if_fail (name && *name);
1499 
1500 	iter = g_queue_peek_head_link (formatter->priv->header_list);
1501 	while (iter) {
1502 		EMailFormatterHeader *header = iter->data;
1503 
1504 		if (!header->value || !*header->value) {
1505 			GList *next = iter->next;
1506 			if (g_strcmp0 (name, header->name) == 0)
1507 				g_queue_delete_link (formatter->priv->header_list, iter);
1508 
1509 			iter = next;
1510 			continue;
1511 		}
1512 
1513 		if (value && *value) {
1514 			if ((g_strcmp0 (name, header->name) == 0) &&
1515 			    (g_strcmp0 (value, header->value) == 0))
1516 				break;
1517 		} else {
1518 			if (g_strcmp0 (name, header->name) == 0)
1519 				break;
1520 		}
1521 
1522 		iter = iter->next;
1523 	}
1524 
1525 	if (iter) {
1526 		e_mail_formatter_header_free (iter->data);
1527 		g_queue_delete_link (formatter->priv->header_list, iter);
1528 	}
1529 }
1530 
1531 void
1532 e_mail_formatter_remove_header_struct (EMailFormatter *formatter,
1533                                        const EMailFormatterHeader *header)
1534 {
1535 	g_return_if_fail (header != NULL);
1536 
1537 	e_mail_formatter_remove_header (formatter, header->name, header->value);
1538 }
1539 
1540 EMailFormatterHeader *
1541 e_mail_formatter_header_new (const gchar *name,
1542                              const gchar *value)
1543 {
1544 	EMailFormatterHeader *header;
1545 
1546 	g_return_val_if_fail (name && *name, NULL);
1547 
1548 	header = g_new0 (EMailFormatterHeader, 1);
1549 	header->name = g_strdup (name);
1550 	if (value && *value)
1551 		header->value = g_strdup (value);
1552 
1553 	return header;
1554 }
1555 
1556 void
1557 e_mail_formatter_header_free (EMailFormatterHeader *header)
1558 {
1559 	g_return_if_fail (header);
1560 
1561 	if (header->name) {
1562 		g_free (header->name);
1563 		header->name = NULL;
1564 	}
1565 
1566 	if (header->value) {
1567 		g_free (header->value);
1568 		header->value = NULL;
1569 	}
1570 
1571 	g_free (header);
1572 }