1 /*
2 * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Milan Crha <mcrha@redhat.com>
17 */
18
19 #include "evolution-config.h"
20
21 #include <string.h>
22 #include <glib/gi18n-lib.h>
23
24 #include <libedataserver/libedataserver.h>
25
26 #include "calendar/gui/calendar-config.h"
27 #include <calendar/gui/comp-util.h>
28 #include <calendar/gui/e-comp-editor.h>
29
30 #include "shell/e-shell-backend.h"
31 #include "shell/e-shell-view.h"
32 #include "shell/e-shell-window.h"
33
34 #include "e-cal-base-shell-view.h"
35 #include "e-cal-base-shell-backend.h"
36
37 #define E_CAL_BASE_SHELL_BACKEND_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE \
39 ((obj), E_TYPE_CAL_BASE_SHELL_BACKEND, ECalBaseShellBackendPrivate))
40
41 struct _ECalBaseShellBackendPrivate {
42 gint placeholder;
43 };
44
G_DEFINE_ABSTRACT_TYPE(ECalBaseShellBackend,e_cal_base_shell_backend,E_TYPE_SHELL_BACKEND)45 G_DEFINE_ABSTRACT_TYPE (ECalBaseShellBackend, e_cal_base_shell_backend, E_TYPE_SHELL_BACKEND)
46
47 static void
48 cal_base_shell_backend_handle_webcal_uri (EShellBackend *shell_backend,
49 const gchar *uri)
50 {
51 EShell *shell;
52 ESourceRegistry *registry;
53 ESourceConfig *source_config;
54 const gchar *extension_name;
55 GtkWidget *config;
56 GtkWidget *dialog;
57 GtkWindow *window, *active_window;
58 GSList *candidates, *link;
59
60 g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
61 g_return_if_fail (uri != NULL);
62
63 shell = e_shell_backend_get_shell (shell_backend);
64
65 active_window = e_shell_get_active_window (shell);
66 registry = e_shell_get_registry (shell);
67 config = e_cal_source_config_new (registry, NULL, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
68 source_config = E_SOURCE_CONFIG (config);
69
70 if (E_IS_SHELL_WINDOW (active_window)) {
71 EShellWindow *shell_window;
72 EShellView *shell_view;
73
74 shell_window = E_SHELL_WINDOW (active_window);
75 shell_view = e_shell_window_peek_shell_view (shell_window, e_shell_window_get_active_view (shell_window));
76
77 if (shell_view && E_IS_CAL_BASE_SHELL_VIEW (shell_view))
78 e_cal_base_shell_view_preselect_source_config (shell_view, config);
79 }
80
81 extension_name = e_source_config_get_backend_extension_name (source_config);
82
83 dialog = e_source_config_dialog_new (source_config);
84 window = GTK_WINDOW (dialog);
85
86 if (active_window)
87 gtk_window_set_transient_for (window, active_window);
88 gtk_window_set_icon_name (window, "x-office-calendar");
89 gtk_window_set_title (window, _("New Calendar"));
90
91 gtk_widget_show (dialog);
92
93 /* Can do this only after the dialog is shown, thus the list
94 of candidates is populated. */
95 candidates = e_source_config_list_candidates (source_config);
96
97 for (link = candidates; link; link = g_slist_next (link)) {
98 ESource *candidate = link->data;
99
100 if (e_source_has_extension (candidate, extension_name)) {
101 const gchar *backend_name;
102
103 backend_name = e_source_backend_get_backend_name (
104 e_source_get_extension (candidate, extension_name));
105 if (g_strcmp0 (backend_name, "webcal") == 0) {
106 ESourceWebdav *webdav_extension;
107 SoupURI *soup_uri;
108
109 soup_uri = soup_uri_new (uri);
110 if (!soup_uri) {
111 /* Just a fallback when the passed-in URI is invalid,
112 to have set something in the UI. */
113 soup_uri = soup_uri_new (NULL);
114 soup_uri_set_path (soup_uri, uri);
115 }
116
117 /* https everywhere */
118 soup_uri_set_scheme (soup_uri, "https");
119
120 if (soup_uri_get_path (soup_uri)) {
121 gchar *basename;
122
123 basename = g_path_get_basename (soup_uri_get_path (soup_uri));
124 if (basename && g_utf8_strlen (basename, -1) > 3) {
125 gchar *dot;
126
127 dot = strrchr (basename, '.');
128 if (dot && strlen (dot) <= 4)
129 *dot = '\0';
130
131 if (*basename)
132 e_source_set_display_name (candidate, basename);
133 }
134
135 g_free (basename);
136 }
137
138 webdav_extension = e_source_get_extension (candidate, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
139 e_source_webdav_set_soup_uri (webdav_extension, soup_uri);
140
141 e_source_config_select_page (source_config, candidate);
142
143 soup_uri_free (soup_uri);
144 break;
145 }
146 }
147 }
148
149 g_slist_free_full (candidates, g_object_unref);
150 }
151
152 static gboolean
cal_base_shell_backend_handle_uri_cb(EShellBackend * shell_backend,const gchar * uri)153 cal_base_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
154 const gchar *uri)
155 {
156 ECalBaseShellBackendClass *klass;
157
158 g_return_val_if_fail (E_IS_CAL_BASE_SHELL_BACKEND (shell_backend), FALSE);
159 g_return_val_if_fail (uri != NULL, FALSE);
160
161 if (g_str_has_prefix (uri, "webcal:")) {
162 cal_base_shell_backend_handle_webcal_uri (shell_backend, uri);
163 return TRUE;
164 }
165
166 klass = E_CAL_BASE_SHELL_BACKEND_GET_CLASS (shell_backend);
167 g_return_val_if_fail (klass != NULL, FALSE);
168
169 return klass->handle_uri && klass->handle_uri (shell_backend, uri);
170 }
171
172 static void
cal_base_shell_backend_window_added_cb(ECalBaseShellBackend * cal_base_shell_backend,GtkWindow * window)173 cal_base_shell_backend_window_added_cb (ECalBaseShellBackend *cal_base_shell_backend,
174 GtkWindow *window)
175 {
176 ECalBaseShellBackendClass *cal_base_shell_backend_class;
177 const gchar *backend_name;
178
179 if (!E_IS_SHELL_WINDOW (window))
180 return;
181
182 cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_GET_CLASS (cal_base_shell_backend);
183 g_return_if_fail (cal_base_shell_backend_class != NULL);
184
185 backend_name = E_SHELL_BACKEND_GET_CLASS (cal_base_shell_backend)->name;
186
187 if (cal_base_shell_backend_class->new_item_entries &&
188 cal_base_shell_backend_class->new_item_n_entries > 0)
189 e_shell_window_register_new_item_actions (
190 E_SHELL_WINDOW (window), backend_name,
191 cal_base_shell_backend_class->new_item_entries,
192 cal_base_shell_backend_class->new_item_n_entries);
193
194 if (cal_base_shell_backend_class->source_entries &&
195 cal_base_shell_backend_class->source_n_entries > 0)
196 e_shell_window_register_new_source_actions (
197 E_SHELL_WINDOW (window), backend_name,
198 cal_base_shell_backend_class->source_entries,
199 cal_base_shell_backend_class->source_n_entries);
200 }
201
202 static void
cal_base_shell_backend_constructed(GObject * object)203 cal_base_shell_backend_constructed (GObject *object)
204 {
205 EShell *shell;
206 EShellBackend *shell_backend;
207
208 /* Chain up to parent's constructed() method. */
209 G_OBJECT_CLASS (e_cal_base_shell_backend_parent_class)->constructed (object);
210
211 shell_backend = E_SHELL_BACKEND (object);
212 shell = e_shell_backend_get_shell (shell_backend);
213
214 g_signal_connect_swapped (
215 shell, "handle-uri",
216 G_CALLBACK (cal_base_shell_backend_handle_uri_cb),
217 shell_backend);
218
219 g_signal_connect_swapped (
220 shell, "window-added",
221 G_CALLBACK (cal_base_shell_backend_window_added_cb),
222 shell_backend);
223 }
224
225 static void
e_cal_base_shell_backend_class_init(ECalBaseShellBackendClass * class)226 e_cal_base_shell_backend_class_init (ECalBaseShellBackendClass *class)
227 {
228 GObjectClass *object_class;
229
230 g_type_class_add_private (class, sizeof (ECalBaseShellBackendPrivate));
231
232 object_class = G_OBJECT_CLASS (class);
233 object_class->constructed = cal_base_shell_backend_constructed;
234
235 class->new_item_entries = NULL;
236 class->new_item_n_entries = 0;
237 class->source_entries = NULL;
238 class->source_n_entries = 0;
239 class->handle_uri = NULL;
240
241 /* Register relevant ESource extensions. */
242 g_type_ensure (E_TYPE_SOURCE_CALENDAR);
243
244 /* Force 24 hour format for locales which don't support 12 hour format */
245 if (!calendar_config_locale_supports_12_hour_format ()) {
246 GSettings *settings;
247
248 settings = e_util_ref_settings ("org.gnome.evolution.calendar");
249
250 if (!g_settings_get_boolean (settings, "use-24hour-format"))
251 g_settings_set_boolean (settings, "use-24hour-format", TRUE);
252
253 g_clear_object (&settings);
254 }
255 }
256
257 static void
e_cal_base_shell_backend_init(ECalBaseShellBackend * cal_base_shell_backend)258 e_cal_base_shell_backend_init (ECalBaseShellBackend *cal_base_shell_backend)
259 {
260 cal_base_shell_backend->priv = E_CAL_BASE_SHELL_BACKEND_GET_PRIVATE (cal_base_shell_backend);
261 }
262
263 void
e_cal_base_shell_backend_util_new_source(EShellWindow * shell_window,ECalClientSourceType source_type)264 e_cal_base_shell_backend_util_new_source (EShellWindow *shell_window,
265 ECalClientSourceType source_type)
266 {
267 EShell *shell;
268 EShellView *shell_view;
269 ESourceRegistry *registry;
270 GtkWidget *config;
271 GtkWidget *dialog;
272 GtkWindow *window;
273 const gchar *icon_name;
274 const gchar *title;
275
276 g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
277
278 switch (source_type) {
279 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
280 title = _("New Calendar");
281 icon_name = "x-office-calendar";
282 break;
283 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
284 title = _("New Memo List");
285 icon_name = "stock_notes";
286 break;
287 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
288 title = _("New Task List");
289 icon_name = "stock_todo";
290 break;
291 default:
292 g_warn_if_reached ();
293 return;
294 }
295
296 shell = e_shell_window_get_shell (shell_window);
297
298 registry = e_shell_get_registry (shell);
299 config = e_cal_source_config_new (registry, NULL, source_type);
300
301 shell_view = e_shell_window_peek_shell_view (shell_window, e_shell_window_get_active_view (shell_window));
302
303 if (shell_view && E_IS_CAL_BASE_SHELL_VIEW (shell_view))
304 e_cal_base_shell_view_preselect_source_config (shell_view, config);
305
306 dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
307 window = GTK_WINDOW (dialog);
308
309 gtk_window_set_transient_for (window, GTK_WINDOW (shell_window));
310 gtk_window_set_icon_name (window, icon_name);
311 gtk_window_set_title (window, title);
312
313 gtk_widget_show (dialog);
314 }
315
316 typedef struct {
317 EShellBackend *shell_backend;
318 ECalClientSourceType source_type;
319 gchar *source_uid;
320 gchar *comp_uid;
321 gchar *comp_rid;
322
323 ECalClient *cal_client;
324 ICalComponent *existing_icomp;
325 } HandleUriData;
326
327 static void
handle_uri_data_free(gpointer ptr)328 handle_uri_data_free (gpointer ptr)
329 {
330 HandleUriData *hud = ptr;
331
332 if (!hud)
333 return;
334
335 if (hud->cal_client) {
336 ECompEditor *comp_editor = NULL;
337
338 comp_editor = e_comp_editor_open_for_component (NULL,
339 e_shell_backend_get_shell (hud->shell_backend),
340 e_client_get_source (E_CLIENT (hud->cal_client)),
341 hud->existing_icomp, 0);
342
343 if (comp_editor)
344 gtk_window_present (GTK_WINDOW (comp_editor));
345 }
346
347 g_clear_object (&hud->existing_icomp);
348 g_clear_object (&hud->cal_client);
349 g_clear_object (&hud->shell_backend);
350 g_free (hud->source_uid);
351 g_free (hud->comp_uid);
352 g_free (hud->comp_rid);
353 g_slice_free (HandleUriData, hud);
354 }
355
356 static void
cal_base_shell_backend_handle_uri_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)357 cal_base_shell_backend_handle_uri_thread (EAlertSinkThreadJobData *job_data,
358 gpointer user_data,
359 GCancellable *cancellable,
360 GError **error)
361 {
362 HandleUriData *hud = user_data;
363 EShell *shell;
364 ESourceRegistry *registry;
365 ESource *source;
366 const gchar *extension_name;
367 GError *local_error = NULL;
368
369 g_return_if_fail (hud != NULL);
370
371 switch (hud->source_type) {
372 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
373 extension_name = E_SOURCE_EXTENSION_CALENDAR;
374 break;
375 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
376 extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
377 break;
378 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
379 extension_name = E_SOURCE_EXTENSION_TASK_LIST;
380 break;
381 default:
382 g_warn_if_reached ();
383 return;
384 }
385
386 shell = e_shell_backend_get_shell (hud->shell_backend);
387 registry = e_shell_get_registry (shell);
388 source = e_source_registry_ref_source (registry, hud->source_uid);
389 if (!source) {
390 g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
391 _("Source with UID “%s” not found"), hud->source_uid);
392 } else {
393 EClientCache *client_cache;
394 EClient *client;
395
396 client_cache = e_shell_get_client_cache (shell);
397
398 client = e_client_cache_get_client_sync (client_cache, source, extension_name, 30, cancellable, &local_error);
399 if (client) {
400 hud->cal_client = E_CAL_CLIENT (client);
401
402 if (!e_cal_client_get_object_sync (hud->cal_client, hud->comp_uid,
403 hud->comp_rid, &hud->existing_icomp, cancellable, &local_error))
404 g_clear_object (&hud->cal_client);
405 }
406 }
407
408 e_util_propagate_open_source_job_error (job_data, extension_name, local_error, error);
409
410 g_clear_object (&source);
411 }
412
413 static void
populate_g_date(GDate * date,time_t utc_time,ICalTimezone * zone)414 populate_g_date (GDate *date,
415 time_t utc_time,
416 ICalTimezone *zone)
417 {
418 ICalTime *itt;
419
420 g_return_if_fail (date != NULL);
421
422 if ((gint) utc_time == -1)
423 return;
424
425 itt = i_cal_time_new_from_timet_with_zone (utc_time, FALSE, zone);
426
427 if (itt && !i_cal_time_is_null_time (itt) &&
428 i_cal_time_is_valid_time (itt)) {
429 g_date_set_dmy (date, i_cal_time_get_day (itt), i_cal_time_get_month (itt), i_cal_time_get_year (itt));
430 }
431
432 g_clear_object (&itt);
433 }
434
435 static time_t
convert_time_from_isodate(const gchar * text,ICalTimezone * use_date_zone)436 convert_time_from_isodate (const gchar *text,
437 ICalTimezone *use_date_zone)
438 {
439 time_t res;
440
441 g_return_val_if_fail (text != NULL, (time_t) 0);
442
443 res = time_from_isodate (text);
444
445 /* Is it date only? Then use the date zone to match the right day */
446 if (use_date_zone && strlen (text) == 8) {
447 ICalTime *itt;
448
449 itt = i_cal_time_new_from_timet_with_zone (res, TRUE, NULL);
450 res = i_cal_time_as_timet_with_zone (itt, use_date_zone);
451 g_clear_object (&itt);
452 }
453
454 return res;
455 }
456
457 gboolean
e_cal_base_shell_backend_util_handle_uri(EShellBackend * shell_backend,ECalClientSourceType source_type,const gchar * uri,ECalBaseShellBackendHandleStartEndDatesFunc handle_start_end_dates)458 e_cal_base_shell_backend_util_handle_uri (EShellBackend *shell_backend,
459 ECalClientSourceType source_type,
460 const gchar *uri,
461 ECalBaseShellBackendHandleStartEndDatesFunc handle_start_end_dates)
462 {
463 EShell *shell;
464 EShellWindow *shell_window;
465 SoupURI *soup_uri;
466 const gchar *cp;
467 gchar *source_uid = NULL;
468 gchar *comp_uid = NULL;
469 gchar *comp_rid = NULL;
470 gchar *new_ics = NULL;
471 gboolean attendees = FALSE;
472 gboolean handled = FALSE;
473 GSettings *settings;
474 GList *windows, *link;
475 GDate start_date;
476 GDate end_date;
477 ICalTimezone *zone = NULL;
478 const gchar *extension_name;
479
480 g_return_val_if_fail (E_IS_CAL_BASE_SHELL_BACKEND (shell_backend), FALSE);
481 g_return_val_if_fail (uri != NULL, FALSE);
482
483 switch (source_type) {
484 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
485 extension_name = E_SOURCE_EXTENSION_CALENDAR;
486 break;
487 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
488 extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
489 break;
490 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
491 extension_name = E_SOURCE_EXTENSION_TASK_LIST;
492 break;
493 default:
494 g_warn_if_reached ();
495 return FALSE;
496 }
497
498 shell = e_shell_backend_get_shell (shell_backend);
499
500 soup_uri = soup_uri_new (uri);
501
502 if (soup_uri == NULL)
503 return FALSE;
504
505 g_date_clear (&start_date, 1);
506 g_date_clear (&end_date, 1);
507
508 settings = e_util_ref_settings ("org.gnome.evolution.calendar");
509
510 if (g_settings_get_boolean (settings, "use-system-timezone"))
511 zone = e_cal_util_get_system_timezone ();
512 else {
513 gchar *location;
514
515 location = g_settings_get_string (settings, "timezone");
516
517 if (location != NULL) {
518 zone = i_cal_timezone_get_builtin_timezone (location);
519 g_free (location);
520 }
521 }
522
523 if (zone == NULL)
524 zone = i_cal_timezone_get_utc_timezone ();
525
526 g_object_unref (settings);
527
528 cp = soup_uri_get_query (soup_uri);
529 if (cp == NULL)
530 goto exit;
531
532 while (*cp != '\0') {
533 gchar *header;
534 gchar *content;
535 gsize header_len;
536 gsize content_len;
537
538 header_len = strcspn (cp, "=&");
539
540 /* If it's malformed, give up. */
541 if (cp[header_len] != '=')
542 break;
543
544 header = (gchar *) cp;
545 header[header_len] = '\0';
546 cp += header_len + 1;
547
548 content_len = strcspn (cp, "&");
549
550 content = g_strndup (cp, content_len);
551 if (g_ascii_strcasecmp (header, "startdate") == 0)
552 populate_g_date (&start_date, convert_time_from_isodate (content, zone), zone);
553 else if (g_ascii_strcasecmp (header, "enddate") == 0)
554 populate_g_date (&end_date, convert_time_from_isodate (content, zone) - 1, zone);
555 else if (g_ascii_strcasecmp (header, "source-uid") == 0)
556 source_uid = g_uri_unescape_string (content, NULL);
557 else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
558 comp_uid = g_uri_unescape_string (content, NULL);
559 else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
560 comp_rid = g_uri_unescape_string (content, NULL);
561 else if (g_ascii_strcasecmp (header, "new-ics") == 0)
562 new_ics = g_uri_unescape_string (content, NULL);
563 else if (g_ascii_strcasecmp (header, "attendees") == 0)
564 attendees = g_strcmp0 (content, "true") == 0 || g_strcmp0 (content, "1") == 0;
565 g_free (content);
566
567 cp += content_len;
568 if (*cp == '&') {
569 cp++;
570 if (strcmp (cp, "amp;") == 0)
571 cp += 4;
572 }
573 }
574
575 /* This is primarily for launching Evolution
576 * from the calendar in the clock applet. */
577 if (g_date_valid (&start_date) && handle_start_end_dates) {
578 if (g_date_valid (&end_date) && g_date_compare (&start_date, &end_date) > 0)
579 end_date = start_date;
580
581 handle_start_end_dates (shell_backend, &start_date, &end_date);
582 handled = TRUE;
583 goto exit;
584 }
585
586 if (!new_ics && (!source_uid || !comp_uid))
587 goto exit;
588
589 /* URI is valid, so consider it handled. Whether
590 * we successfully open it is another matter... */
591 handled = TRUE;
592
593 shell_window = NULL;
594 windows = gtk_application_get_windows (GTK_APPLICATION (shell));
595 for (link = windows; link; link = g_list_next (link)) {
596 GtkWindow *window = link->data;
597
598 if (E_IS_SHELL_WINDOW (window)) {
599 shell_window = E_SHELL_WINDOW (window);
600 break;
601 }
602 }
603
604 if (new_ics) {
605 gchar *content = NULL;
606 ICalComponent *icomp;
607 GError *error = NULL;
608
609 if (!g_file_get_contents (new_ics, &content, NULL, &error)) {
610 if (error)
611 g_warning ("Cannot create new ics: %s", error->message);
612 else
613 g_warning ("Cannot create new ics: Failed to open file '%s': Unknown error", new_ics);
614 g_clear_error (&error);
615 goto exit;
616 }
617
618 icomp = content ? i_cal_component_new_from_string (content) : NULL;
619 if (!icomp) {
620 g_warning ("Cannot create new ics: File '%s' doesn't contain valid iCalendar component", new_ics);
621 g_free (content);
622 goto exit;
623 }
624
625 if (i_cal_component_isa (icomp) == I_CAL_VEVENT_COMPONENT &&
626 source_type != E_CAL_CLIENT_SOURCE_TYPE_EVENTS) {
627 g_warning ("Cannot create new ics: Expected %s, but got VEVENT", source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ? "VTODO" : "VJOURNAL");
628 } else if (i_cal_component_isa (icomp) == I_CAL_VJOURNAL_COMPONENT &&
629 source_type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
630 g_warning ("Cannot create new ics: Expected %s, but got VJOURNAL", source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ? "VTODO" : "VEVENT");
631 } else if (i_cal_component_isa (icomp) == I_CAL_VTODO_COMPONENT &&
632 source_type != E_CAL_CLIENT_SOURCE_TYPE_TASKS) {
633 g_warning ("Cannot create new ics: Expected %s, but got VTODO", source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS ? "VJOURNAL" : "VEVENT");
634 } else if (i_cal_component_isa (icomp) != I_CAL_VEVENT_COMPONENT &&
635 i_cal_component_isa (icomp) != I_CAL_VJOURNAL_COMPONENT &&
636 i_cal_component_isa (icomp) != I_CAL_VTODO_COMPONENT) {
637 g_warning ("Cannot create new ics: Received unexpected component type '%s'", i_cal_component_kind_to_string (i_cal_component_isa (icomp)));
638 } else {
639 ECompEditor *comp_editor;
640 ESource *source = NULL;
641 ECompEditorFlags flags;
642
643 if (source_uid) {
644 ESourceRegistry *registry;
645
646 registry = e_shell_get_registry (shell);
647 source = e_source_registry_ref_source (registry, source_uid);
648 }
649
650 flags = E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER |
651 (attendees ? E_COMP_EDITOR_FLAG_WITH_ATTENDEES : 0);
652
653 comp_editor = e_comp_editor_open_for_component (NULL, shell, source, icomp, flags);
654
655 if (comp_editor)
656 gtk_window_present (GTK_WINDOW (comp_editor));
657
658 g_clear_object (&source);
659 }
660
661 g_object_unref (icomp);
662 g_free (content);
663 } else if (shell_window) {
664 HandleUriData *hud;
665 ESourceRegistry *registry;
666 ESource *source;
667 EShellView *shell_view;
668 EActivity *activity;
669 gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
670 gchar *source_display_name = NULL;
671
672 hud = g_slice_new0 (HandleUriData);
673 hud->shell_backend = g_object_ref (shell_backend);
674 hud->source_type = source_type;
675 hud->source_uid = g_strdup (source_uid);
676 hud->comp_uid = g_strdup (comp_uid);
677 hud->comp_rid = g_strdup (comp_rid);
678 hud->cal_client = NULL;
679 hud->existing_icomp = NULL;
680
681 registry = e_shell_get_registry (shell);
682 source = e_source_registry_ref_source (registry, source_uid);
683 if (source)
684 source_display_name = e_util_get_source_full_name (registry, source);
685
686 shell_view = e_shell_window_get_shell_view (shell_window,
687 e_shell_window_get_active_view (shell_window));
688
689 g_warn_if_fail (e_util_get_open_source_job_info (extension_name,
690 source_display_name ? source_display_name : "", &description, &alert_ident, &alert_arg_0));
691
692 activity = e_shell_view_submit_thread_job (
693 shell_view, description, alert_ident, alert_arg_0,
694 cal_base_shell_backend_handle_uri_thread, hud, handle_uri_data_free);
695
696 g_clear_object (&activity);
697 g_clear_object (&source);
698 g_free (source_display_name);
699 g_free (description);
700 g_free (alert_ident);
701 g_free (alert_arg_0);
702 } else {
703 g_warn_if_reached ();
704 }
705
706 exit:
707 g_free (source_uid);
708 g_free (comp_uid);
709 g_free (comp_rid);
710 g_free (new_ics);
711
712 soup_uri_free (soup_uri);
713
714 return handled;
715 }
716