evolution-3.6.4/plugins/save-calendar/rdf-format.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Philip Van Hoof <pvanhoof@gnome.org>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <string.h>
 28 #include <glib/gi18n.h>
 29 
 30 #include <libxml/xmlmemory.h>
 31 #include <libxml/parser.h>
 32 #include <libxml/tree.h>
 33 #include <libxml/xmlIO.h>
 34 #include <libxml/xpath.h>
 35 
 36 #include "format-handler.h"
 37 
 38 static void	add_string_to_rdf		(xmlNodePtr node,
 39 						 const gchar *tag,
 40 						 const gchar *value);
 41 
 42 /* Use { */
 43 
 44 /* #include <calendar/gui/calendar-config-keys.h> */
 45 /* #include <calendar/gui/calendar-config.h> */
 46 
 47 /* } or { */
 48 #define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
 49 #define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
 50 
 51 static gchar *
 52 calendar_config_get_timezone (void)
 53 {
 54 	GSettings *settings;
 55 	gchar *retval = NULL;
 56 
 57 	settings = g_settings_new ("org.gnome.evolution.calendar");
 58 	retval = g_settings_get_string (settings, "timezone");
 59 	if (!retval)
 60 		retval = g_strdup ("UTC");
 61 
 62 	return retval;
 63 }
 64 /* } */
 65 
 66 enum { /* XML helper enum */
 67 	ECALCOMPONENTTEXT,
 68 	ECALCOMPONENTATTENDEE,
 69 	CONSTCHAR
 70 };
 71 
 72 static void
 73 display_error_message (GtkWidget *parent,
 74                        GError *error)
 75 {
 76 	GtkWidget *dialog;
 77 
 78 	dialog = gtk_message_dialog_new (
 79 		GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
 80 		"%s", error->message);
 81 	gtk_dialog_run (GTK_DIALOG (dialog));
 82 	gtk_widget_destroy (dialog);
 83 }
 84 
 85 /* Some helpers for the xml stuff */
 86 static void
 87 add_list_to_rdf (xmlNodePtr node,
 88                  const gchar *tag,
 89                  GSList *list_in,
 90                  gint type)
 91 {
 92 	if (list_in) {
 93 		GSList *list = list_in;
 94 
 95 		while (list) {
 96 			const gchar *str = NULL;
 97 
 98 			switch (type) {
 99 			case ECALCOMPONENTATTENDEE:
100 				str = ((ECalComponentAttendee *) list->data)->value;
101 				break;
102 			case ECALCOMPONENTTEXT:
103 				str = ((ECalComponentText *) list->data)->value;
104 				break;
105 			case CONSTCHAR:
106 			default:
107 				str = list->data;
108 				break;
109 			}
110 
111 			add_string_to_rdf (node, tag, str);
112 
113 			list = g_slist_next (list);
114 		}
115 	}
116 }
117 
118 static void
119 add_nummeric_to_rdf (xmlNodePtr node,
120                      const gchar *tag,
121                      gint *nummeric)
122 {
123 	if (nummeric) {
124 		gchar *value = g_strdup_printf ("%d", *nummeric);
125 		xmlNodePtr cur_node = xmlNewChild (node, NULL, (guchar *) tag, (guchar *) value);
126 		xmlSetProp (cur_node, (const guchar *)"rdf:datatype", (const guchar *)"http://www.w3.org/2001/XMLSchema#integer");
127 		g_free (value);
128 	}
129 }
130 
131 static void
132 add_time_to_rdf (xmlNodePtr node,
133                  const gchar *tag,
134                  icaltimetype *time)
135 {
136 	if (time) {
137 		xmlNodePtr cur_node = NULL;
138 		struct tm mytm =  icaltimetype_to_tm (time);
139 		gchar *str = (gchar *) g_malloc (sizeof (gchar) * 200);
140 		gchar *tmp = NULL;
141 		gchar *timezone;
142 		/*
143 		 * Translator: the %FT%T is the thirth argument for a strftime function.
144 		 * It lets you define the formatting of the date in the rdf-file.
145 		 * Also check out http://www.w3.org/2002/12/cal/tzd
146 		 * */
147 		e_utf8_strftime (str, 200, _("%FT%T"), &mytm);
148 
149 		cur_node = xmlNewChild (node, NULL, (guchar *) tag, (guchar *) str);
150 
151 		/* Not sure about this property */
152 		timezone = calendar_config_get_timezone ();
153 		tmp = g_strdup_printf ("http://www.w3.org/2002/12/cal/tzd/%s#tz", timezone);
154 		xmlSetProp (cur_node, (const guchar *)"rdf:datatype", (guchar *) tmp);
155 		g_free (tmp);
156 		g_free (timezone);
157 		g_free (str);
158 	}
159 }
160 
161 static void
162 add_string_to_rdf (xmlNodePtr node,
163                    const gchar *tag,
164                    const gchar *value)
165 {
166 	if (value) {
167 		xmlNodePtr cur_node = NULL;
168 		cur_node = xmlNewChild (node, NULL, (guchar *) tag, (guchar *) value);
169 		xmlSetProp (cur_node, (const guchar *)"rdf:datatype", (const guchar *)"http://www.w3.org/2001/XMLSchema#string");
170 	}
171 }
172 
173 static void
174 do_save_calendar_rdf (FormatHandler *handler,
175                       ESourceSelector *selector,
176                       ECalClientSourceType type,
177                       gchar *dest_uri)
178 {
179 
180 	/*
181 	 * According to some documentation about CSV, newlines 'are' allowed
182 	 * in CSV-files. But you 'do' have to put the value between quotes.
183 	 * The helper 'string_needsquotes' will check for that
184 	 *
185 	 * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm
186 	 * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl
187 	 */
188 
189 	ESource *primary_source;
190 	ECalClient *source_client;
191 	GError *error = NULL;
192 	GSList *objects = NULL;
193 	gchar *temp = NULL;
194 	GOutputStream *stream;
195 
196 	if (!dest_uri)
197 		return;
198 
199 	/* open source client */
200 	primary_source = e_source_selector_ref_primary_selection (selector);
201 	source_client = e_cal_client_new (primary_source, type, &error);
202 	g_object_unref (primary_source);
203 
204 	if (!source_client || !e_client_open_sync (E_CLIENT (source_client), TRUE, NULL, &error)) {
205 		display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (selector)), error);
206 		if (source_client)
207 			g_object_unref (source_client);
208 		g_error_free (error);
209 		return;
210 	}
211 
212 	stream = open_for_writing (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (selector))), dest_uri, &error);
213 
214 	if (stream && e_cal_client_get_object_list_as_comps_sync (source_client, "#t", &objects, NULL, NULL)) {
215 		GSList *iter;
216 
217 		xmlBufferPtr buffer = xmlBufferCreate ();
218 		xmlDocPtr doc = xmlNewDoc ((xmlChar *) "1.0");
219 		xmlNodePtr fnode;
220 
221 		doc->children = xmlNewDocNode (doc, NULL, (const guchar *)"rdf:RDF", NULL);
222 		xmlSetProp (doc->children, (const guchar *)"xmlns:rdf", (const guchar *)"http://www.w3.org/1999/02/22-rdf-syntax-ns#");
223 		xmlSetProp (doc->children, (const guchar *)"xmlns", (const guchar *)"http://www.w3.org/2002/12/cal/ical#");
224 
225 		fnode = xmlNewChild (doc->children, NULL, (const guchar *)"Vcalendar", NULL);
226 
227 		/* Should Evolution publicise these? */
228 		xmlSetProp (fnode, (const guchar *)"xmlns:x-wr", (const guchar *)"http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#");
229 		xmlSetProp (fnode, (const guchar *)"xmlns:x-lic", (const guchar *)"http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#");
230 
231 		/* Not sure if it's correct like this */
232 		xmlNewChild (fnode, NULL, (const guchar *)"prodid", (const guchar *)"-//" PACKAGE_STRING "//iCal 1.0//EN");
233 
234 		/* Assuming GREGORIAN is the only supported calendar scale */
235 		xmlNewChild (fnode, NULL, (const guchar *)"calscale", (const guchar *)"GREGORIAN");
236 
237 		temp = calendar_config_get_timezone ();
238 		xmlNewChild (fnode, NULL, (const guchar *)"x-wr:timezone", (guchar *) temp);
239 		g_free (temp);
240 
241 		xmlNewChild (fnode, NULL, (const guchar *)"method", (const guchar *)"PUBLISH");
242 
243 		xmlNewChild (fnode, NULL, (const guchar *)"x-wr:relcalid", (guchar *) e_source_get_uid (primary_source));
244 
245 		xmlNewChild (fnode, NULL, (const guchar *)"x-wr:calname", (guchar *) e_source_get_display_name (primary_source));
246 
247 		/* Version of this RDF-format */
248 		xmlNewChild (fnode, NULL, (const guchar *)"version", (const guchar *)"2.0");
249 
250 		for (iter = objects; iter; iter = iter->next) {
251 			ECalComponent *comp = iter->data;
252 			const gchar *temp_constchar;
253 			gchar *tmp_str = NULL;
254 			GSList *temp_list;
255 			ECalComponentDateTime temp_dt;
256 			struct icaltimetype *temp_time;
257 			gint *temp_int;
258 			ECalComponentText temp_comptext;
259 			xmlNodePtr c_node = xmlNewChild (fnode, NULL, (const guchar *)"component", NULL);
260 			xmlNodePtr node = xmlNewChild (c_node, NULL, (const guchar *)"Vevent", NULL);
261 
262 			/* Getting the stuff */
263 			e_cal_component_get_uid (comp, &temp_constchar);
264 			tmp_str = g_strdup_printf ("#%s", temp_constchar);
265 			xmlSetProp (node, (const guchar *)"about", (guchar *) tmp_str);
266 			g_free (tmp_str);
267 			add_string_to_rdf (node, "uid",temp_constchar);
268 
269 			e_cal_component_get_summary (comp, &temp_comptext);
270 			add_string_to_rdf (node, "summary", temp_comptext.value);
271 
272 			e_cal_component_get_description_list (comp, &temp_list);
273 			add_list_to_rdf (node, "description", temp_list, ECALCOMPONENTTEXT);
274 			if (temp_list)
275 				e_cal_component_free_text_list (temp_list);
276 
277 			e_cal_component_get_categories_list (comp, &temp_list);
278 			add_list_to_rdf (node, "categories", temp_list, CONSTCHAR);
279 			if (temp_list)
280 				e_cal_component_free_categories_list (temp_list);
281 
282 			e_cal_component_get_comment_list (comp, &temp_list);
283 			add_list_to_rdf (node, "comment", temp_list, ECALCOMPONENTTEXT);
284 
285 			if (temp_list)
286 				e_cal_component_free_text_list (temp_list);
287 
288 			e_cal_component_get_completed (comp, &temp_time);
289 			add_time_to_rdf (node, "completed", temp_time);
290 			if (temp_time)
291 				e_cal_component_free_icaltimetype (temp_time);
292 
293 			e_cal_component_get_created (comp, &temp_time);
294 			add_time_to_rdf (node, "created", temp_time);
295 			if (temp_time)
296 				e_cal_component_free_icaltimetype (temp_time);
297 
298 			e_cal_component_get_contact_list (comp, &temp_list);
299 			add_list_to_rdf (node, "contact", temp_list, ECALCOMPONENTTEXT);
300 			if (temp_list)
301 				e_cal_component_free_text_list (temp_list);
302 
303 			e_cal_component_get_dtstart (comp, &temp_dt);
304 			add_time_to_rdf (node, "dtstart", temp_dt.value ? temp_dt.value : NULL);
305 			e_cal_component_free_datetime (&temp_dt);
306 
307 			e_cal_component_get_dtend (comp, &temp_dt);
308 			add_time_to_rdf (node, "dtend", temp_dt.value ? temp_dt.value : NULL);
309 			e_cal_component_free_datetime (&temp_dt);
310 
311 			e_cal_component_get_due (comp, &temp_dt);
312 			add_time_to_rdf (node, "due", temp_dt.value ? temp_dt.value : NULL);
313 			e_cal_component_free_datetime (&temp_dt);
314 
315 			e_cal_component_get_percent (comp, &temp_int);
316 			add_nummeric_to_rdf (node, "percentComplete", temp_int);
317 
318 			e_cal_component_get_priority (comp, &temp_int);
319 			add_nummeric_to_rdf (node, "priority", temp_int);
320 
321 			e_cal_component_get_url (comp, &temp_constchar);
322 			add_string_to_rdf (node, "URL", temp_constchar);
323 
324 			if (e_cal_component_has_attendees (comp)) {
325 				e_cal_component_get_attendee_list (comp, &temp_list);
326 				add_list_to_rdf (node, "attendee", temp_list, ECALCOMPONENTATTENDEE);
327 				if (temp_list)
328 					e_cal_component_free_attendee_list (temp_list);
329 			}
330 
331 			e_cal_component_get_location (comp, &temp_constchar);
332 			add_string_to_rdf (node, "location", temp_constchar);
333 
334 			e_cal_component_get_last_modified (comp, &temp_time);
335 			add_time_to_rdf (node, "lastModified",temp_time);
336 
337 			/* Important note!
338 			 * The documentation is not requiring this!
339 			 *
340 			 * if (temp_time) e_cal_component_free_icaltimetype (temp_time);
341 			 *
342 			 * Please uncomment and fix documentation if untrue
343 			 * http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html
344 			 *	#e-cal-component-get-last-modified
345 			 */
346 		}
347 
348 		/* I used a buffer rather than xmlDocDump: I want gio support */
349 		xmlNodeDump (buffer, doc, doc->children, 2, 1);
350 
351 		g_output_stream_write_all (stream, xmlBufferContent (buffer), xmlBufferLength (buffer), NULL, NULL, &error);
352 		g_output_stream_close (stream, NULL, NULL);
353 
354 		e_cal_client_free_ecalcomp_slist (objects);
355 
356 		xmlBufferFree (buffer);
357 		xmlFreeDoc (doc);
358 	}
359 
360 	if (stream)
361 		g_object_unref (stream);
362 
363 	g_object_unref (source_client);
364 
365 	if (error) {
366 		display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (selector)), error);
367 		g_error_free (error);
368 	}
369 
370 	return;
371 }
372 
373 FormatHandler *rdf_format_handler_new (void)
374 {
375 	FormatHandler *handler = g_new (FormatHandler, 1);
376 
377 	handler->isdefault = FALSE;
378 	handler->combo_label = _("RDF (.rdf)");
379 	handler->filename_ext = ".rdf";
380 	handler->options_widget = NULL;
381 	handler->save = do_save_calendar_rdf;
382 
383 	return handler;
384 }