1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * GData Client
4 * Copyright (C) Philip Withnall 2009, 2010, 2014, 2015 <philip@tecnocode.co.uk>
5 *
6 * GData Client is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * GData Client is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * SECTION:gdata-calendar-event
22 * @short_description: GData Calendar event object
23 * @stability: Stable
24 * @include: gdata/services/calendar/gdata-calendar-event.h
25 *
26 * #GDataCalendarEvent is a subclass of #GDataEntry to represent an event on a calendar from Google Calendar.
27 *
28 * For more details of Google Calendar's GData API, see the
29 * <ulink type="http" url="https://developers.google.com/google-apps/calendar/v3/reference/">
30 * online documentation</ulink>.
31 *
32 * <example>
33 * <title>Adding a New Event to the Default Calendar</title>
34 * <programlisting>
35 * GDataCalendarService *service;
36 * GDataCalendarEvent *event, *new_event;
37 * GDataGDWhere *where;
38 * GDataGDWho *who;
39 * GDataGDWhen *when;
40 * GTimeVal current_time;
41 * GError *error = NULL;
42 *
43 * /<!-- -->* Create a service *<!-- -->/
44 * service = create_calendar_service ();
45 *
46 * /<!-- -->* Create the new event *<!-- -->/
47 * event = gdata_calendar_event_new (NULL);
48 *
49 * gdata_entry_set_title (GDATA_ENTRY (event), "Event Title");
50 * gdata_entry_set_content (GDATA_ENTRY (event), "Event description. This should be a few sentences long.");
51 * gdata_calendar_event_set_status (event, GDATA_GD_EVENT_STATUS_CONFIRMED);
52 *
53 * where = gdata_gd_where_new (NULL, "Description of the location", NULL);
54 * gdata_calendar_event_add_place (event, where);
55 * g_object_unref (where);
56 *
57 * who = gdata_gd_who_new (GDATA_GD_WHO_EVENT_ORGANIZER, "John Smith", "john.smith@gmail.com");
58 * gdata_calendar_event_add_person (event, who);
59 * g_object_unref (who);
60 *
61 * g_get_current_time (¤t_time);
62 * when = gdata_gd_when_new (current_time.tv_sec, current_time.tv_sec + 3600, FALSE);
63 * gdata_calendar_event_add_time (event, when);
64 * g_object_unref (when);
65 *
66 * /<!-- -->* Insert the event in the calendar *<!-- -->/
67 * new_event = gdata_calendar_service_insert_event (service, event, NULL, &error);
68 *
69 * g_object_unref (event);
70 * g_object_unref (service);
71 *
72 * if (error != NULL) {
73 * g_error ("Error inserting event: %s", error->message);
74 * g_error_free (error);
75 * return NULL;
76 * }
77 *
78 * /<!-- -->* Do something with the new_event here, such as return it to the user or store its ID for later usage *<!-- -->/
79 *
80 * g_object_unref (new_event);
81 * </programlisting>
82 * </example>
83 */
84
85 #include <config.h>
86 #include <glib.h>
87 #include <glib/gi18n-lib.h>
88 #include <string.h>
89
90 #include "gdata-calendar-event.h"
91 #include "gdata-private.h"
92 #include "gdata-service.h"
93 #include "gdata-parser.h"
94 #include "gdata-types.h"
95 #include "gdata-comparable.h"
96
97 static GObject *gdata_calendar_event_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params);
98 static void gdata_calendar_event_dispose (GObject *object);
99 static void gdata_calendar_event_finalize (GObject *object);
100 static void gdata_calendar_event_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
101 static void gdata_calendar_event_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
102 static void get_json (GDataParsable *parsable, JsonBuilder *builder);
103 static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
104 static gboolean post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error);
105 static const gchar *get_content_type (void);
106
107 struct _GDataCalendarEventPrivate {
108 gint64 edited;
109 gchar *status;
110 gchar *visibility;
111 gchar *transparency;
112 gchar *uid;
113 gint64 sequence;
114 GList *times; /* GDataGDWhen */
115 gboolean guests_can_modify;
116 gboolean guests_can_invite_others;
117 gboolean guests_can_see_guests;
118 gboolean anyone_can_add_self;
119 GList *people; /* GDataGDWho */
120 GList *places; /* GDataGDWhere */
121 gchar *recurrence;
122 gchar *original_event_id;
123 gchar *original_event_uri;
124 gchar *organiser_email; /* owned */
125
126 /* Parsing state. */
127 struct {
128 gint64 start_time;
129 gint64 end_time;
130 gboolean seen_start;
131 gboolean seen_end;
132 gboolean start_is_date;
133 gboolean end_is_date;
134 } parser;
135 };
136
137 enum {
138 PROP_EDITED = 1,
139 PROP_STATUS,
140 PROP_VISIBILITY,
141 PROP_TRANSPARENCY,
142 PROP_UID,
143 PROP_SEQUENCE,
144 PROP_GUESTS_CAN_MODIFY,
145 PROP_GUESTS_CAN_INVITE_OTHERS,
146 PROP_GUESTS_CAN_SEE_GUESTS,
147 PROP_ANYONE_CAN_ADD_SELF,
148 PROP_RECURRENCE,
149 PROP_ORIGINAL_EVENT_ID,
150 PROP_ORIGINAL_EVENT_URI
151 };
152
G_DEFINE_TYPE(GDataCalendarEvent,gdata_calendar_event,GDATA_TYPE_ENTRY)153 G_DEFINE_TYPE (GDataCalendarEvent, gdata_calendar_event, GDATA_TYPE_ENTRY)
154
155 static void
156 gdata_calendar_event_class_init (GDataCalendarEventClass *klass)
157 {
158 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
159 GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
160 GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass);
161
162 g_type_class_add_private (klass, sizeof (GDataCalendarEventPrivate));
163
164 gobject_class->constructor = gdata_calendar_event_constructor;
165 gobject_class->get_property = gdata_calendar_event_get_property;
166 gobject_class->set_property = gdata_calendar_event_set_property;
167 gobject_class->dispose = gdata_calendar_event_dispose;
168 gobject_class->finalize = gdata_calendar_event_finalize;
169
170 parsable_class->parse_json = parse_json;
171 parsable_class->post_parse_json = post_parse_json;
172 parsable_class->get_json = get_json;
173 parsable_class->get_content_type = get_content_type;
174
175 entry_class->kind_term = "calendar#event";
176
177 /**
178 * GDataCalendarEvent:edited:
179 *
180 * The last time the event was edited. If the event has not been edited yet, the content indicates the time it was created.
181 *
182 * For more information, see the <ulink type="http" url="http://www.atomenabled.org/developers/protocol/#appEdited">
183 * Atom Publishing Protocol specification</ulink>.
184 */
185 g_object_class_install_property (gobject_class, PROP_EDITED,
186 g_param_spec_int64 ("edited",
187 "Edited", "The last time the event was edited.",
188 -1, G_MAXINT64, -1,
189 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
190
191 /**
192 * GDataCalendarEvent:status:
193 *
194 * The scheduling status of the event. For example: %GDATA_GD_EVENT_STATUS_CANCELED or %GDATA_GD_EVENT_STATUS_CONFIRMED.
195 *
196 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdEventStatus">
197 * GData specification</ulink>.
198 *
199 * Since: 0.2.0
200 */
201 g_object_class_install_property (gobject_class, PROP_STATUS,
202 g_param_spec_string ("status",
203 "Status", "The scheduling status of the event.",
204 NULL,
205 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206
207 /**
208 * GDataCalendarEvent:visibility:
209 *
210 * The event's visibility to calendar users. For example: %GDATA_GD_EVENT_VISIBILITY_PUBLIC or %GDATA_GD_EVENT_VISIBILITY_DEFAULT.
211 *
212 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdVisibility">
213 * GData specification</ulink>.
214 */
215 g_object_class_install_property (gobject_class, PROP_VISIBILITY,
216 g_param_spec_string ("visibility",
217 "Visibility", "The event's visibility to calendar users.",
218 NULL,
219 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
220
221 /**
222 * GDataCalendarEvent:transparency:
223 *
224 * How the event is marked as consuming time on a calendar. For example: %GDATA_GD_EVENT_TRANSPARENCY_OPAQUE or
225 * %GDATA_GD_EVENT_TRANSPARENCY_TRANSPARENT.
226 *
227 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdTransparency">
228 * GData specification</ulink>.
229 */
230 g_object_class_install_property (gobject_class, PROP_TRANSPARENCY,
231 g_param_spec_string ("transparency",
232 "Transparency", "How the event is marked as consuming time on a calendar.",
233 NULL,
234 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
235
236 /**
237 * GDataCalendarEvent:uid:
238 *
239 * The globally unique identifier (UID) of the event as defined in Section 4.8.4.7 of <ulink type="http"
240 * url="http://www.ietf.org/rfc/rfc2445.txt">RFC 2445</ulink>.
241 */
242 g_object_class_install_property (gobject_class, PROP_UID,
243 g_param_spec_string ("uid",
244 "UID", "The globally unique identifier (UID) of the event.",
245 NULL,
246 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
247
248 /**
249 * GDataCalendarEvent:sequence:
250 *
251 * The revision sequence number of the event as defined in Section 4.8.7.4 of <ulink type="http"
252 * url="http://www.ietf.org/rfc/rfc2445.txt">RFC 2445</ulink>.
253 */
254 g_object_class_install_property (gobject_class, PROP_SEQUENCE,
255 g_param_spec_uint ("sequence",
256 "Sequence", "The revision sequence number of the event.",
257 0, G_MAXUINT, 0,
258 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
259
260 /**
261 * GDataCalendarEvent:guests-can-modify:
262 *
263 * Indicates whether attendees may modify the original event, so that changes are visible to organizers and other attendees.
264 * Otherwise, any changes made by attendees will be restricted to that attendee's calendar.
265 *
266 * For more information, see the
267 * <ulink type="http" url="https://developers.google.com/google-apps/calendar/v3/reference/events#guestsCanInviteOthers">
268 * GData specification</ulink>.
269 */
270 g_object_class_install_property (gobject_class, PROP_GUESTS_CAN_MODIFY,
271 g_param_spec_boolean ("guests-can-modify",
272 "Guests can modify", "Indicates whether attendees may modify the original event.",
273 FALSE,
274 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
275
276 /**
277 * GDataCalendarEvent:guests-can-invite-others:
278 *
279 * Indicates whether attendees may invite others to the event.
280 *
281 * For more information, see the <ulink type="http"
282 * url="https://developers.google.com/google-apps/calendar/v3/reference/events#guestsCanInviteOthers">GData specification</ulink>.
283 */
284 g_object_class_install_property (gobject_class, PROP_GUESTS_CAN_INVITE_OTHERS,
285 g_param_spec_boolean ("guests-can-invite-others",
286 "Guests can invite others", "Indicates whether attendees may invite others.",
287 FALSE,
288 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
289
290 /**
291 * GDataCalendarEvent:guests-can-see-guests:
292 *
293 * Indicates whether attendees can see other people invited to the event.
294 *
295 * For more information, see the
296 * <ulink type="http" url="https://developers.google.com/google-apps/calendar/v3/reference/events#guestsCanSeeOtherGuests">
297 * GData specification</ulink>.
298 */
299 g_object_class_install_property (gobject_class, PROP_GUESTS_CAN_SEE_GUESTS,
300 g_param_spec_boolean ("guests-can-see-guests",
301 "Guests can see guests", "Indicates whether attendees can see other people invited.",
302 FALSE,
303 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
304
305 /**
306 * GDataCalendarEvent:anyone-can-add-self:
307 *
308 * Indicates whether anyone can invite themselves to the event, by adding themselves to the attendee list.
309 */
310 g_object_class_install_property (gobject_class, PROP_ANYONE_CAN_ADD_SELF,
311 g_param_spec_boolean ("anyone-can-add-self",
312 "Anyone can add self", "Indicates whether anyone can invite themselves to the event.",
313 FALSE,
314 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
315
316 /**
317 * GDataCalendarEvent:recurrence:
318 *
319 * Represents the dates and times when a recurring event takes place. The returned string is in iCal format, as a list of properties.
320 *
321 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdRecurrence">
322 * GData specification</ulink>.
323 *
324 * Note: gdata_calendar_event_add_time() and gdata_calendar_event_set_recurrence() are mutually
325 * exclusive. See the documentation for gdata_calendar_event_add_time() for details.
326 *
327 * Since: 0.3.0
328 */
329 g_object_class_install_property (gobject_class, PROP_RECURRENCE,
330 g_param_spec_string ("recurrence",
331 "Recurrence", "Represents the dates and times when a recurring event takes place.",
332 NULL,
333 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
334
335 /**
336 * GDataCalendarEvent:original-event-id:
337 *
338 * The event ID for the original event, if this event is an exception to a recurring event.
339 *
340 * Since: 0.3.0
341 */
342 g_object_class_install_property (gobject_class, PROP_ORIGINAL_EVENT_ID,
343 g_param_spec_string ("original-event-id",
344 "Original event ID", "The event ID for the original event.",
345 NULL,
346 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
347
348 /**
349 * GDataCalendarEvent:original-event-uri:
350 *
351 * The event URI for the original event, if this event is an exception to a recurring event.
352 *
353 * Since: 0.3.0
354 */
355 g_object_class_install_property (gobject_class, PROP_ORIGINAL_EVENT_URI,
356 g_param_spec_string ("original-event-uri",
357 "Original event URI", "The event URI for the original event.",
358 NULL,
359 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
360 }
361
362 static void
gdata_calendar_event_init(GDataCalendarEvent * self)363 gdata_calendar_event_init (GDataCalendarEvent *self)
364 {
365 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_CALENDAR_EVENT, GDataCalendarEventPrivate);
366 self->priv->edited = -1;
367 }
368
369 static GObject *
gdata_calendar_event_constructor(GType type,guint n_construct_params,GObjectConstructParam * construct_params)370 gdata_calendar_event_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params)
371 {
372 GObject *object;
373
374 /* Chain up to the parent class */
375 object = G_OBJECT_CLASS (gdata_calendar_event_parent_class)->constructor (type, n_construct_params, construct_params);
376
377 if (_gdata_parsable_is_constructed_from_xml (GDATA_PARSABLE (object)) == FALSE) {
378 GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (object)->priv;
379 GTimeVal time_val;
380
381 /* Set the edited property to the current time (creation time). We don't do this in *_init() since that would cause
382 * setting it from parse_xml() to fail (duplicate element). */
383 g_get_current_time (&time_val);
384 priv->edited = time_val.tv_sec;
385 }
386
387 return object;
388 }
389
390 static void
gdata_calendar_event_dispose(GObject * object)391 gdata_calendar_event_dispose (GObject *object)
392 {
393 GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (object)->priv;
394
395 g_list_free_full(priv->times, g_object_unref);
396 priv->times = NULL;
397
398 g_list_free_full (priv->people, g_object_unref);
399 priv->people = NULL;
400
401 g_list_free_full (priv->places, g_object_unref);
402 priv->places = NULL;
403
404 /* Chain up to the parent class */
405 G_OBJECT_CLASS (gdata_calendar_event_parent_class)->dispose (object);
406 }
407
408 static void
gdata_calendar_event_finalize(GObject * object)409 gdata_calendar_event_finalize (GObject *object)
410 {
411 GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (object)->priv;
412
413 g_free (priv->status);
414 g_free (priv->visibility);
415 g_free (priv->transparency);
416 g_free (priv->uid);
417 g_free (priv->recurrence);
418 g_free (priv->original_event_id);
419 g_free (priv->original_event_uri);
420 g_free (priv->organiser_email);
421
422 /* Chain up to the parent class */
423 G_OBJECT_CLASS (gdata_calendar_event_parent_class)->finalize (object);
424 }
425
426 static void
gdata_calendar_event_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)427 gdata_calendar_event_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
428 {
429 GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (object)->priv;
430
431 switch (property_id) {
432 case PROP_EDITED:
433 g_value_set_int64 (value, priv->edited);
434 break;
435 case PROP_STATUS:
436 g_value_set_string (value, priv->status);
437 break;
438 case PROP_VISIBILITY:
439 g_value_set_string (value, priv->visibility);
440 break;
441 case PROP_TRANSPARENCY:
442 g_value_set_string (value, priv->transparency);
443 break;
444 case PROP_UID:
445 g_value_set_string (value, priv->uid);
446 break;
447 case PROP_SEQUENCE:
448 g_value_set_uint (value, CLAMP (priv->sequence, 0, G_MAXUINT));
449 break;
450 case PROP_GUESTS_CAN_MODIFY:
451 g_value_set_boolean (value, priv->guests_can_modify);
452 break;
453 case PROP_GUESTS_CAN_INVITE_OTHERS:
454 g_value_set_boolean (value, priv->guests_can_invite_others);
455 break;
456 case PROP_GUESTS_CAN_SEE_GUESTS:
457 g_value_set_boolean (value, priv->guests_can_see_guests);
458 break;
459 case PROP_ANYONE_CAN_ADD_SELF:
460 g_value_set_boolean (value, priv->anyone_can_add_self);
461 break;
462 case PROP_RECURRENCE:
463 g_value_set_string (value, priv->recurrence);
464 break;
465 case PROP_ORIGINAL_EVENT_ID:
466 g_value_set_string (value, priv->original_event_id);
467 break;
468 case PROP_ORIGINAL_EVENT_URI:
469 g_value_set_string (value, priv->original_event_uri);
470 break;
471 default:
472 /* We don't have any other property... */
473 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
474 break;
475 }
476 }
477
478 static void
gdata_calendar_event_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)479 gdata_calendar_event_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
480 {
481 GDataCalendarEvent *self = GDATA_CALENDAR_EVENT (object);
482
483 switch (property_id) {
484 case PROP_STATUS:
485 gdata_calendar_event_set_status (self, g_value_get_string (value));
486 break;
487 case PROP_VISIBILITY:
488 gdata_calendar_event_set_visibility (self, g_value_get_string (value));
489 break;
490 case PROP_TRANSPARENCY:
491 gdata_calendar_event_set_transparency (self, g_value_get_string (value));
492 break;
493 case PROP_UID:
494 gdata_calendar_event_set_uid (self, g_value_get_string (value));
495 break;
496 case PROP_SEQUENCE:
497 gdata_calendar_event_set_sequence (self, g_value_get_uint (value));
498 break;
499 case PROP_GUESTS_CAN_MODIFY:
500 gdata_calendar_event_set_guests_can_modify (self, g_value_get_boolean (value));
501 break;
502 case PROP_GUESTS_CAN_INVITE_OTHERS:
503 gdata_calendar_event_set_guests_can_invite_others (self, g_value_get_boolean (value));
504 break;
505 case PROP_GUESTS_CAN_SEE_GUESTS:
506 gdata_calendar_event_set_guests_can_see_guests (self, g_value_get_boolean (value));
507 break;
508 case PROP_ANYONE_CAN_ADD_SELF:
509 gdata_calendar_event_set_anyone_can_add_self (self, g_value_get_boolean (value));
510 break;
511 case PROP_RECURRENCE:
512 gdata_calendar_event_set_recurrence (self, g_value_get_string (value));
513 break;
514 default:
515 /* We don't have any other property... */
516 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
517 break;
518 }
519 }
520
521 static gboolean
date_object_from_json(JsonReader * reader,const gchar * member_name,GDataParserOptions options,gint64 * date_time_output,gboolean * is_date_output,gboolean * success,GError ** error)522 date_object_from_json (JsonReader *reader,
523 const gchar *member_name,
524 GDataParserOptions options,
525 gint64 *date_time_output,
526 gboolean *is_date_output,
527 gboolean *success,
528 GError **error)
529 {
530 gint64 date_time;
531 gboolean is_date = FALSE;
532 gboolean found_member = FALSE;
533
534 /* Check if there’s such an element */
535 if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) {
536 return FALSE;
537 }
538
539 /* Check that it’s an object. */
540 if (!json_reader_is_object (reader)) {
541 const GError *child_error;
542
543 /* Manufacture an error. */
544 json_reader_read_member (reader, "dateTime");
545 child_error = json_reader_get_error (reader);
546 g_assert (child_error != NULL);
547 *success = gdata_parser_error_from_json_error (reader,
548 child_error,
549 error);
550 json_reader_end_member (reader);
551
552 return TRUE;
553 }
554
555 /* Try to parse either the dateTime or date member. */
556 if (json_reader_read_member (reader, "dateTime")) {
557 const gchar *date_string;
558 const GError *child_error;
559 GTimeVal time_val;
560
561 date_string = json_reader_get_string_value (reader);
562 child_error = json_reader_get_error (reader);
563
564 if (child_error != NULL) {
565 *success = gdata_parser_error_from_json_error (reader,
566 child_error,
567 error);
568 json_reader_end_member (reader);
569 return TRUE;
570 }
571
572 if (!g_time_val_from_iso8601 (date_string, &time_val)) {
573 *success = gdata_parser_error_not_iso8601_format_json (reader, date_string, error);
574 json_reader_end_member (reader);
575 return TRUE;
576 }
577
578 date_time = time_val.tv_sec;
579 is_date = FALSE;
580 found_member = TRUE;
581 }
582 json_reader_end_member (reader);
583
584 if (json_reader_read_member (reader, "date")) {
585 const gchar *date_string;
586 const GError *child_error;
587
588 date_string = json_reader_get_string_value (reader);
589 child_error = json_reader_get_error (reader);
590
591 if (child_error != NULL) {
592 *success = gdata_parser_error_from_json_error (reader,
593 child_error,
594 error);
595 json_reader_end_member (reader);
596 return TRUE;
597 }
598
599 if (!gdata_parser_int64_from_date (date_string, &date_time)) {
600 *success = gdata_parser_error_not_iso8601_format_json (reader, date_string, error);
601 json_reader_end_member (reader);
602 return TRUE;
603 }
604
605 is_date = TRUE;
606 found_member = TRUE;
607 }
608 json_reader_end_member (reader);
609
610 /* Ignore timeZone; it should be specified in dateTime. */
611 if (!found_member) {
612 *success = gdata_parser_error_required_json_content_missing (reader, error);
613 return TRUE;
614 }
615
616 *date_time_output = date_time;
617 *is_date_output = is_date;
618 *success = TRUE;
619
620 return TRUE;
621 }
622
623 /* Convert between v2 and v3 versions of various enum values. v2 uses a URI
624 * style with a constant prefix; v3 simply drops this prefix, and changes the
625 * spelling of ‘canceled’ to ‘cancelled’. */
626 #define V2_PREFIX "http://schemas.google.com/g/2005#event."
627
628 static gchar *
add_v2_prefix(const gchar * in)629 add_v2_prefix (const gchar *in)
630 {
631 return g_strconcat (V2_PREFIX, in, NULL);
632 }
633
634 static const gchar *
strip_v2_prefix(const gchar * uri)635 strip_v2_prefix (const gchar *uri)
636 {
637 /* Convert to v3 format. */
638 if (g_str_has_prefix (uri, V2_PREFIX)) {
639 return uri + strlen (V2_PREFIX);
640 } else {
641 return uri;
642 }
643 }
644
645 static gboolean
parse_json(GDataParsable * parsable,JsonReader * reader,gpointer user_data,GError ** error)646 parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
647 {
648 gboolean success;
649 GDataCalendarEvent *self = GDATA_CALENDAR_EVENT (parsable);
650 GDataCalendarEventPrivate *priv = self->priv;
651
652 /* FIXME: Currently unsupported:
653 * - htmlLink
654 * - colorId
655 * - endTimeUnspecified
656 * - originalStartTime
657 * - attendeesOmitted
658 * - extendedProperties
659 * - hangoutLink
660 * - gadget
661 * - privateCopy
662 * - locked
663 * - reminders
664 * - source
665 */
666
667 if (g_strcmp0 (json_reader_get_member_name (reader), "start") == 0) {
668 self->priv->parser.seen_start = TRUE;
669 } else if (g_strcmp0 (json_reader_get_member_name (reader), "end") == 0) {
670 self->priv->parser.seen_end = TRUE;
671 }
672
673 if (gdata_parser_string_from_json_member (reader, "recurringEventId", P_DEFAULT, &self->priv->original_event_id, &success, error) ||
674 gdata_parser_boolean_from_json_member (reader, "guestsCanModify", P_DEFAULT, &self->priv->guests_can_modify, &success, error) ||
675 gdata_parser_boolean_from_json_member (reader, "guestsCanInviteOthers", P_DEFAULT, &self->priv->guests_can_invite_others, &success, error) ||
676 gdata_parser_boolean_from_json_member (reader, "guestsCanSeeOtherGuests", P_DEFAULT, &self->priv->guests_can_see_guests, &success, error) ||
677 gdata_parser_boolean_from_json_member (reader, "anyoneCanAddSelf", P_DEFAULT, &self->priv->anyone_can_add_self, &success, error) ||
678 gdata_parser_string_from_json_member (reader, "iCalUID", P_DEFAULT, &self->priv->uid, &success, error) ||
679 gdata_parser_int_from_json_member (reader, "sequence", P_DEFAULT, &self->priv->sequence, &success, error) ||
680 gdata_parser_int64_time_from_json_member (reader, "updated", P_DEFAULT, &self->priv->edited, &success, error) ||
681 date_object_from_json (reader, "start", P_DEFAULT, &self->priv->parser.start_time, &self->priv->parser.start_is_date, &success, error) ||
682 date_object_from_json (reader, "end", P_DEFAULT, &self->priv->parser.end_time, &self->priv->parser.end_is_date, &success, error)) {
683 if (success) {
684 if (self->priv->edited != -1) {
685 _gdata_entry_set_updated (GDATA_ENTRY (parsable),
686 self->priv->edited);
687 }
688
689 if (self->priv->original_event_id != NULL) {
690 g_free (self->priv->original_event_uri);
691 self->priv->original_event_uri = g_strconcat ("https://www.googleapis.com/calendar/v3/events/",
692 self->priv->original_event_id, NULL);
693 }
694
695 if (self->priv->parser.seen_start && self->priv->parser.seen_end) {
696 GDataGDWhen *when;
697
698 when = gdata_gd_when_new (self->priv->parser.start_time,
699 self->priv->parser.end_time,
700 self->priv->parser.start_is_date ||
701 self->priv->parser.end_is_date);
702 self->priv->times = g_list_prepend (self->priv->times, when); /* transfer ownership */
703
704 self->priv->parser.seen_start = FALSE;
705 self->priv->parser.seen_end = FALSE;
706 }
707 }
708
709 return success;
710 } else if (g_strcmp0 (json_reader_get_member_name (reader), "transparency") == 0) {
711 gchar *transparency = NULL; /* owned */
712
713 g_assert (gdata_parser_string_from_json_member (reader,
714 "transparency",
715 P_DEFAULT,
716 &transparency,
717 &success,
718 error));
719
720 if (success) {
721 priv->transparency = add_v2_prefix (transparency);
722 }
723
724 g_free (transparency);
725
726 return success;
727 } else if (g_strcmp0 (json_reader_get_member_name (reader), "visibility") == 0) {
728 gchar *visibility = NULL; /* owned */
729
730 g_assert (gdata_parser_string_from_json_member (reader,
731 "visibility",
732 P_DEFAULT,
733 &visibility,
734 &success,
735 error));
736
737 if (success) {
738 priv->visibility = add_v2_prefix (visibility);
739 }
740
741 g_free (visibility);
742
743 return success;
744 } else if (g_strcmp0 (json_reader_get_member_name (reader), "status") == 0) {
745 gchar *status = NULL; /* owned */
746
747 g_assert (gdata_parser_string_from_json_member (reader,
748 "status",
749 P_DEFAULT,
750 &status,
751 &success,
752 error));
753
754 if (success) {
755 if (g_strcmp0 (status, "cancelled") == 0) {
756 /* Those damned British Englishes. */
757 priv->status = add_v2_prefix ("canceled");
758 } else {
759 priv->status = add_v2_prefix (status);
760 }
761 }
762
763 g_free (status);
764
765 return success;
766 } else if (g_strcmp0 (json_reader_get_member_name (reader), "summary") == 0) {
767 const gchar *summary;
768 const GError *child_error = NULL;
769
770 summary = json_reader_get_string_value (reader);
771 child_error = json_reader_get_error (reader);
772
773 if (child_error != NULL) {
774 gdata_parser_error_from_json_error (reader,
775 child_error, error);
776 return FALSE;
777 }
778
779 gdata_entry_set_title (GDATA_ENTRY (parsable), summary);
780 } else if (g_strcmp0 (json_reader_get_member_name (reader), "description") == 0) {
781 const gchar *description;
782 const GError *child_error = NULL;
783
784 description = json_reader_get_string_value (reader);
785 child_error = json_reader_get_error (reader);
786
787 if (child_error != NULL) {
788 gdata_parser_error_from_json_error (reader,
789 child_error, error);
790 return FALSE;
791 }
792
793 gdata_entry_set_content (GDATA_ENTRY (parsable), description);
794 } else if (g_strcmp0 (json_reader_get_member_name (reader), "location") == 0) {
795 const gchar *location;
796 GDataGDWhere *where = NULL; /* owned */
797 const GError *child_error = NULL;
798
799 location = json_reader_get_string_value (reader);
800 child_error = json_reader_get_error (reader);
801
802 if (child_error != NULL) {
803 gdata_parser_error_from_json_error (reader,
804 child_error, error);
805 return FALSE;
806 }
807
808 where = gdata_gd_where_new (GDATA_GD_WHERE_EVENT,
809 location, NULL);
810 priv->places = g_list_prepend (priv->places, where); /* transfer ownership */
811 } else if (g_strcmp0 (json_reader_get_member_name (reader), "created") == 0) {
812 gint64 created;
813
814 g_assert (gdata_parser_int64_time_from_json_member (reader,
815 "created",
816 P_DEFAULT,
817 &created,
818 &success,
819 error));
820
821 if (success) {
822 _gdata_entry_set_published (GDATA_ENTRY (parsable),
823 created);
824 }
825
826 return success;
827 } else if (g_strcmp0 (json_reader_get_member_name (reader), "recurrence") == 0) {
828 guint i, j;
829 GString *recurrence = NULL; /* owned */
830
831 /* In the JSON API, the recurrence is given as an array of
832 * strings, each giving an RFC 2445 property such as RRULE,
833 * EXRULE, RDATE or EXDATE. Concatenate them all to form a
834 * recurrence string as used in v2 of the API. */
835 if (self->priv->recurrence != NULL) {
836 return gdata_parser_error_duplicate_json_element (reader,
837 error);
838 }
839
840 recurrence = g_string_new ("");
841
842 for (i = 0, j = json_reader_count_elements (reader); i < j; i++) {
843 const gchar *line;
844 const GError *child_error;
845
846 json_reader_read_element (reader, i);
847
848 line = json_reader_get_string_value (reader);
849 child_error = json_reader_get_error (reader);
850 if (child_error != NULL) {
851 gdata_parser_error_from_json_error (reader, child_error, error);
852 json_reader_end_element (reader);
853 return FALSE;
854 }
855
856 g_string_append (recurrence, line);
857 g_string_append (recurrence, "\n");
858
859 json_reader_end_element (reader);
860 }
861
862 g_assert (self->priv->recurrence == NULL);
863 self->priv->recurrence = g_string_free (recurrence, FALSE);
864
865 return TRUE;
866 } else if (g_strcmp0 (json_reader_get_member_name (reader), "attendees") == 0) {
867 guint i, j;
868
869 if (priv->people != NULL) {
870 return gdata_parser_error_duplicate_json_element (reader,
871 error);
872 }
873
874 for (i = 0, j = json_reader_count_elements (reader); i < j; i++) {
875 GDataGDWho *who = NULL; /* owned */
876 const gchar *email_address, *value_string;
877 const gchar *relation_type;
878 gboolean is_organizer, is_resource;
879 const GError *child_error;
880
881 json_reader_read_element (reader, i);
882
883 json_reader_read_member (reader, "responseStatus");
884 child_error = json_reader_get_error (reader);
885 if (child_error != NULL) {
886 gdata_parser_error_from_json_error (reader,
887 child_error,
888 error);
889 json_reader_end_member (reader);
890 return FALSE;
891 }
892 json_reader_end_member (reader);
893
894 json_reader_read_member (reader, "email");
895 email_address = json_reader_get_string_value (reader);
896 json_reader_end_member (reader);
897
898 json_reader_read_member (reader, "displayName");
899 value_string = json_reader_get_string_value (reader);
900 json_reader_end_member (reader);
901
902 json_reader_read_member (reader, "organizer");
903 is_organizer = json_reader_get_boolean_value (reader);
904 json_reader_end_member (reader);
905
906 json_reader_read_member (reader, "resource");
907 is_resource = json_reader_get_boolean_value (reader);
908 json_reader_end_member (reader);
909
910 /* FIXME: Currently unsupported:
911 * - id
912 * - self
913 * - optional (writeble)
914 * - responseStatus (writeble)
915 * - comment (writeble)
916 * - additionalGuests (writeble)
917 */
918
919 if (is_organizer) {
920 relation_type = GDATA_GD_WHO_EVENT_ORGANIZER;
921 } else if (!is_resource) {
922 relation_type = GDATA_GD_WHO_EVENT_ATTENDEE;
923 } else {
924 /* FIXME: Add support for resources. */
925 relation_type = NULL;
926 }
927
928 who = gdata_gd_who_new (relation_type, value_string,
929 email_address);
930 priv->people = g_list_prepend (priv->people, who); /* transfer ownership */
931
932 json_reader_end_element (reader);
933 }
934 } else if (g_strcmp0 (json_reader_get_member_name (reader), "organizer") == 0) {
935 /* This actually gives the parent calendar. Optional. */
936 g_clear_pointer (&priv->organiser_email, g_free);
937 if (json_reader_read_member (reader, "email"))
938 priv->organiser_email = g_strdup (json_reader_get_string_value (reader));
939 json_reader_end_member (reader);
940
941 return TRUE;
942 } else if (g_strcmp0 (json_reader_get_member_name (reader), "creator") == 0) {
943 /* These are read-only and already handled as part of
944 * ‘attendees’, so ignore them. */
945 return TRUE;
946 } else {
947 return GDATA_PARSABLE_CLASS (gdata_calendar_event_parent_class)->parse_json (parsable, reader, user_data, error);
948 }
949
950 return TRUE;
951 }
952
953 static gboolean
post_parse_json(GDataParsable * parsable,gpointer user_data,GError ** error)954 post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error)
955 {
956 GDataLink *_link = NULL; /* owned */
957 const gchar *id, *calendar_id;
958 gchar *uri = NULL; /* owned */
959 GDataCalendarEventPrivate *priv;
960
961 priv = GDATA_CALENDAR_EVENT (parsable)->priv;
962
963 /* Set the self link, which is needed for gdata_service_delete_entry().
964 * Unfortunately, it needs the event ID _and_ the calendar ID — which
965 * is perversely only available as the organiser e-mail address. */
966 id = gdata_entry_get_id (GDATA_ENTRY (parsable));
967 calendar_id = priv->organiser_email;
968
969 if (id == NULL || calendar_id == NULL) {
970 return TRUE;
971 }
972
973 uri = g_strconcat ("https://www.googleapis.com/calendar/v3/calendars/",
974 calendar_id, "/events/", id, NULL);
975 _link = gdata_link_new (uri, GDATA_LINK_SELF);
976 gdata_entry_add_link (GDATA_ENTRY (parsable), _link);
977 g_object_unref (_link);
978 g_free (uri);
979
980 return TRUE;
981 }
982
983 static void
get_json(GDataParsable * parsable,JsonBuilder * builder)984 get_json (GDataParsable *parsable, JsonBuilder *builder)
985 {
986 GList *l;
987 const gchar *id, *etag, *title, *description;
988 GDataGDWho *organiser_who = NULL; /* unowned */
989 GDataCalendarEventPrivate *priv = GDATA_CALENDAR_EVENT (parsable)->priv;
990
991 /* FIXME: Support:
992 * - colorId
993 * - attendeesOmitted
994 * - extendedProperties
995 * - gadget
996 * - reminders
997 * - source
998 */
999
1000 id = gdata_entry_get_id (GDATA_ENTRY (parsable));
1001 if (id != NULL) {
1002 json_builder_set_member_name (builder, "id");
1003 json_builder_add_string_value (builder, id);
1004 }
1005
1006 json_builder_set_member_name (builder, "kind");
1007 json_builder_add_string_value (builder, "calendar#event");
1008
1009 /* Add the ETag, if available. */
1010 etag = gdata_entry_get_etag (GDATA_ENTRY (parsable));
1011 if (etag != NULL) {
1012 json_builder_set_member_name (builder, "etag");
1013 json_builder_add_string_value (builder, etag);
1014 }
1015
1016 /* Calendar labels titles as ‘summary’. */
1017 title = gdata_entry_get_title (GDATA_ENTRY (parsable));
1018 if (title != NULL) {
1019 json_builder_set_member_name (builder, "summary");
1020 json_builder_add_string_value (builder, title);
1021 }
1022
1023 description = gdata_entry_get_content (GDATA_ENTRY (parsable));
1024 if (description != NULL) {
1025 json_builder_set_member_name (builder, "description");
1026 json_builder_add_string_value (builder, description);
1027 }
1028
1029 /* Add all the calendar-specific JSON */
1030 json_builder_set_member_name (builder, "anyoneCanAddSelf");
1031 json_builder_add_boolean_value (builder, priv->anyone_can_add_self);
1032
1033 json_builder_set_member_name (builder, "guestsCanInviteOthers");
1034 json_builder_add_boolean_value (builder, priv->guests_can_invite_others);
1035
1036 json_builder_set_member_name (builder, "guestsCanModify");
1037 json_builder_add_boolean_value (builder, priv->guests_can_modify);
1038
1039 json_builder_set_member_name (builder, "guestsCanSeeOtherGuests");
1040 json_builder_add_boolean_value (builder, priv->guests_can_see_guests);
1041
1042 if (priv->transparency != NULL) {
1043 json_builder_set_member_name (builder, "transparency");
1044 json_builder_add_string_value (builder,
1045 strip_v2_prefix (priv->transparency));
1046 }
1047
1048 if (priv->visibility != NULL) {
1049 json_builder_set_member_name (builder, "visibility");
1050 json_builder_add_string_value (builder,
1051 strip_v2_prefix (priv->visibility));
1052 }
1053
1054 if (priv->uid != NULL) {
1055 json_builder_set_member_name (builder, "iCalUID");
1056 json_builder_add_string_value (builder, priv->uid);
1057 }
1058
1059 if (priv->sequence > 0) {
1060 json_builder_set_member_name (builder, "sequence");
1061 json_builder_add_int_value (builder, priv->sequence);
1062 }
1063
1064 if (priv->status != NULL) {
1065 const gchar *status;
1066
1067 /* Convert to v3 format. */
1068 status = strip_v2_prefix (priv->status);
1069 if (g_strcmp0 (status, "canceled") == 0) {
1070 status = "cancelled";
1071 }
1072
1073 json_builder_set_member_name (builder, "status");
1074 json_builder_add_string_value (builder, status);
1075 }
1076
1077 if (priv->recurrence != NULL) {
1078 gchar **parts;
1079 guint i;
1080
1081 json_builder_set_member_name (builder, "recurrence");
1082 json_builder_begin_array (builder);
1083
1084 parts = g_strsplit (priv->recurrence, "\n", -1);
1085
1086 for (i = 0; parts[i] != NULL; i++) {
1087 json_builder_add_string_value (builder, parts[i]);
1088 }
1089
1090 g_strfreev (parts);
1091
1092 json_builder_end_array (builder);
1093 }
1094
1095 if (priv->original_event_id != NULL) {
1096 json_builder_set_member_name (builder, "recurringEventId");
1097 json_builder_add_string_value (builder, priv->original_event_id);
1098 }
1099
1100 /* Times. */
1101 for (l = priv->times; l != NULL; l = l->next) {
1102 GDataGDWhen *when; /* unowned */
1103 gchar *val = NULL; /* owned */
1104 const gchar *member_name;
1105 gint64 start_time, end_time;
1106
1107 when = l->data;
1108
1109 /* Start time. */
1110 start_time = gdata_gd_when_get_start_time (when);
1111 json_builder_set_member_name (builder, "start");
1112 json_builder_begin_object (builder);
1113
1114 if (gdata_gd_when_is_date (when)) {
1115 member_name = "date";
1116 val = gdata_parser_date_from_int64 (start_time);
1117 } else {
1118 member_name = "dateTime";
1119 val = gdata_parser_int64_to_iso8601 (start_time);
1120 }
1121
1122 json_builder_set_member_name (builder, member_name);
1123 json_builder_add_string_value (builder, val);
1124 g_free (val);
1125
1126 json_builder_set_member_name (builder, "timeZone");
1127 json_builder_add_string_value (builder, "UTC");
1128
1129 json_builder_end_object (builder);
1130
1131 /* End time. */
1132 end_time = gdata_gd_when_get_end_time (when);
1133
1134 if (end_time > -1) {
1135 json_builder_set_member_name (builder, "end");
1136 json_builder_begin_object (builder);
1137
1138 if (gdata_gd_when_is_date (when)) {
1139 member_name = "date";
1140 val = gdata_parser_date_from_int64 (end_time);
1141 } else {
1142 member_name = "dateTime";
1143 val = gdata_parser_int64_to_iso8601 (end_time);
1144 }
1145
1146 json_builder_set_member_name (builder, member_name);
1147 json_builder_add_string_value (builder, val);
1148 g_free (val);
1149
1150 json_builder_set_member_name (builder, "timeZone");
1151 json_builder_add_string_value (builder, "UTC");
1152
1153 json_builder_end_object (builder);
1154 } else {
1155 json_builder_set_member_name (builder, "endTimeUnspecified");
1156 json_builder_add_boolean_value (builder, TRUE);
1157 }
1158
1159 /* Only use the first time. :-(
1160 * FIXME: There must be a better solution. */
1161 if (l->next != NULL) {
1162 g_warning ("Ignoring secondary times; they are no "
1163 "longer supported by the server-side API.");
1164 break;
1165 }
1166 }
1167
1168 /* Locations. */
1169 for (l = priv->places; l != NULL; l = l->next) {
1170 GDataGDWhere *where; /* unowned */
1171 const gchar *location;
1172
1173 where = l->data;
1174 location = gdata_gd_where_get_value_string (where);
1175
1176 json_builder_set_member_name (builder, "location");
1177 json_builder_add_string_value (builder, location);
1178
1179 /* Only use the first location. :-(
1180 * FIXME: There must be a better solution. */
1181 if (l->next != NULL) {
1182 g_warning ("Ignoring secondary locations; they are no "
1183 "longer supported by the server-side API.");
1184 break;
1185 }
1186 }
1187
1188 /* People. */
1189 json_builder_set_member_name (builder, "attendees");
1190 json_builder_begin_array (builder);
1191
1192 for (l = priv->people; l != NULL; l = l->next) {
1193 GDataGDWho *who; /* unowned */
1194 const gchar *display_name, *email_address;
1195
1196 who = l->data;
1197
1198 json_builder_begin_object (builder);
1199
1200 display_name = gdata_gd_who_get_value_string (who);
1201 if (display_name != NULL) {
1202 json_builder_set_member_name (builder, "displayName");
1203 json_builder_add_string_value (builder, display_name);
1204 }
1205
1206 email_address = gdata_gd_who_get_email_address (who);
1207 if (email_address != NULL) {
1208 json_builder_set_member_name (builder, "email");
1209 json_builder_add_string_value (builder, email_address);
1210 }
1211
1212 if (g_strcmp0 (gdata_gd_who_get_relation_type (who),
1213 GDATA_GD_WHO_EVENT_ORGANIZER) == 0) {
1214 json_builder_set_member_name (builder, "organizer");
1215 json_builder_add_boolean_value (builder, TRUE);
1216
1217 organiser_who = who;
1218 }
1219
1220 json_builder_end_object (builder);
1221 }
1222
1223 json_builder_end_array (builder);
1224
1225 if (organiser_who != NULL) {
1226 const gchar *display_name, *email_address;
1227
1228 json_builder_set_member_name (builder, "organizer");
1229 json_builder_begin_object (builder);
1230
1231 display_name = gdata_gd_who_get_value_string (organiser_who);
1232 if (display_name != NULL) {
1233 json_builder_set_member_name (builder, "displayName");
1234 json_builder_add_string_value (builder, display_name);
1235 }
1236
1237 email_address = gdata_gd_who_get_email_address (organiser_who);
1238 if (email_address != NULL) {
1239 json_builder_set_member_name (builder, "email");
1240 json_builder_add_string_value (builder, email_address);
1241 }
1242
1243 json_builder_end_object (builder);
1244 }
1245 }
1246
1247 static const gchar *
get_content_type(void)1248 get_content_type (void)
1249 {
1250 return "application/json";
1251 }
1252
1253 /**
1254 * gdata_calendar_event_new:
1255 * @id: (allow-none): the event's ID, or %NULL
1256 *
1257 * Creates a new #GDataCalendarEvent with the given ID and default properties.
1258 *
1259 * Return value: a new #GDataCalendarEvent; unref with g_object_unref()
1260 */
1261 GDataCalendarEvent *
gdata_calendar_event_new(const gchar * id)1262 gdata_calendar_event_new (const gchar *id)
1263 {
1264 return GDATA_CALENDAR_EVENT (g_object_new (GDATA_TYPE_CALENDAR_EVENT, "id", id, NULL));
1265 }
1266
1267 /**
1268 * gdata_calendar_event_get_edited:
1269 * @self: a #GDataCalendarEvent
1270 *
1271 * Gets the #GDataCalendarEvent:edited property. If the property is unset, <code class="literal">-1</code> will be returned.
1272 *
1273 * Return value: the UNIX timestamp for the time the event was last edited, or <code class="literal">-1</code>
1274 */
1275 gint64
gdata_calendar_event_get_edited(GDataCalendarEvent * self)1276 gdata_calendar_event_get_edited (GDataCalendarEvent *self)
1277 {
1278 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), -1);
1279 return self->priv->edited;
1280 }
1281
1282 /**
1283 * gdata_calendar_event_get_status:
1284 * @self: a #GDataCalendarEvent
1285 *
1286 * Gets the #GDataCalendarEvent:status property.
1287 *
1288 * Return value: the event status, or %NULL
1289 *
1290 * Since: 0.2.0
1291 */
1292 const gchar *
gdata_calendar_event_get_status(GDataCalendarEvent * self)1293 gdata_calendar_event_get_status (GDataCalendarEvent *self)
1294 {
1295 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1296 return self->priv->status;
1297 }
1298
1299 /**
1300 * gdata_calendar_event_set_status:
1301 * @self: a #GDataCalendarEvent
1302 * @status: (allow-none): a new event status, or %NULL
1303 *
1304 * Sets the #GDataCalendarEvent:status property to the new status, @status.
1305 *
1306 * Set @status to %NULL to unset the property in the event.
1307 *
1308 * Since: 0.2.0
1309 */
1310 void
gdata_calendar_event_set_status(GDataCalendarEvent * self,const gchar * status)1311 gdata_calendar_event_set_status (GDataCalendarEvent *self, const gchar *status)
1312 {
1313 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1314
1315 g_free (self->priv->status);
1316 self->priv->status = g_strdup (status);
1317 g_object_notify (G_OBJECT (self), "status");
1318 }
1319
1320 /**
1321 * gdata_calendar_event_get_visibility:
1322 * @self: a #GDataCalendarEvent
1323 *
1324 * Gets the #GDataCalendarEvent:visibility property.
1325 *
1326 * Return value: the event visibility, or %NULL
1327 */
1328 const gchar *
gdata_calendar_event_get_visibility(GDataCalendarEvent * self)1329 gdata_calendar_event_get_visibility (GDataCalendarEvent *self)
1330 {
1331 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1332 return self->priv->visibility;
1333 }
1334
1335 /**
1336 * gdata_calendar_event_set_visibility:
1337 * @self: a #GDataCalendarEvent
1338 * @visibility: (allow-none): a new event visibility, or %NULL
1339 *
1340 * Sets the #GDataCalendarEvent:visibility property to the new visibility, @visibility.
1341 *
1342 * Set @visibility to %NULL to unset the property in the event.
1343 */
1344 void
gdata_calendar_event_set_visibility(GDataCalendarEvent * self,const gchar * visibility)1345 gdata_calendar_event_set_visibility (GDataCalendarEvent *self, const gchar *visibility)
1346 {
1347 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1348
1349 g_free (self->priv->visibility);
1350 self->priv->visibility = g_strdup (visibility);
1351 g_object_notify (G_OBJECT (self), "visibility");
1352 }
1353
1354 /**
1355 * gdata_calendar_event_get_transparency:
1356 * @self: a #GDataCalendarEvent
1357 *
1358 * Gets the #GDataCalendarEvent:transparency property.
1359 *
1360 * Return value: the event transparency, or %NULL
1361 */
1362 const gchar *
gdata_calendar_event_get_transparency(GDataCalendarEvent * self)1363 gdata_calendar_event_get_transparency (GDataCalendarEvent *self)
1364 {
1365 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1366 return self->priv->transparency;
1367 }
1368
1369 /**
1370 * gdata_calendar_event_set_transparency:
1371 * @self: a #GDataCalendarEvent
1372 * @transparency: (allow-none): a new event transparency, or %NULL
1373 *
1374 * Sets the #GDataCalendarEvent:transparency property to the new transparency, @transparency.
1375 *
1376 * Set @transparency to %NULL to unset the property in the event.
1377 */
1378 void
gdata_calendar_event_set_transparency(GDataCalendarEvent * self,const gchar * transparency)1379 gdata_calendar_event_set_transparency (GDataCalendarEvent *self, const gchar *transparency)
1380 {
1381 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1382
1383 g_free (self->priv->transparency);
1384 self->priv->transparency = g_strdup (transparency);
1385 g_object_notify (G_OBJECT (self), "transparency");
1386 }
1387
1388 /**
1389 * gdata_calendar_event_get_uid:
1390 * @self: a #GDataCalendarEvent
1391 *
1392 * Gets the #GDataCalendarEvent:uid property.
1393 *
1394 * Return value: the event's UID, or %NULL
1395 */
1396 const gchar *
gdata_calendar_event_get_uid(GDataCalendarEvent * self)1397 gdata_calendar_event_get_uid (GDataCalendarEvent *self)
1398 {
1399 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1400 return self->priv->uid;
1401 }
1402
1403 /**
1404 * gdata_calendar_event_set_uid:
1405 * @self: a #GDataCalendarEvent
1406 * @uid: (allow-none): a new event UID, or %NULL
1407 *
1408 * Sets the #GDataCalendarEvent:uid property to the new UID, @uid.
1409 *
1410 * Set @uid to %NULL to unset the property in the event.
1411 */
1412 void
gdata_calendar_event_set_uid(GDataCalendarEvent * self,const gchar * uid)1413 gdata_calendar_event_set_uid (GDataCalendarEvent *self, const gchar *uid)
1414 {
1415 /* TODO: is modifying this allowed? */
1416 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1417
1418 g_free (self->priv->uid);
1419 self->priv->uid = g_strdup (uid);
1420 g_object_notify (G_OBJECT (self), "uid");
1421 }
1422
1423 /**
1424 * gdata_calendar_event_get_sequence:
1425 * @self: a #GDataCalendarEvent
1426 *
1427 * Gets the #GDataCalendarEvent:sequence property.
1428 *
1429 * Return value: the event's sequence number
1430 */
1431 guint
gdata_calendar_event_get_sequence(GDataCalendarEvent * self)1432 gdata_calendar_event_get_sequence (GDataCalendarEvent *self)
1433 {
1434 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), 0);
1435 return CLAMP (self->priv->sequence, 0, G_MAXUINT);
1436 }
1437
1438 /**
1439 * gdata_calendar_event_set_sequence:
1440 * @self: a #GDataCalendarEvent
1441 * @sequence: a new sequence number, or <code class="literal">0</code>
1442 *
1443 * Sets the #GDataCalendarEvent:sequence property to the new sequence number, @sequence.
1444 */
1445 void
gdata_calendar_event_set_sequence(GDataCalendarEvent * self,guint sequence)1446 gdata_calendar_event_set_sequence (GDataCalendarEvent *self, guint sequence)
1447 {
1448 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1449 self->priv->sequence = sequence;
1450 g_object_notify (G_OBJECT (self), "sequence");
1451 }
1452
1453 /**
1454 * gdata_calendar_event_get_guests_can_modify:
1455 * @self: a #GDataCalendarEvent
1456 *
1457 * Gets the #GDataCalendarEvent:guests-can-modify property.
1458 *
1459 * Return value: %TRUE if attendees can modify the original event, %FALSE otherwise
1460 */
1461 gboolean
gdata_calendar_event_get_guests_can_modify(GDataCalendarEvent * self)1462 gdata_calendar_event_get_guests_can_modify (GDataCalendarEvent *self)
1463 {
1464 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1465 return self->priv->guests_can_modify;
1466 }
1467
1468 /**
1469 * gdata_calendar_event_set_guests_can_modify:
1470 * @self: a #GDataCalendarEvent
1471 * @guests_can_modify: %TRUE if attendees can modify the original event, %FALSE otherwise
1472 *
1473 * Sets the #GDataCalendarEvent:guests-can-modify property to @guests_can_modify.
1474 */
1475 void
gdata_calendar_event_set_guests_can_modify(GDataCalendarEvent * self,gboolean guests_can_modify)1476 gdata_calendar_event_set_guests_can_modify (GDataCalendarEvent *self, gboolean guests_can_modify)
1477 {
1478 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1479 self->priv->guests_can_modify = guests_can_modify;
1480 g_object_notify (G_OBJECT (self), "guests-can-modify");
1481 }
1482
1483 /**
1484 * gdata_calendar_event_get_guests_can_invite_others:
1485 * @self: a #GDataCalendarEvent
1486 *
1487 * Gets the #GDataCalendarEvent:guests-can-invite-others property.
1488 *
1489 * Return value: %TRUE if attendees can invite others to the event, %FALSE otherwise
1490 */
1491 gboolean
gdata_calendar_event_get_guests_can_invite_others(GDataCalendarEvent * self)1492 gdata_calendar_event_get_guests_can_invite_others (GDataCalendarEvent *self)
1493 {
1494 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1495 return self->priv->guests_can_invite_others;
1496 }
1497
1498 /**
1499 * gdata_calendar_event_set_guests_can_invite_others:
1500 * @self: a #GDataCalendarEvent
1501 * @guests_can_invite_others: %TRUE if attendees can invite others to the event, %FALSE otherwise
1502 *
1503 * Sets the #GDataCalendarEvent:guests-can-invite-others property to @guests_can_invite_others.
1504 */
1505 void
gdata_calendar_event_set_guests_can_invite_others(GDataCalendarEvent * self,gboolean guests_can_invite_others)1506 gdata_calendar_event_set_guests_can_invite_others (GDataCalendarEvent *self, gboolean guests_can_invite_others)
1507 {
1508 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1509 self->priv->guests_can_invite_others = guests_can_invite_others;
1510 g_object_notify (G_OBJECT (self), "guests-can-invite-others");
1511 }
1512
1513 /**
1514 * gdata_calendar_event_get_guests_can_see_guests:
1515 * @self: a #GDataCalendarEvent
1516 *
1517 * Gets the #GDataCalendarEvent:guests-can-see-guests property.
1518 *
1519 * Return value: %TRUE if attendees can see who's attending the event, %FALSE otherwise
1520 */
1521 gboolean
gdata_calendar_event_get_guests_can_see_guests(GDataCalendarEvent * self)1522 gdata_calendar_event_get_guests_can_see_guests (GDataCalendarEvent *self)
1523 {
1524 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1525 return self->priv->guests_can_see_guests;
1526 }
1527
1528 /**
1529 * gdata_calendar_event_set_guests_can_see_guests:
1530 * @self: a #GDataCalendarEvent
1531 * @guests_can_see_guests: %TRUE if attendees can see who's attending the event, %FALSE otherwise
1532 *
1533 * Sets the #GDataCalendarEvent:guests-can-see-guests property to @guests_can_see_guests.
1534 */
1535 void
gdata_calendar_event_set_guests_can_see_guests(GDataCalendarEvent * self,gboolean guests_can_see_guests)1536 gdata_calendar_event_set_guests_can_see_guests (GDataCalendarEvent *self, gboolean guests_can_see_guests)
1537 {
1538 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1539 self->priv->guests_can_see_guests = guests_can_see_guests;
1540 g_object_notify (G_OBJECT (self), "guests-can-see-guests");
1541 }
1542
1543 /**
1544 * gdata_calendar_event_get_anyone_can_add_self:
1545 * @self: a #GDataCalendarEvent
1546 *
1547 * Gets the #GDataCalendarEvent:anyone-can-add-self property.
1548 *
1549 * Return value: %TRUE if anyone can add themselves as an attendee to the event, %FALSE otherwise
1550 */
1551 gboolean
gdata_calendar_event_get_anyone_can_add_self(GDataCalendarEvent * self)1552 gdata_calendar_event_get_anyone_can_add_self (GDataCalendarEvent *self)
1553 {
1554 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1555 return self->priv->anyone_can_add_self;
1556 }
1557
1558 /**
1559 * gdata_calendar_event_set_anyone_can_add_self:
1560 * @self: a #GDataCalendarEvent
1561 * @anyone_can_add_self: %TRUE if anyone can add themselves as an attendee to the event, %FALSE otherwise
1562 *
1563 * Sets the #GDataCalendarEvent:anyone-can-add-self property to @anyone_can_add_self.
1564 */
1565 void
gdata_calendar_event_set_anyone_can_add_self(GDataCalendarEvent * self,gboolean anyone_can_add_self)1566 gdata_calendar_event_set_anyone_can_add_self (GDataCalendarEvent *self, gboolean anyone_can_add_self)
1567 {
1568 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1569 self->priv->anyone_can_add_self = anyone_can_add_self;
1570 g_object_notify (G_OBJECT (self), "anyone-can-add-self");
1571 }
1572
1573 /**
1574 * gdata_calendar_event_add_person:
1575 * @self: a #GDataCalendarEvent
1576 * @who: a #GDataGDWho to add
1577 *
1578 * Adds the person @who to the event as a guest (attendee, organiser, performer, etc.), and increments its reference count.
1579 *
1580 * Duplicate people will not be added to the list.
1581 */
1582 void
gdata_calendar_event_add_person(GDataCalendarEvent * self,GDataGDWho * who)1583 gdata_calendar_event_add_person (GDataCalendarEvent *self, GDataGDWho *who)
1584 {
1585 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1586 g_return_if_fail (GDATA_IS_GD_WHO (who));
1587
1588 if (g_list_find_custom (self->priv->people, who, (GCompareFunc) gdata_comparable_compare) == NULL)
1589 self->priv->people = g_list_append (self->priv->people, g_object_ref (who));
1590 }
1591
1592 /**
1593 * gdata_calendar_event_get_people:
1594 * @self: a #GDataCalendarEvent
1595 *
1596 * Gets a list of the people attending the event.
1597 *
1598 * Return value: (element-type GData.GDWho) (transfer none): a #GList of #GDataGDWhos, or %NULL
1599 *
1600 * Since: 0.2.0
1601 */
1602 GList *
gdata_calendar_event_get_people(GDataCalendarEvent * self)1603 gdata_calendar_event_get_people (GDataCalendarEvent *self)
1604 {
1605 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1606 return self->priv->people;
1607 }
1608
1609 /**
1610 * gdata_calendar_event_add_place:
1611 * @self: a #GDataCalendarEvent
1612 * @where: a #GDataGDWhere to add
1613 *
1614 * Adds the place @where to the event as a location and increments its reference count.
1615 *
1616 * Duplicate places will not be added to the list.
1617 */
1618 void
gdata_calendar_event_add_place(GDataCalendarEvent * self,GDataGDWhere * where)1619 gdata_calendar_event_add_place (GDataCalendarEvent *self, GDataGDWhere *where)
1620 {
1621 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1622 g_return_if_fail (GDATA_IS_GD_WHERE (where));
1623
1624 if (g_list_find_custom (self->priv->places, where, (GCompareFunc) gdata_comparable_compare) == NULL)
1625 self->priv->places = g_list_append (self->priv->places, g_object_ref (where));
1626 }
1627
1628 /**
1629 * gdata_calendar_event_get_places:
1630 * @self: a #GDataCalendarEvent
1631 *
1632 * Gets a list of the locations associated with the event.
1633 *
1634 * Return value: (element-type GData.GDWhere) (transfer none): a #GList of #GDataGDWheres, or %NULL
1635 *
1636 * Since: 0.2.0
1637 */
1638 GList *
gdata_calendar_event_get_places(GDataCalendarEvent * self)1639 gdata_calendar_event_get_places (GDataCalendarEvent *self)
1640 {
1641 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1642 return self->priv->places;
1643 }
1644
1645 /**
1646 * gdata_calendar_event_add_time:
1647 * @self: a #GDataCalendarEvent
1648 * @when: a #GDataGDWhen to add
1649 *
1650 * Adds @when to the event as a time period when the event happens, and increments its reference count.
1651 *
1652 * Duplicate times will not be added to the list.
1653 *
1654 * Note: gdata_calendar_event_add_time() and gdata_calendar_event_set_recurrence() are mutually
1655 * exclusive, as the server doesn't support positive exceptions to recurrence rules. If recurrences
1656 * are required, use gdata_calendar_event_set_recurrence(). Note that this means reminders cannot
1657 * be set for the event, as they are only supported by #GDataGDWhen. No checks are performed for
1658 * these forbidden conditions, as to do so would break libgdata's API; if both a recurrence is set
1659 * and a specific time is added, the server will return an error when the #GDataCalendarEvent is
1660 * inserted using gdata_service_insert_entry().
1661 *
1662 * Since: 0.2.0
1663 */
1664 void
gdata_calendar_event_add_time(GDataCalendarEvent * self,GDataGDWhen * when)1665 gdata_calendar_event_add_time (GDataCalendarEvent *self, GDataGDWhen *when)
1666 {
1667 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1668 g_return_if_fail (GDATA_IS_GD_WHEN (when));
1669
1670 if (g_list_find_custom (self->priv->times, when, (GCompareFunc) gdata_comparable_compare) == NULL)
1671 self->priv->times = g_list_append (self->priv->times, g_object_ref (when));
1672 }
1673
1674 /**
1675 * gdata_calendar_event_get_times:
1676 * @self: a #GDataCalendarEvent
1677 *
1678 * Gets a list of the time periods associated with the event.
1679 *
1680 * Return value: (element-type GData.GDWhen) (transfer none): a #GList of #GDataGDWhens, or %NULL
1681 *
1682 * Since: 0.2.0
1683 */
1684 GList *
gdata_calendar_event_get_times(GDataCalendarEvent * self)1685 gdata_calendar_event_get_times (GDataCalendarEvent *self)
1686 {
1687 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1688 return self->priv->times;
1689 }
1690
1691 /**
1692 * gdata_calendar_event_get_primary_time:
1693 * @self: a #GDataCalendarEvent
1694 * @start_time: (out caller-allocates): a #gint64 for the start time, or %NULL
1695 * @end_time: (out caller-allocates): a #gint64 for the end time, or %NULL
1696 * @when: (out callee-allocates) (transfer none): a #GDataGDWhen for the primary time structure, or %NULL
1697 *
1698 * Gets the first time period associated with the event, conveniently returning just its start and
1699 * end times if required.
1700 *
1701 * If there are no time periods, or more than one time period, associated with the event, %FALSE will
1702 * be returned, and the parameters will remain unmodified.
1703 *
1704 * Return value: %TRUE if there is only one time period associated with the event, %FALSE otherwise
1705 *
1706 * Since: 0.2.0
1707 */
1708 gboolean
gdata_calendar_event_get_primary_time(GDataCalendarEvent * self,gint64 * start_time,gint64 * end_time,GDataGDWhen ** when)1709 gdata_calendar_event_get_primary_time (GDataCalendarEvent *self, gint64 *start_time, gint64 *end_time, GDataGDWhen **when)
1710 {
1711 GDataGDWhen *primary_when;
1712
1713 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1714
1715 if (self->priv->times == NULL || self->priv->times->next != NULL)
1716 return FALSE;
1717
1718 primary_when = GDATA_GD_WHEN (self->priv->times->data);
1719 if (start_time != NULL)
1720 *start_time = gdata_gd_when_get_start_time (primary_when);
1721 if (end_time != NULL)
1722 *end_time = gdata_gd_when_get_end_time (primary_when);
1723 if (when != NULL)
1724 *when = primary_when;
1725
1726 return TRUE;
1727 }
1728
1729 /**
1730 * gdata_calendar_event_get_recurrence:
1731 * @self: a #GDataCalendarEvent
1732 *
1733 * Gets the #GDataCalendarEvent:recurrence property.
1734 *
1735 * Return value: the event recurrence patterns, or %NULL
1736 *
1737 * Since: 0.3.0
1738 */
1739 const gchar *
gdata_calendar_event_get_recurrence(GDataCalendarEvent * self)1740 gdata_calendar_event_get_recurrence (GDataCalendarEvent *self)
1741 {
1742 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
1743 return self->priv->recurrence;
1744 }
1745
1746 /**
1747 * gdata_calendar_event_set_recurrence:
1748 * @self: a #GDataCalendarEvent
1749 * @recurrence: (allow-none): a new event recurrence, or %NULL
1750 *
1751 * Sets the #GDataCalendarEvent:recurrence property to the new recurrence, @recurrence.
1752 *
1753 * Set @recurrence to %NULL to unset the property in the event.
1754 *
1755 * Note: gdata_calendar_event_add_time() and gdata_calendar_event_set_recurrence() are mutually
1756 * exclusive. See the documentation for gdata_calendar_event_add_time() for details.
1757 *
1758 * Since: 0.3.0
1759 */
1760 void
gdata_calendar_event_set_recurrence(GDataCalendarEvent * self,const gchar * recurrence)1761 gdata_calendar_event_set_recurrence (GDataCalendarEvent *self, const gchar *recurrence)
1762 {
1763 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1764
1765 g_free (self->priv->recurrence);
1766 self->priv->recurrence = g_strdup (recurrence);
1767 g_object_notify (G_OBJECT (self), "recurrence");
1768 }
1769
1770 /**
1771 * gdata_calendar_event_get_original_event_details:
1772 * @self: a #GDataCalendarEvent
1773 * @event_id: (out callee-allocates) (transfer full): return location for the original event's ID, or %NULL
1774 * @event_uri: (out callee-allocates) (transfer full): return location for the original event's URI, or %NULL
1775 *
1776 * Gets details of the original event, if this event is an exception to a recurring event. The original
1777 * event's ID and the URI of the event's XML are returned in @event_id and @event_uri, respectively.
1778 *
1779 * If this event is not an exception to a recurring event, @event_id and @event_uri will be set to %NULL.
1780 * See gdata_calendar_event_is_exception() to determine more simply whether an event is an exception to a
1781 * recurring event.
1782 *
1783 * If both @event_id and @event_uri are %NULL, this function is a no-op. Otherwise, they should both be
1784 * freed with g_free().
1785 *
1786 * Since: 0.3.0
1787 */
1788 void
gdata_calendar_event_get_original_event_details(GDataCalendarEvent * self,gchar ** event_id,gchar ** event_uri)1789 gdata_calendar_event_get_original_event_details (GDataCalendarEvent *self, gchar **event_id, gchar **event_uri)
1790 {
1791 g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
1792
1793 if (event_id != NULL)
1794 *event_id = g_strdup (self->priv->original_event_id);
1795 if (event_uri != NULL)
1796 *event_uri = g_strdup (self->priv->original_event_uri);
1797 }
1798
1799 /**
1800 * gdata_calendar_event_is_exception:
1801 * @self: a #GDataCalendarEvent
1802 *
1803 * Determines whether the event is an exception to a recurring event. If it is, details of the original event
1804 * can be retrieved using gdata_calendar_event_get_original_event_details().
1805 *
1806 * Return value: %TRUE if the event is an exception, %FALSE otherwise
1807 *
1808 * Since: 0.3.0
1809 */
1810 gboolean
gdata_calendar_event_is_exception(GDataCalendarEvent * self)1811 gdata_calendar_event_is_exception (GDataCalendarEvent *self)
1812 {
1813 g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
1814 return (self->priv->original_event_id != NULL && self->priv->original_event_uri != NULL) ? TRUE : FALSE;
1815 }
1816