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

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-formatter-utils.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-formatter-utils.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-utils.h
  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 #ifdef HAVE_CONFIG
 20 #include <config.h>
 21 #endif
 22 
 23 #include "e-mail-formatter-utils.h"
 24 
 25 #include <camel/camel.h>
 26 
 27 #include <libemail-engine/e-mail-utils.h>
 28 #include <libemail-engine/mail-config.h>
 29 #include <e-util/e-util.h>
 30 #include <e-util/e-datetime-format.h>
 31 #include <libedataserver/libedataserver.h>
 32 
 33 #include <glib/gi18n.h>
 34 
 35 #include <string.h>
 36 
 37 static const gchar *addrspec_hdrs[] = {
 38 	"Sender", "From", "Reply-To", "To", "Cc", "Bcc",
 39 	"Resent-Sender", "Resent-From", "Resent-Reply-To",
 40 	"Resent-To", "Resent-Cc", "Resent-Bcc", NULL
 41 };
 42 
 43 void
 44 e_mail_formatter_format_text_header (EMailFormatter *formatter,
 45                                      GString *buffer,
 46                                      const gchar *label,
 47                                      const gchar *value,
 48                                      guint32 flags)
 49 {
 50 	const gchar *fmt, *html;
 51 	gchar *mhtml = NULL;
 52 	gboolean is_rtl;
 53 
 54 	if (value == NULL)
 55 		return;
 56 
 57 	while (*value == ' ')
 58 		value++;
 59 
 60 	if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML))
 61 		html = mhtml = camel_text_to_html (
 62 			value,
 63 			e_mail_formatter_get_text_format_flags (formatter), 0);
 64 	else
 65 		html = value;
 66 
 67 	is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL;
 68 
 69 	if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) {
 70 		if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
 71 			fmt = "<tr class=\"header-item\" style=\"display: %s\"><td><b>%s:</b> %s</td></tr>";
 72 		} else {
 73 			fmt = "<tr class=\"header-item\" style=\"display: %s\"><td>%s: %s</td></tr>";
 74 		}
 75 	} else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) {
 76 		if (is_rtl)
 77 			fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th valign=top align=\"left\" nowrap>%1$s<b>&nbsp;</b></th></tr>";
 78 		else
 79 			fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s<b>&nbsp;</b></th><td valign=top>%s</td></tr>";
 80 	} else {
 81 		if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
 82 			if (is_rtl)
 83 				fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th align=\"left\" nowrap>%1$s:<b>&nbsp;</b></th></tr>";
 84 			else
 85 				fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></th><td>%s</td></tr>";
 86 		} else {
 87 			if (is_rtl)
 88 				fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%\">%2$s</td><td align=\"left\" nowrap>%1$s:<b>&nbsp;</b></td></tr>";
 89 			else
 90 				fmt = "<tr class=\"header-item\" style=\"display: %s\"><td align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></td><td>%s</td></tr>";
 91 		}
 92 	}
 93 
 94 	g_string_append_printf (
 95 		buffer, fmt,
 96 		(flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN ? "none" : "table-row"), label, html);
 97 
 98 	g_free (mhtml);
 99 }
