1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		JP Rosevear <jpr@novell.com>
17  *
18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19  *
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <glib/gi18n.h>
27 
28 #include "e-mail-parser-itip.h"
29 
30 #include <shell/e-shell.h>
31 
32 #include <em-format/e-mail-extension-registry.h>
33 #include <em-format/e-mail-parser-extension.h>
34 #include <em-format/e-mail-part.h>
35 
36 #include "e-mail-part-itip.h"
37 #include "itip-view.h"
38 
39 #define d(x)
40 
41 typedef EMailParserExtension EMailParserItip;
42 typedef EMailParserExtensionClass EMailParserItipClass;
43 
44 typedef EExtension EMailParserItipLoader;
45 typedef EExtensionClass EMailParserItipLoaderClass;
46 
47 GType e_mail_parser_itip_get_type (void);
48 
49 G_DEFINE_DYNAMIC_TYPE (
50 	EMailParserItip,
51 	e_mail_parser_itip,
52 	E_TYPE_MAIL_PARSER_EXTENSION)
53 
54 static const gchar *parser_mime_types[] = {
55 	"text/calendar",
56 	"application/ics",
57 	NULL
58 };
59 
60 static void
empe_itip_wrap_attachment(EMailParser * parser,GString * part_id,ICalProperty * prop,const gchar * content,GQueue * queue)61 empe_itip_wrap_attachment (EMailParser *parser,
62 			   GString *part_id,
63 			   ICalProperty *prop,
64 			   const gchar *content,
65 			   GQueue *queue)
66 {
67 	CamelMimePart *opart;
68 	CamelDataWrapper *dw;
69 	ICalParameter *param;
70 	const gchar *mime_type = NULL, *tmp;
71 
72 	opart = camel_mime_part_new ();
73 
74 	param = i_cal_property_get_first_parameter (prop, I_CAL_FILENAME_PARAMETER);
75 
76 	if (param) {
77 		tmp = i_cal_parameter_get_filename (param);
78 
79 		if (tmp && *tmp)
80 			camel_mime_part_set_filename (opart, tmp);
81 
82 		g_object_unref (param);
83 	}
84 
85 	param = i_cal_property_get_first_parameter (prop, I_CAL_FMTTYPE_PARAMETER);
86 
87 	if (param)
88 		mime_type = i_cal_parameter_get_fmttype (param);
89 
90 	if (!mime_type || !*mime_type)
91 		mime_type = "application/octet-stream";
92 
93 	camel_mime_part_set_content (opart, content, strlen (content), mime_type);
94 	camel_mime_part_set_encoding (opart, CAMEL_TRANSFER_ENCODING_BASE64);
95 
96 	dw = camel_medium_get_content (CAMEL_MEDIUM (opart));
97 	camel_data_wrapper_set_encoding (dw, CAMEL_TRANSFER_ENCODING_BASE64);
98 
99 	e_mail_parser_wrap_as_attachment (parser, opart, part_id, queue);
100 
101 	g_clear_object (&param);
102 	g_object_unref (opart);
103 }
104 
105 static void
empe_itip_extract_attachments(EMailParser * parser,const gchar * vcalendar_str,GString * part_id,GQueue * queue)106 empe_itip_extract_attachments (EMailParser *parser,
107 			       const gchar *vcalendar_str,
108 			       GString *part_id,
109 			       GQueue *queue)
110 {
111 	ICalComponent *vcalendar, *ical_comp;
112 	ICalCompIter *iter;
113 
114 	if (!vcalendar_str)
115 		return;
116 
117 	vcalendar = i_cal_parser_parse_string (vcalendar_str);
118 
119 	if (!vcalendar)
120 		return;
121 
122 	iter = i_cal_component_begin_component (vcalendar, I_CAL_ANY_COMPONENT);
123 	ical_comp = i_cal_comp_iter_deref (iter);
124 	if (ical_comp) {
125 		ICalComponentKind kind;
126 
127 		kind = i_cal_component_isa (ical_comp);
128 		if (kind != I_CAL_VEVENT_COMPONENT &&
129 		    kind != I_CAL_VTODO_COMPONENT &&
130 		    kind != I_CAL_VFREEBUSY_COMPONENT &&
131 		    kind != I_CAL_VJOURNAL_COMPONENT) {
132 			do {
133 				g_clear_object (&ical_comp);
134 				ical_comp = i_cal_comp_iter_next (iter);
135 				if (!ical_comp)
136 					break;
137 				kind = i_cal_component_isa (ical_comp);
138 			} while (ical_comp &&
139 				 kind != I_CAL_VEVENT_COMPONENT &&
140 				 kind != I_CAL_VTODO_COMPONENT &&
141 				 kind != I_CAL_VFREEBUSY_COMPONENT &&
142 				 kind != I_CAL_VJOURNAL_COMPONENT);
143 		}
144 	}
145 
146 	g_clear_object (&iter);
147 
148 	if (ical_comp) {
149 		ICalProperty *prop;
150 		gint len, index = 0;
151 
152 		len = part_id->len;
153 
154 		for (prop = i_cal_component_get_first_property (ical_comp, I_CAL_ATTACH_PROPERTY);
155 		     prop;
156 		     g_object_unref (prop), prop = i_cal_component_get_next_property (ical_comp, I_CAL_ATTACH_PROPERTY)) {
157 			ICalAttach *attach;
158 
159 			attach = i_cal_property_get_attach (prop);
160 
161 			if (attach && !i_cal_attach_get_is_url (attach)) {
162 				const gchar *content;
163 
164 				content = (const gchar *) i_cal_attach_get_data (attach);
165 
166 				if (content) {
167 					g_string_append_printf (part_id, ".attachment.%d", index);
168 
169 					empe_itip_wrap_attachment (parser, part_id, prop, content, queue);
170 
171 					g_string_truncate (part_id, len);
172 					index++;
173 				}
174 			}
175 
176 			g_clear_object (&attach);
177 		}
178 	}
179 
180 	g_clear_object (&ical_comp);
181 	g_clear_object (&vcalendar);
182 }
183 
184 static gboolean
empe_itip_parse(EMailParserExtension * extension,EMailParser * parser,CamelMimePart * part,GString * part_id,GCancellable * cancellable,GQueue * out_mail_parts)185 empe_itip_parse (EMailParserExtension *extension,
186                  EMailParser *parser,
187                  CamelMimePart *part,
188                  GString *part_id,
189                  GCancellable *cancellable,
190                  GQueue *out_mail_parts)
191 {
192 	EMailPartItip *itip_part;
193 	CamelDataWrapper *content;
194 	CamelStream *stream;
195 	GByteArray *byte_array;
196 	gint len;
197 	const CamelContentDisposition *disposition;
198 	GQueue work_queue = G_QUEUE_INIT;
199 
200 	len = part_id->len;
201 	g_string_append_printf (part_id, ".itip");
202 
203 	itip_part = e_mail_part_itip_new (part, part_id->str);
204 	itip_part->itip_mime_part = g_object_ref (part);
205 
206 	/* This is non-gui thread. Download the part for using in the main thread */
207 	content = camel_medium_get_content ((CamelMedium *) part);
208 
209 	byte_array = g_byte_array_new ();
210 	stream = camel_stream_mem_new_with_byte_array (byte_array);
211 	camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL);
212 
213 	if (byte_array->len == 0)
214 		itip_part->vcalendar = NULL;
215 	else
216 		itip_part->vcalendar = g_strndup (
217 			(gchar *) byte_array->data, byte_array->len);
218 
219 	g_object_unref (stream);
220 
221 	g_queue_push_tail (&work_queue, itip_part);
222 
223 	disposition = camel_mime_part_get_content_disposition (part);
224 	if (disposition &&
225 	    (g_strcmp0 (disposition->disposition, "attachment") == 0)) {
226 		e_mail_parser_wrap_as_attachment (
227 			parser, part, part_id, &work_queue);
228 	}
229 
230 	e_queue_transfer (&work_queue, out_mail_parts);
231 
232 	empe_itip_extract_attachments (parser, itip_part->vcalendar, part_id, &work_queue);
233 	e_queue_transfer (&work_queue, out_mail_parts);
234 
235 	g_string_truncate (part_id, len);
236 
237 	return TRUE;
238 }
239 
240 static void
e_mail_parser_itip_class_init(EMailParserExtensionClass * class)241 e_mail_parser_itip_class_init (EMailParserExtensionClass *class)
242 {
243 	class->mime_types = parser_mime_types;
244 	class->flags = E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION;
245 	class->parse = empe_itip_parse;
246 }
247 
248 static void
e_mail_parser_itip_class_finalize(EMailParserExtensionClass * class)249 e_mail_parser_itip_class_finalize (EMailParserExtensionClass *class)
250 {
251 }
252 
253 static void
e_mail_parser_itip_init(EMailParserExtension * class)254 e_mail_parser_itip_init (EMailParserExtension *class)
255 {
256 }
257 
258 void
e_mail_parser_itip_type_register(GTypeModule * type_module)259 e_mail_parser_itip_type_register (GTypeModule *type_module)
260 {
261 	e_mail_parser_itip_register_type (type_module);
262 }
263