100 
101 gchar *
102 e_mail_formatter_format_address (EMailFormatter *formatter,
103                                  GString *out,
104                                  struct _camel_header_address *a,
105                                  gchar *field,
106                                  gboolean no_links,
107                                  gboolean elipsize)
108 {
109 	guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
110 	gchar *name, *mailto, *addr;
111 	gint i = 0;
112 	gchar *str = NULL;
113 	gint limit = mail_config_get_address_count ();
114 
115 	while (a) {
116 		if (a->name)
117 			name = camel_text_to_html (a->name, flags, 0);
118 		else
119 			name = NULL;
120 
121 		switch (a->type) {
122 		case CAMEL_HEADER_ADDRESS_NAME:
123 			if (name && *name) {
124 				gchar *real, *mailaddr;
125 
126 				if (strchr (a->name, ',') || strchr (a->name, ';'))
127 					g_string_append_printf (out, "&quot;%s&quot;", name);
128 				else
129 					g_string_append (out, name);
130 
131 				g_string_append (out, " &lt;");
132 
133 				/* rfc2368 for mailto syntax and url encoding extras */
134 				if ((real = camel_header_encode_phrase ((guchar *) a->name))) {
135 					mailaddr = g_strdup_printf ("%s <%s>", real, a->v.addr);
136 					g_free (real);
137 					mailto = camel_url_encode (mailaddr, "?=&()");
138 					g_free (mailaddr);
139 				} else {
140 					mailto = camel_url_encode (a->v.addr, "?=&()");
141 				}
142 			} else {
143 				mailto = camel_url_encode (a->v.addr, "?=&()");
144 			}
145 			addr = camel_text_to_html (a->v.addr, flags, 0);
146 			if (no_links)
147 				g_string_append_printf (out, "%s", addr);
148 			else
149 				g_string_append_printf (out, "<a href=\"mailto:%s\">%s</a>", mailto, addr);
150 			g_free (mailto);
151 			g_free (addr);
152 
153 			if (name && *name)
154 				g_string_append (out, "&gt;");
155 			break;
156 		case CAMEL_HEADER_ADDRESS_GROUP:
157 			g_string_append_printf (out, "%s: ", name);
158 			e_mail_formatter_format_address (
159 				formatter, out, a->v.members, field,
160 				no_links, elipsize);
161 			g_string_append_printf (out, ";");
162 			break;
163 		default:
164 			g_warning ("Invalid address type");
165 			break;
166 		}
167 
168 		g_free (name);
169 
170 		i++;
171 		a = a->next;
172 		if (a)
173 			g_string_append (out, ", ");
174 
175 		if (!elipsize)
176 			continue;
177 
178 		/* Let us add a '...' if we have more addresses */
179 		if (limit > 0 && i == limit && a != NULL) {
180 			const gchar *id = NULL;
181 
182 			if (strcmp (field, _("To")) == 0) {
183 				id = "to";
184 			} else if (strcmp (field, _("Cc")) == 0) {
185 				id = "cc";
186 			} else if (strcmp (field, _("Bcc")) == 0) {
187 				id = "bcc";
188 			}
189 
190 			if (id) {
191 				g_string_append_printf (
192 					out,
193 					"<span id=\"__evo-moreaddr-%s\" "
194 					"style=\"display: none;\">", id);
195 				str = g_strdup_printf (
196 					"<img src=\"evo-file://%s/plus.png\" "
197 					"id=\"__evo-moreaddr-img-%s\" class=\"navigable\">",
198 					EVOLUTION_IMAGESDIR, id);
199 			}
200 		}
201 	}
202 
203 	if (elipsize && str) {
204 		const gchar *id = NULL;
205 
206 		if (strcmp (field, _("To")) == 0) {
207 			id = "to";
208 		} else if (strcmp (field, _("Cc")) == 0) {
209 			id = "cc";
210 		} else if (strcmp (field, _("Bcc")) == 0) {
211 			id = "bcc";
212 		}
213 
214 		if (id) {
215 			g_string_append_printf (
216 				out,
217 				"</span>"
218 				"<span class=\"navigable\" "
219 					"id=\"__evo-moreaddr-ellipsis-%s\" "
220 					"style=\"display: inline;\">...</span>",
221 				id);
222 		}
223 	}
224 
225 	return str;
226 }
227 
228 void
229 e_mail_formatter_canon_header_name (gchar *name)
230 {
231 	gchar *inptr = name;
232 
233 	/* canonicalise the header name... first letter is
234 	 * capitalised and any letter following a '-' also gets
235 	 * capitalised */
236 
237 	if (*inptr >= 'a' && *inptr <= 'z')
238 		*inptr -= 0x20;
239 
240 	inptr++;
241 
242 	while (*inptr) {
243 		if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z')
244 			*inptr -= 0x20;
245 		else if (*inptr >= 'A' && *inptr <= 'Z')
246 			*inptr += 0x20;
247 
248 		inptr++;
249 	}
250 }
251 
252 void
253 e_mail_formatter_format_header (EMailFormatter *formatter,
254                                 GString *buffer,
255                                 CamelMedium *part,
256                                 struct _camel_header_raw *header,
257                                 guint32 flags,
258                                 const gchar *charset)
259 {
260 	gchar *name, *buf, *value = NULL;
261 	const gchar *label, *txt;
262 	gboolean addrspec = FALSE;
263 	gchar *str_field = NULL;
264 	gint i;
265 
266 	name = g_alloca (strlen (header->name) + 1);
267 	strcpy (name, header->name);
268 	e_mail_formatter_canon_header_name (name);
269 
270 	for (i = 0; addrspec_hdrs[i]; i++) {
271 		if (!strcmp (name, addrspec_hdrs[i])) {
272 			addrspec = TRUE;
273 			break;
274 		}
275 	}
276 
277 	label = _(name);
278 
279 	if (addrspec) {
280 		struct _camel_header_address *addrs;
281 		GString *html;
282 		gchar *img;
283 		const gchar *charset = e_mail_formatter_get_charset (formatter) ?
284 						e_mail_formatter_get_charset (formatter) :
285 						e_mail_formatter_get_default_charset (formatter);
286 
287 		buf = camel_header_unfold (header->value);
288 		if (!(addrs = camel_header_address_decode (buf, charset))) {
289 			g_free (buf);
290 			return;
291 		}
292 
293 		g_free (buf);
294 
295 		html = g_string_new ("");
296 		img = e_mail_formatter_format_address (
297 			formatter, html, addrs, (gchar *) label,
298 			(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS),
299 			!(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
300 
301 		if (img) {
302 			str_field = g_strdup_printf ("%s: %s", label, img);
303 			label = str_field;
304 			flags |= E_MAIL_FORMATTER_HEADER_FLAG_NODEC;
305 			g_free (img);
306 		}
307 
308 		camel_header_address_list_clear (&addrs);
309 		txt = value = html->str;
310 		g_string_free (html, FALSE);
311 
312 		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML | E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
313 	} else if (!strcmp (name, "Subject")) {
314 		buf = camel_header_unfold (header->value);
315 		txt = value = camel_header_decode_string (buf, charset);
316 		g_free (buf);
317 
318 		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
319 	} else if (!strcmp (name, "X-evolution-mailer")) {
320 		/* pseudo-header */
321 		label = _("Mailer");
322 		txt = value = camel_header_format_ctext (header->value, charset);
323 		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
324 	} else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) {
325 		gint msg_offset, local_tz;
326 		time_t msg_date;
327 		struct tm local;
328 		gchar *html;
329 		gboolean hide_real_date;
330 
331 		hide_real_date = !e_mail_formatter_get_show_real_date (formatter);
332 
333 		txt = header->value;
334 		while (*txt == ' ' || *txt == '\t')
335 			txt++;
336 
337 		html = camel_text_to_html (
338 			txt,
339 			e_mail_formatter_get_text_format_flags (formatter), 0);
340 
341 		msg_date = camel_header_decode_date (txt, &msg_offset);
342 		e_localtime_with_offset (msg_date, &local, &local_tz);
343 
344 		/* Convert message offset to minutes (e.g. -0400 --> -240) */
345 		msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100);
346 		/* Turn into offset from localtime, not UTC */
347 		msg_offset -= local_tz / 60;
348 
349 		/* value will be freed at the end */
350 		if (!hide_real_date && !msg_offset) {
351 			/* No timezone difference; just show the real Date: header */
352 			txt = value = html;
353 		} else {
354 			gchar *date_str;
355 
356 			date_str = e_datetime_format_format (
357 				"mail", "header",
358 				DTFormatKindDateTime, msg_date);
359 
360 			if (hide_real_date) {
361 				/* Show only the local-formatted date, losing all timezone
362 				 * information like Outlook does. Should we attempt to show
363 				 * it somehow? */
364 				txt = value = date_str;
365 			} else {
366 				txt = value = g_strdup_printf ("%s (<I>%s</I>)", html, date_str);
367 				g_free (date_str);
368 			}
369 			g_free (html);
370 		}
371 		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML |
372 			 E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
373 	} else if (!strcmp (name, "Newsgroups")) {
374 		struct _camel_header_newsgroup *ng, *scan;
375 		GString *html;
376 
377 		buf = camel_header_unfold (header->value);
378 
379 		if (!(ng = camel_header_newsgroups_decode (buf))) {
380 			g_free (buf);
381 			return;
382 		}
383 
384 		g_free (buf);
385 
386 		html = g_string_new ("");
387 		scan = ng;
388 		while (scan) {
389 			if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS)
390 				g_string_append_printf (html, "%s", scan->newsgroup);
391 			else
392 				g_string_append_printf (
393 					html, "<a href=\"news:%s\">%s</a>",
394 					scan->newsgroup, scan->newsgroup);
395 			scan = scan->next;
396 			if (scan)
397 				g_string_append_printf (html, ", ");
398 		}
399 
400 		camel_header_newsgroups_free (ng);
401 
402 		txt = html->str;
403 		g_string_free (html, FALSE);
404 		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML |
405 			 E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
406 	} else if (!strcmp (name, "Received") || !strncmp (name, "X-", 2)) {
407 		/* don't unfold Received nor extension headers */
408 		txt = value = camel_header_decode_string (header->value, charset);
409 	} else {
410 		/* don't unfold Received nor extension headers */
411 		buf = camel_header_unfold (header->value);
412 		txt = value = camel_header_decode_string (buf, charset);
413 		g_free (buf);
414 	}
415 
416 	e_mail_formatter_format_text_header (formatter, buffer, label, txt, flags);
417 
418 	g_free (value);
419 	g_free (str_field);
420 }
421 
422 GSList *
423 e_mail_formatter_find_rfc822_end_iter (GSList *iter)
424 {
425 	EMailPart *part;
426 	gchar *end;
427 
428 	part = iter->data;
429 	end = g_strconcat (part->id, ".end", NULL);
430 	for (; iter != NULL; iter = g_slist_next (iter)) {
431 		part = iter->data;
432 		if (!part)
433 			continue;
434 
435 		if (g_strcmp0 (part->id, end) == 0) {
436 			g_free (end);
437 			return iter;
438 		}
439 	}
440 	g_free (end);
441 	return iter;
442 }
443 
444 gchar *
445 e_mail_formatter_parse_html_mnemonics (const gchar *label,
446                                        gchar **access_key)
447 {
448 	const gchar *pos = NULL;
449 	gchar ak = 0;
450 	GString *html_label = NULL;
451 
452 	pos = strstr (label, "_");
453 	if (pos != NULL) {
454 		ak = pos[1];
455 
456 		/* Convert to uppercase */
457 		if (ak >= 'a')
458 			ak = ak - 32;
459 
460 		html_label = g_string_new ("");
461 		g_string_append_len (html_label, label, pos - label);
462 		g_string_append_printf (html_label, "<u>%c</u>", pos[1]);
463 		g_string_append (html_label, &pos[2]);
464 
465 		if (access_key) {
466 			if (ak) {
467 				*access_key = g_strdup_printf ("%c", ak);
468 			} else {
469 				*access_key = NULL;
470 			}
471 		}
472 
473 	} else {
474 		html_label = g_string_new (label);
475 
476 		if (access_key) {
477 			*access_key = NULL;
478 		}
479 	}
480 
481 	return g_string_free (html_label, FALSE);
482 }