evolution-3.6.4/calendar/gui/e-cal-model.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-cal-model.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-cal-model.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  * Evolution calendar - Data model for ETable
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Authors:
  19  *		Rodrigo Moya <rodrigo@ximian.com>
  20  *
  21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  22  *
  23  */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include <config.h>
  27 #endif
  28 
  29 #include <string.h>
  30 #include <glib/gi18n.h>
  31 
  32 #include <libebackend/libebackend.h>
  33 
  34 #include <e-util/e-util.h>
  35 #include <e-util/e-util-enumtypes.h>
  36 
  37 #include "comp-util.h"
  38 #include "e-cal-model.h"
  39 #include "itip-utils.h"
  40 #include "misc.h"
  41 
  42 struct _ECalModelComponentPrivate {
  43 	GString *categories_str;
  44 };
  45 
  46 #define E_CAL_MODEL_GET_PRIVATE(obj) \
  47 	(G_TYPE_INSTANCE_GET_PRIVATE \
  48 	((obj), E_TYPE_CAL_MODEL, ECalModelPrivate))
  49 
  50 #define E_CAL_MODEL_COMPONENT_GET_PRIVATE(obj) \
  51 	(G_TYPE_INSTANCE_GET_PRIVATE \
  52 	((obj), E_TYPE_CAL_MODEL_COMPONENT, ECalModelComponentPrivate))
  53 
  54 typedef struct {
  55 	ECalClient *client;
  56 	ECalClientView *view;
  57 
  58 	gboolean do_query;
  59 	GCancellable *cancellable;
  60 } ECalModelClient;
  61 
  62 struct _ECalModelPrivate {
  63 	ESourceRegistry *registry;
  64 
  65 	/* The list of clients we are managing. Each element is of type ECalModelClient */
  66 	GList *clients;
  67 
  68 	/* The default client in the list */
  69 	ECalClient *default_client;
  70 
  71 	/* Array for storing the objects. Each element is of type ECalModelComponent */
  72 	GPtrArray *objects;
  73 
  74 	icalcomponent_kind kind;
  75 	ECalModelFlags flags;
  76 	icaltimezone *zone;
  77 
  78 	/* The time range to display */
  79 	time_t start;
  80 	time_t end;
  81 
  82 	/* The search regular expression */
  83 	gchar *search_sexp;
  84 
  85 	/* The full regular expression, including time range */
  86 	gchar *full_sexp;
  87 
  88 	/* The default category */
  89 	gchar *default_category;
  90 
  91 	/* Whether we display dates in 24-hour format. */
  92         gboolean use_24_hour_format;
  93 
  94 	/* Whether to compress weekends into one cell. */
  95 	gboolean compress_weekend;
  96 
  97 	/* First day of the week: 0 (Monday) to 6 (Sunday) */
  98 	gint week_start_day;
  99 
 100 	/* Work day timespan */
 101 	gint work_day_start_hour;
 102 	gint work_day_start_minute;
 103 	gint work_day_end_hour;
 104 	gint work_day_end_minute;
 105 
 106 	/* callback, to retrieve start time for newly added rows by click-to-add */
 107 	ECalModelDefaultTimeFunc get_default_time;
 108 	gpointer get_default_time_user_data;
 109 
 110 	/* Default reminder for events */
 111 	gboolean use_default_reminder;
 112 	gint default_reminder_interval;
 113 	EDurationType default_reminder_units;
 114 
 115 	/* Ask user to confirm before deleting components. */
 116 	gboolean confirm_delete;
 117 
 118 	gboolean in_added;
 119 	gboolean in_modified;
 120 	gboolean in_removed;
 121 
 122 	GHashTable *notify_added;
 123 	GHashTable *notify_modified;
 124 	GHashTable *notify_removed;
 125 
 126 	GMutex *notify_lock;
 127 
 128 	GCancellable *loading_clients;
 129 };
 130 
 131 static gint ecm_column_count (ETableModel *etm);
 132 static gint ecm_row_count (ETableModel *etm);
 133 static gpointer ecm_value_at (ETableModel *etm, gint col, gint row);
 134 static void ecm_set_value_at (ETableModel *etm, gint col, gint row, gconstpointer value);
 135 static gboolean ecm_is_cell_editable (ETableModel *etm, gint col, gint row);
 136 static void ecm_append_row (ETableModel *etm, ETableModel *source, gint row);
 137 static gpointer ecm_duplicate_value (ETableModel *etm, gint col, gconstpointer value);
 138 static void ecm_free_value (ETableModel *etm, gint col, gpointer value);
 139 static gpointer ecm_initialize_value (ETableModel *etm, gint col);
 140 static gboolean ecm_value_is_empty (ETableModel *etm, gint col, gconstpointer value);
 141 static gchar *ecm_value_to_string (ETableModel *etm, gint col, gconstpointer value);
 142 
 143 static const gchar *ecm_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data);
 144 
 145 static ECalModelClient *add_new_client (ECalModel *model, ECalClient *client, gboolean do_query);
 146 static ECalModelClient *find_client_data (ECalModel *model, ECalClient *client);
 147 static void remove_client_objects (ECalModel *model, ECalModelClient *client_data);
 148 static void remove_client (ECalModel *model, ECalModelClient *client_data);
 149 static void redo_queries (ECalModel *model);
 150 
 151 enum {
 152 	PROP_0,
 153 	PROP_COMPRESS_WEEKEND,
 154 	PROP_CONFIRM_DELETE,
 155 	PROP_DEFAULT_CLIENT,
 156 	PROP_DEFAULT_REMINDER_INTERVAL,
 157 	PROP_DEFAULT_REMINDER_UNITS,
 158 	PROP_REGISTRY,
 159 	PROP_TIMEZONE,
 160 	PROP_USE_24_HOUR_FORMAT,
 161 	PROP_USE_DEFAULT_REMINDER,
 162 	PROP_WEEK_START_DAY,
 163 	PROP_WORK_DAY_END_HOUR,
 164 	PROP_WORK_DAY_END_MINUTE,
 165 	PROP_WORK_DAY_START_HOUR,
 166 	PROP_WORK_DAY_START_MINUTE
 167 };
 168 
 169 enum {
 170 	TIME_RANGE_CHANGED,
 171 	ROW_APPENDED,
 172 	COMPS_DELETED,
 173 	CAL_VIEW_PROGRESS,
 174 	CAL_VIEW_COMPLETE,
 175 	STATUS_MESSAGE,
 176 	TIMEZONE_CHANGED,
 177 	LAST_SIGNAL
 178 };
 179 
 180 static guint signals[LAST_SIGNAL];
 181 
 182 G_DEFINE_TYPE_WITH_CODE (
 183 	ECalModel, e_cal_model, E_TYPE_TABLE_MODEL,
 184 	G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
 185 
 186 G_DEFINE_TYPE (
 187 	ECalModelComponent,
 188 	e_cal_model_component,
 189 	G_TYPE_OBJECT)
 190 
 191 static void
 192 cal_model_set_registry (ECalModel *model,
 193                         ESourceRegistry *registry)
 194 {
 195 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
 196 	g_return_if_fail (model->priv->registry == NULL);
 197 
 198 	model->priv->registry = g_object_ref (registry);
 199 }
 200 
 201 static void
 202 cal_model_set_property (GObject *object,
 203                         guint property_id,
 204                         const GValue *value,
 205                         GParamSpec *pspec)
 206 {
 207 	switch (property_id) {
 208 		case PROP_COMPRESS_WEEKEND:
 209 			e_cal_model_set_compress_weekend (
 210 				E_CAL_MODEL (object),
 211 				g_value_get_boolean (value));
 212 			return;
 213 
 214 		case PROP_CONFIRM_DELETE:
 215 			e_cal_model_set_confirm_delete (
 216 				E_CAL_MODEL (object),
 217 				g_value_get_boolean (value));
 218 			return;
 219 
 220 		case PROP_DEFAULT_CLIENT:
 221 			e_cal_model_set_default_client (
 222 				E_CAL_MODEL (object),
 223 				g_value_get_object (value));
 224 			return;
 225 
 226 		case PROP_DEFAULT_REMINDER_INTERVAL:
 227 			e_cal_model_set_default_reminder_interval (
 228 				E_CAL_MODEL (object),
 229 				g_value_get_int (value));
 230 			return;
 231 
 232 		case PROP_DEFAULT_REMINDER_UNITS:
 233 			e_cal_model_set_default_reminder_units (
 234 				E_CAL_MODEL (object),
 235 				g_value_get_enum (value));
 236 			return;
 237 
 238 		case PROP_REGISTRY:
 239 			cal_model_set_registry (
 240 				E_CAL_MODEL (object),
 241 				g_value_get_object (value));
 242 			return;
 243 
 244 		case PROP_TIMEZONE:
 245 			e_cal_model_set_timezone (
 246 				E_CAL_MODEL (object),
 247 				g_value_get_pointer (value));
 248 			return;
 249 
 250 		case PROP_USE_24_HOUR_FORMAT:
 251 			e_cal_model_set_use_24_hour_format (
 252 				E_CAL_MODEL (object),
 253 				g_value_get_boolean (value));
 254 			return;
 255 
 256 		case PROP_USE_DEFAULT_REMINDER:
 257 			e_cal_model_set_use_default_reminder (
 258 				E_CAL_MODEL (object),
 259 				g_value_get_boolean (value));
 260 			return;
 261 
 262 		case PROP_WEEK_START_DAY:
 263 			e_cal_model_set_week_start_day (
 264 				E_CAL_MODEL (object),
 265 				g_value_get_int (value));
 266 			return;
 267 
 268 		case PROP_WORK_DAY_END_HOUR:
 269 			e_cal_model_set_work_day_end_hour (
 270 				E_CAL_MODEL (object),
 271 				g_value_get_int (value));
 272 			return;
 273 
 274 		case PROP_WORK_DAY_END_MINUTE:
 275 			e_cal_model_set_work_day_end_minute (
 276 				E_CAL_MODEL (object),
 277 				g_value_get_int (value));
 278 			return;
 279 
 280 		case PROP_WORK_DAY_START_HOUR:
 281 			e_cal_model_set_work_day_start_hour (
 282 				E_CAL_MODEL (object),
 283 				g_value_get_int (value));
 284 			return;
 285 
 286 		case PROP_WORK_DAY_START_MINUTE:
 287 			e_cal_model_set_work_day_start_minute (
 288 				E_CAL_MODEL (object),
 289 				g_value_get_int (value));
 290 			return;
 291 	}
 292 
 293 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 294 }
 295 
 296 static void
 297 cal_model_get_property (GObject *object,
 298                         guint property_id,
 299                         GValue *value,
 300                         GParamSpec *pspec)
 301 {
 302 	switch (property_id) {
 303 		case PROP_COMPRESS_WEEKEND:
 304 			g_value_set_boolean (
 305 				value,
 306 				e_cal_model_get_compress_weekend (
 307 				E_CAL_MODEL (object)));
 308 			return;
 309 
 310 		case PROP_CONFIRM_DELETE:
 311 			g_value_set_boolean (
 312 				value,
 313 				e_cal_model_get_confirm_delete (
 314 				E_CAL_MODEL (object)));
 315 			return;
 316 
 317 		case PROP_DEFAULT_CLIENT:
 318 			g_value_set_object (
 319 				value,
 320 				e_cal_model_get_default_client (
 321 				E_CAL_MODEL (object)));
 322 			return;
 323 
 324 		case PROP_DEFAULT_REMINDER_INTERVAL:
 325 			g_value_set_int (
 326 				value,
 327 				e_cal_model_get_default_reminder_interval (
 328 				E_CAL_MODEL (object)));
 329 			return;
 330 
 331 		case PROP_DEFAULT_REMINDER_UNITS:
 332 			g_value_set_enum (
 333 				value,
 334 				e_cal_model_get_default_reminder_units (
 335 				E_CAL_MODEL (object)));
 336 			return;
 337 
 338 		case PROP_REGISTRY:
 339 			g_value_set_object (
 340 				value,
 341 				e_cal_model_get_registry (
 342 				E_CAL_MODEL (object)));
 343 			return;
 344 
 345 		case PROP_TIMEZONE:
 346 			g_value_set_pointer (
 347 				value,
 348 				e_cal_model_get_timezone (
 349 				E_CAL_MODEL (object)));
 350 			return;
 351 
 352 		case PROP_USE_24_HOUR_FORMAT:
 353 			g_value_set_boolean (
 354 				value,
 355 				e_cal_model_get_use_24_hour_format (
 356 				E_CAL_MODEL (object)));
 357 			return;
 358 
 359 		case PROP_USE_DEFAULT_REMINDER:
 360 			g_value_set_boolean (
 361 				value,
 362 				e_cal_model_get_use_default_reminder (
 363 				E_CAL_MODEL (object)));
 364 			return;
 365 
 366 		case PROP_WEEK_START_DAY:
 367 			g_value_set_int (
 368 				value,
 369 				e_cal_model_get_week_start_day (
 370 				E_CAL_MODEL (object)));
 371 			return;
 372 
 373 		case PROP_WORK_DAY_END_HOUR:
 374 			g_value_set_int (
 375 				value,
 376 				e_cal_model_get_work_day_end_hour (
 377 				E_CAL_MODEL (object)));
 378 			return;
 379 
 380 		case PROP_WORK_DAY_END_MINUTE:
 381 			g_value_set_int (
 382 				value,
 383 				e_cal_model_get_work_day_end_minute (
 384 				E_CAL_MODEL (object)));
 385 			return;
 386 
 387 		case PROP_WORK_DAY_START_HOUR:
 388 			g_value_set_int (
 389 				value,
 390 				e_cal_model_get_work_day_start_hour (
 391 				E_CAL_MODEL (object)));
 392 			return;
 393 
 394 		case PROP_WORK_DAY_START_MINUTE:
 395 			g_value_set_int (
 396 				value,
 397 				e_cal_model_get_work_day_start_minute (
 398 				E_CAL_MODEL (object)));
 399 			return;
 400 	}
 401 
 402 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 403 }
 404 
 405 static void
 406 cal_model_constructed (GObject *object)
 407 {
 408 	e_extensible_load_extensions (E_EXTENSIBLE (object));
 409 
 410 	/* Chain up to parent's constructed() method. */
 411 	G_OBJECT_CLASS (e_cal_model_parent_class)->constructed (object);
 412 }
 413 
 414 static void
 415 cal_model_dispose (GObject *object)
 416 {
 417 	ECalModelPrivate *priv;
 418 
 419 	priv = E_CAL_MODEL_GET_PRIVATE (object);
 420 
 421 	if (priv->registry != NULL) {
 422 		g_object_unref (priv->registry);
 423 		priv->registry = NULL;
 424 	}
 425 
 426 	if (priv->loading_clients) {
 427 		g_cancellable_cancel (priv->loading_clients);
 428 		g_object_unref (priv->loading_clients);
 429 		priv->loading_clients = NULL;
 430 	}
 431 
 432 	if (priv->clients) {
 433 		while (priv->clients != NULL) {
 434 			ECalModelClient *client_data = (ECalModelClient *) priv->clients->data;
 435 
 436 			g_signal_handlers_disconnect_matched (
 437 				client_data->client, G_SIGNAL_MATCH_DATA,
 438 				0, 0, NULL, NULL, object);
 439 			if (client_data->view)
 440 				g_signal_handlers_disconnect_matched (
 441 					client_data->view, G_SIGNAL_MATCH_DATA,
 442 					0, 0, NULL, NULL, object);
 443 
 444 			priv->clients = g_list_remove (priv->clients, client_data);
 445 
 446 			g_object_unref (client_data->client);
 447 			if (client_data->cancellable) {
 448 				g_cancellable_cancel (client_data->cancellable);
 449 				g_object_unref (client_data->cancellable);
 450 			}
 451 			if (client_data->view)
 452 				g_object_unref (client_data->view);
 453 			g_free (client_data);
 454 		}
 455 
 456 		priv->clients = NULL;
 457 		priv->default_client = NULL;
 458 	}
 459 
 460 	/* Chain up to parent's dispose() method. */
 461 	G_OBJECT_CLASS (e_cal_model_parent_class)->dispose (object);
 462 }
 463 
 464 static void
 465 cal_model_finalize (GObject *object)
 466 {
 467 	ECalModelPrivate *priv;
 468 	gint ii;
 469 
 470 	priv = E_CAL_MODEL_GET_PRIVATE (object);
 471 
 472 	g_free (priv->search_sexp);
 473 	g_free (priv->full_sexp);
 474 
 475 	g_free (priv->default_category);
 476 
 477 	for (ii = 0; ii < priv->objects->len; ii++) {
 478 		ECalModelComponent *comp_data;
 479 
 480 		comp_data = g_ptr_array_index (priv->objects, ii);
 481 		if (comp_data == NULL) {
 482 			g_warning ("comp_data is null\n");
 483 			continue;
 484 		}
 485 		g_object_unref (comp_data);
 486 	}
 487 	g_ptr_array_free (priv->objects, FALSE);
 488 
 489 	g_mutex_free (priv->notify_lock);
 490 
 491 	g_hash_table_destroy (priv->notify_added);
 492 	g_hash_table_destroy (priv->notify_modified);
 493 	g_hash_table_destroy (priv->notify_removed);
 494 
 495 	/* Chain up to parent's finalize() method. */
 496 	G_OBJECT_CLASS (e_cal_model_parent_class)->finalize (object);
 497 }
 498 
 499 static void
 500 e_cal_model_class_init (ECalModelClass *class)
 501 {
 502 	GObjectClass *object_class;
 503 	ETableModelClass *etm_class;
 504 
 505 	g_type_class_add_private (class, sizeof (ECalModelPrivate));
 506 
 507 	object_class = G_OBJECT_CLASS (class);
 508 	object_class->set_property = cal_model_set_property;
 509 	object_class->get_property = cal_model_get_property;
 510 	object_class->constructed = cal_model_constructed;
 511 	object_class->dispose = cal_model_dispose;
 512 	object_class->finalize = cal_model_finalize;
 513 
 514 	etm_class = E_TABLE_MODEL_CLASS (class);
 515 	etm_class->column_count = ecm_column_count;
 516 	etm_class->row_count = ecm_row_count;
 517 	etm_class->value_at = ecm_value_at;
 518 	etm_class->set_value_at = ecm_set_value_at;
 519 	etm_class->is_cell_editable = ecm_is_cell_editable;
 520 	etm_class->append_row = ecm_append_row;
 521 	etm_class->duplicate_value = ecm_duplicate_value;
 522 	etm_class->free_value = ecm_free_value;
 523 	etm_class->initialize_value = ecm_initialize_value;
 524 	etm_class->value_is_empty = ecm_value_is_empty;
 525 	etm_class->value_to_string = ecm_value_to_string;
 526 
 527 	class->get_color_for_component = ecm_get_color_for_component;
 528 	class->fill_component_from_model = NULL;
 529 
 530 	g_object_class_install_property (
 531 		object_class,
 532 		PROP_COMPRESS_WEEKEND,
 533 		g_param_spec_boolean (
 534 			"compress-weekend",
 535 			"Compress Weekend",
 536 			NULL,
 537 			FALSE,
 538 			G_PARAM_READWRITE));
 539 
 540 	g_object_class_install_property (
 541 		object_class,
 542 		PROP_CONFIRM_DELETE,
 543 		g_param_spec_boolean (
 544 			"confirm-delete",
 545 			"Confirm Delete",
 546 			NULL,
 547 			TRUE,
 548 			G_PARAM_READWRITE));
 549 
 550 	g_object_class_install_property (
 551 		object_class,
 552 		PROP_DEFAULT_CLIENT,
 553 		g_param_spec_object (
 554 			"default-client",
 555 			"Default ECalClient",
 556 			NULL,
 557 			E_TYPE_CAL_CLIENT,
 558 			G_PARAM_READWRITE));
 559 
 560 	g_object_class_install_property (
 561 		object_class,
 562 		PROP_DEFAULT_REMINDER_INTERVAL,
 563 		g_param_spec_int (
 564 			"default-reminder-interval",
 565 			"Default Reminder Interval",
 566 			NULL,
 567 			G_MININT,
 568 			G_MAXINT,
 569 			0,
 570 			G_PARAM_READWRITE));
 571 
 572 	g_object_class_install_property (
 573 		object_class,
 574 		PROP_DEFAULT_REMINDER_UNITS,
 575 		g_param_spec_enum (
 576 			"default-reminder-units",
 577 			"Default Reminder Units",
 578 			NULL,
 579 			E_TYPE_DURATION_TYPE,
 580 			E_DURATION_MINUTES,
 581 			G_PARAM_READWRITE));
 582 
 583 	g_object_class_install_property (
 584 		object_class,
 585 		PROP_REGISTRY,
 586 		g_param_spec_object (
 587 			"registry",
 588 			"Registry",
 589 			"Data source registry",
 590 			E_TYPE_SOURCE_REGISTRY,
 591 			G_PARAM_READWRITE |
 592 			G_PARAM_CONSTRUCT_ONLY));
 593 
 594 	g_object_class_install_property (
 595 		object_class,
 596 		PROP_TIMEZONE,
 597 		g_param_spec_pointer (
 598 			"timezone",
 599 			"Time Zone",
 600 			NULL,
 601 			G_PARAM_READWRITE));
 602 
 603 	g_object_class_install_property (
 604 		object_class,
 605 		PROP_USE_24_HOUR_FORMAT,
 606 		g_param_spec_boolean (
 607 			"use-24-hour-format",
 608 			"Use 24-Hour Format",
 609 			NULL,
 610 			TRUE,
 611 			G_PARAM_READWRITE));
 612 
 613 	g_object_class_install_property (
 614 		object_class,
 615 		PROP_USE_DEFAULT_REMINDER,
 616 		g_param_spec_boolean (
 617 			"use-default-reminder",
 618 			"Use Default Reminder",
 619 			NULL,
 620 			FALSE,
 621 			G_PARAM_READWRITE));
 622 
 623 	g_object_class_install_property (
 624 		object_class,
 625 		PROP_WEEK_START_DAY,
 626 		g_param_spec_int (
 627 			"week-start-day",
 628 			"Week Start Day",
 629 			NULL,
 630 			0,  /* Monday */
 631 			6,  /* Sunday */
 632 			0,
 633 			G_PARAM_READWRITE));
 634 
 635 	g_object_class_install_property (
 636 		object_class,
 637 		PROP_WORK_DAY_END_HOUR,
 638 		g_param_spec_int (
 639 			"work-day-end-hour",
 640 			"Work Day End Hour",
 641 			NULL,
 642 			0,
 643 			23,
 644 			0,
 645 			G_PARAM_READWRITE));
 646 
 647 	g_object_class_install_property (
 648 		object_class,
 649 		PROP_WORK_DAY_END_MINUTE,
 650 		g_param_spec_int (
 651 			"work-day-end-minute",
 652 			"Work Day End Minute",
 653 			NULL,
 654 			0,
 655 			59,
 656 			0,
 657 			G_PARAM_READWRITE));
 658 
 659 	g_object_class_install_property (
 660 		object_class,
 661 		PROP_WORK_DAY_START_HOUR,
 662 		g_param_spec_int (
 663 			"work-day-start-hour",
 664 			"Work Day Start Hour",
 665 			NULL,
 666 			0,
 667 			23,
 668 			0,
 669 			G_PARAM_READWRITE));
 670 
 671 	g_object_class_install_property (
 672 		object_class,
 673 		PROP_WORK_DAY_START_MINUTE,
 674 		g_param_spec_int (
 675 			"work-day-start-minute",
 676 			"Work Day Start Minute",
 677 			NULL,
 678 			0,
 679 			59,
 680 			0,
 681 			G_PARAM_READWRITE));
 682 
 683 	signals[TIME_RANGE_CHANGED] = g_signal_new (
 684 		"time_range_changed",
 685 		G_TYPE_FROM_CLASS (class),
 686 		G_SIGNAL_RUN_LAST,
 687 		G_STRUCT_OFFSET (ECalModelClass, time_range_changed),
 688 		NULL, NULL,
 689 		e_marshal_VOID__LONG_LONG,
 690 		G_TYPE_NONE, 2,
 691 		G_TYPE_LONG,
 692 		G_TYPE_LONG);
 693 
 694 	signals[ROW_APPENDED] = g_signal_new (
 695 		"row_appended",
 696 		G_TYPE_FROM_CLASS (class),
 697 		G_SIGNAL_RUN_LAST,
 698 		G_STRUCT_OFFSET (ECalModelClass, row_appended),
 699 		NULL, NULL,
 700 		g_cclosure_marshal_VOID__VOID,
 701 		G_TYPE_NONE, 0);
 702 
 703 	signals[COMPS_DELETED] = g_signal_new (
 704 		"comps_deleted",
 705 		G_TYPE_FROM_CLASS (class),
 706 		G_SIGNAL_RUN_LAST,
 707 		G_STRUCT_OFFSET (ECalModelClass, comps_deleted),
 708 		NULL, NULL,
 709 		g_cclosure_marshal_VOID__POINTER,
 710 		G_TYPE_NONE, 1,
 711 		G_TYPE_POINTER);
 712 
 713 	signals[CAL_VIEW_PROGRESS] = g_signal_new (
 714 		"cal_view_progress",
 715 		G_TYPE_FROM_CLASS (class),
 716 		G_SIGNAL_RUN_LAST,
 717 		G_STRUCT_OFFSET (ECalModelClass, cal_view_progress),
 718 		NULL, NULL,
 719 		e_marshal_VOID__STRING_INT_INT,
 720 		G_TYPE_NONE, 3,
 721 		G_TYPE_STRING,
 722 		G_TYPE_INT,
 723 		G_TYPE_INT);
 724 
 725 	signals[CAL_VIEW_COMPLETE] = g_signal_new (
 726 		"cal_view_complete",
 727 		G_TYPE_FROM_CLASS (class),
 728 		G_SIGNAL_RUN_LAST,
 729 		G_STRUCT_OFFSET (ECalModelClass, cal_view_complete),
 730 		NULL, NULL,
 731 		e_marshal_VOID__BOXED_INT,
 732 		G_TYPE_NONE, 2,
 733 		G_TYPE_ERROR,
 734 		G_TYPE_INT);
 735 
 736 	signals[STATUS_MESSAGE] = g_signal_new (
 737 		"status-message",
 738 		G_TYPE_FROM_CLASS (class),
 739 		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 740 		G_STRUCT_OFFSET (ECalModelClass, status_message),
 741 		NULL, NULL,
 742 		e_marshal_VOID__STRING_DOUBLE,
 743 		G_TYPE_NONE, 2,
 744 		G_TYPE_STRING,
 745 		G_TYPE_DOUBLE);
 746 
 747 	signals[TIMEZONE_CHANGED] = g_signal_new (
 748 		"timezone-changed",
 749 		G_TYPE_FROM_CLASS (class),
 750 		G_SIGNAL_RUN_LAST,
 751 		G_STRUCT_OFFSET (ECalModelClass, timezone_changed),
 752 		NULL, NULL,
 753 		e_marshal_VOID__POINTER_POINTER,
 754 		G_TYPE_NONE, 2,
 755 		G_TYPE_POINTER,
 756 		G_TYPE_POINTER);
 757 }
 758 
 759 static void
 760 e_cal_model_init (ECalModel *model)
 761 {
 762 	model->priv = E_CAL_MODEL_GET_PRIVATE (model);
 763 
 764 	/* match none by default */
 765 	model->priv->start = -1;
 766 	model->priv->end = -1;
 767 	model->priv->search_sexp = NULL;
 768 	model->priv->full_sexp = g_strdup ("#f");
 769 
 770 	model->priv->objects = g_ptr_array_new ();
 771 	model->priv->kind = ICAL_NO_COMPONENT;
 772 	model->priv->flags = 0;
 773 
 774 	model->priv->use_24_hour_format = TRUE;
 775 
 776 	model->priv->in_added = FALSE;
 777 	model->priv->in_modified = FALSE;
 778 	model->priv->in_removed = FALSE;
 779 	model->priv->notify_added = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
 780 	model->priv->notify_modified = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
 781 	model->priv->notify_removed = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
 782 	model->priv->notify_lock = g_mutex_new ();
 783 
 784 	model->priv->loading_clients = g_cancellable_new ();
 785 }
 786 
 787 /* ETableModel methods */
 788 
 789 static gint
 790 ecm_column_count (ETableModel *etm)
 791 {
 792 	return E_CAL_MODEL_FIELD_LAST;
 793 }
 794 
 795 static gint
 796 ecm_row_count (ETableModel *etm)
 797 {
 798 	ECalModelPrivate *priv;
 799 	ECalModel *model = (ECalModel *) etm;
 800 
 801 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
 802 
 803 	priv = model->priv;
 804 
 805 	return priv->objects->len;
 806 }
 807 
 808 static gpointer
 809 get_categories (ECalModelComponent *comp_data)
 810 {
 811 	if (!comp_data->priv->categories_str) {
 812 		icalproperty *prop;
 813 
 814 		comp_data->priv->categories_str = g_string_new ("");
 815 
 816 		for (prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CATEGORIES_PROPERTY);
 817 		     prop;
 818 		     prop = icalcomponent_get_next_property (comp_data->icalcomp, ICAL_CATEGORIES_PROPERTY)) {
 819 			const gchar *categories = icalproperty_get_categories (prop);
 820 			if (!categories)
 821 				continue;
 822 
 823 			if (comp_data->priv->categories_str->len)
 824 				g_string_append_c (comp_data->priv->categories_str, ',');
 825 			g_string_append (comp_data->priv->categories_str, categories);
 826 		}
 827 	}
 828 
 829 	return comp_data->priv->categories_str->str;
 830 }
 831 
 832 static gchar *
 833 get_classification (ECalModelComponent *comp_data)
 834 {
 835 	icalproperty *prop;
 836 	icalproperty_class class;
 837 
 838 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CLASS_PROPERTY);
 839 
 840 	if (!prop)
 841 		return _("Public");
 842 
 843 	class = icalproperty_get_class (prop);
 844 
 845 	switch (class)
 846 	{
 847 	case ICAL_CLASS_PUBLIC:
 848 		return _("Public");
 849 	case ICAL_CLASS_PRIVATE:
 850 		return _("Private");
 851 	case ICAL_CLASS_CONFIDENTIAL:
 852 		return _("Confidential");
 853 	default:
 854 		return _("Unknown");
 855 	}
 856 }
 857 
 858 static const gchar *
 859 get_color (ECalModel *model,
 860            ECalModelComponent *comp_data)
 861 {
 862 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
 863 
 864 	return e_cal_model_get_color_for_component (model, comp_data);
 865 }
 866 
 867 static gpointer
 868 get_description (ECalModelComponent *comp_data)
 869 {
 870 	icalproperty *prop;
 871 	static GString *str = NULL;
 872 
 873 	if (str) {
 874 		g_string_free (str, TRUE);
 875 		str = NULL;
 876 	}
 877 
 878 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY);
 879 	if (prop) {
 880 		str = g_string_new (NULL);
 881 		do {
 882 			str = g_string_append (str, icalproperty_get_description (prop));
 883 		} while ((prop = icalcomponent_get_next_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY)));
 884 
 885 		return str->str;
 886 	}
 887 
 888 	return (gpointer) "";
 889 }
 890 
 891 static ECellDateEditValue *
 892 get_dtstart (ECalModel *model,
 893              ECalModelComponent *comp_data)
 894 {
 895 	ECalModelPrivate *priv;
 896 	struct icaltimetype tt_start;
 897 
 898 	priv = model->priv;
 899 
 900 	if (!comp_data->dtstart) {
 901 		icalproperty *prop;
 902 		icaltimezone *zone;
 903 		gboolean got_zone = FALSE;
 904 
 905 		prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY);
 906 		if (!prop)
 907 			return NULL;
 908 
 909 		tt_start = icalproperty_get_dtstart (prop);
 910 
 911 		if (icaltime_get_tzid (tt_start)
 912 		    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_start), &zone, NULL, NULL))
 913 			got_zone = TRUE;
 914 
 915 		if (e_cal_model_get_flags (model) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) {
 916 			if (got_zone) {
 917 				tt_start = icaltime_from_timet_with_zone (comp_data->instance_start, tt_start.is_date, zone);
 918 				if (priv->zone)
 919 					icaltimezone_convert_time (&tt_start, zone, priv->zone);
 920 			} else
 921 				if (priv->zone)
 922 					tt_start = icaltime_from_timet_with_zone (comp_data->instance_start, tt_start.is_date, priv->zone);
 923 		}
 924 
 925 		if (!icaltime_is_valid_time (tt_start) || icaltime_is_null_time (tt_start))
 926 			return NULL;
 927 
 928 		comp_data->dtstart = g_new0 (ECellDateEditValue, 1);
 929 		comp_data->dtstart->tt = tt_start;
 930 
 931 		if (got_zone)
 932 			comp_data->dtstart->zone = zone;
 933 		else
 934 			comp_data->dtstart->zone = NULL;
 935 	}
 936 
 937 	return comp_data->dtstart;
 938 }
 939 
 940 static ECellDateEditValue *
 941 get_datetime_from_utc (ECalModel *model,
 942                        ECalModelComponent *comp_data,
 943                        icalproperty_kind propkind,
 944                        struct icaltimetype (*get_value) (const icalproperty *prop),
 945                                                          ECellDateEditValue **buffer)
 946 {
 947 	ECalModelPrivate *priv;
 948 	struct icaltimetype tt_value;
 949 	icalproperty *prop;
 950 	ECellDateEditValue *res;
 951 
 952 	g_return_val_if_fail (buffer!= NULL, NULL);
 953 
 954 	if (*buffer)
 955 		return *buffer;
 956 
 957 	priv = model->priv;
 958 
 959 	prop = icalcomponent_get_first_property (comp_data->icalcomp, propkind);
 960 	if (!prop)
 961 		return NULL;
 962 
 963 	tt_value = get_value (prop);
 964 
 965 	/* these are always in UTC, thus convert to default zone, if any and done */
 966 	if (priv->zone)
 967 		icaltimezone_convert_time (&tt_value, icaltimezone_get_utc_timezone (), priv->zone);
 968 
 969 	if (!icaltime_is_valid_time (tt_value) || icaltime_is_null_time (tt_value))
 970 		return NULL;
 971 
 972 	res = g_new0 (ECellDateEditValue, 1);
 973 	res->tt = tt_value;
 974 	res->zone = NULL;
 975 
 976 	*buffer = res;
 977 
 978 	return res;
 979 }
 980 
 981 static gpointer
 982 get_summary (ECalModelComponent *comp_data)
 983 {
 984 	icalproperty *prop;
 985 
 986 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_SUMMARY_PROPERTY);
 987 	if (prop)
 988 		return (gpointer) icalproperty_get_summary (prop);
 989 
 990 	return (gpointer) "";
 991 }
 992 
 993 static gchar *
 994 get_uid (ECalModelComponent *comp_data)
 995 {
 996 	return (gchar *) icalcomponent_get_uid (comp_data->icalcomp);
 997 }
 998 
 999 static gpointer
1000 ecm_value_at (ETableModel *etm,
1001               gint col,
1002               gint row)
1003 {
1004 	ECalModelPrivate *priv;
1005 	ECalModelComponent *comp_data;
1006 	ECalModel *model = (ECalModel *) etm;
1007 	ESourceRegistry *registry;
1008 
1009 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1010 
1011 	priv = model->priv;
1012 
1013 	registry = e_cal_model_get_registry (model);
1014 
1015 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1016 	g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL);
1017 
1018 	comp_data = g_ptr_array_index (priv->objects, row);
1019 	g_return_val_if_fail (comp_data != NULL, NULL);
1020 	g_return_val_if_fail (comp_data->icalcomp != NULL, NULL);
1021 
1022 	switch (col) {
1023 	case E_CAL_MODEL_FIELD_CATEGORIES :
1024 		return get_categories (comp_data);
1025 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1026 		return get_classification (comp_data);
1027 	case E_CAL_MODEL_FIELD_COLOR :
1028 		return (gpointer) get_color (model, comp_data);
1029 	case E_CAL_MODEL_FIELD_COMPONENT :
1030 		return comp_data->icalcomp;
1031 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1032 		return get_description (comp_data);
1033 	case E_CAL_MODEL_FIELD_DTSTART :
1034 		return (gpointer) get_dtstart (model, comp_data);
1035 	case E_CAL_MODEL_FIELD_CREATED :
1036 		return (gpointer) get_datetime_from_utc (
1037 			model, comp_data, ICAL_CREATED_PROPERTY,
1038 			icalproperty_get_created, &comp_data->created);
1039 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1040 		return (gpointer) get_datetime_from_utc (
1041 			model, comp_data, ICAL_LASTMODIFIED_PROPERTY,
1042 			icalproperty_get_lastmodified, &comp_data->lastmodified);
1043 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1044 		return GINT_TO_POINTER (
1045 			icalcomponent_get_first_component (
1046 				comp_data->icalcomp,
1047 				ICAL_VALARM_COMPONENT) != NULL);
1048 	case E_CAL_MODEL_FIELD_ICON :
1049 	{
1050 		ECalComponent *comp;
1051 		icalcomponent *icalcomp;
1052 		gint retval = 0;
1053 
1054 		comp = e_cal_component_new ();
1055 		icalcomp = icalcomponent_new_clone (comp_data->icalcomp);
1056 		if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
1057 			if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_JOURNAL) {
1058 				g_object_unref (comp);
1059 				return GINT_TO_POINTER (retval);
1060 			}
1061 
1062 			if (e_cal_component_has_recurrences (comp))
1063 				retval = 1;
1064 			else if (itip_organizer_is_user (registry, comp, comp_data->client))
1065 				retval = 3;
1066 			else {
1067 				GSList *attendees = NULL, *sl;
1068 
1069 				e_cal_component_get_attendee_list (comp, &attendees);
1070 				for (sl = attendees; sl != NULL; sl = sl->next) {
1071 					ECalComponentAttendee *ca = sl->data;
1072 					const gchar *text;
1073 
1074 					text = itip_strip_mailto (ca->value);
1075 					if (itip_address_is_user (registry, text)) {
1076 						if (ca->delto != NULL)
1077 							retval = 3;
1078 						else
1079 							retval = 2;
1080 						break;
1081 					}
1082 				}
1083 
1084 				e_cal_component_free_attendee_list (attendees);
1085 			}
1086 		} else
1087 			icalcomponent_free (icalcomp);
1088 
1089 		g_object_unref (comp);
1090 
1091 		return GINT_TO_POINTER (retval);
1092 	}
1093 	case E_CAL_MODEL_FIELD_SUMMARY :
1094 		return get_summary (comp_data);
1095 	case E_CAL_MODEL_FIELD_UID :
1096 		return get_uid (comp_data);
1097 	}
1098 
1099 	return (gpointer) "";
1100 }
1101 
1102 static void
1103 set_categories (ECalModelComponent *comp_data,
1104                 const gchar *value)
1105 {
1106 	icalproperty *prop;
1107 
1108 	/* remove all categories first */
1109 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CATEGORIES_PROPERTY);
1110 	while (prop) {
1111 		icalproperty *to_remove = prop;
1112 		prop = icalcomponent_get_next_property (comp_data->icalcomp, ICAL_CATEGORIES_PROPERTY);
1113 
1114 		icalcomponent_remove_property (comp_data->icalcomp, to_remove);
1115 		icalproperty_free (to_remove);
1116 	}
1117 
1118 	if (comp_data->priv->categories_str)
1119 		g_string_free (comp_data->priv->categories_str, TRUE);
1120 	comp_data->priv->categories_str = NULL;
1121 
1122 	/* then set a new value; no need to populate categories_str,
1123 	 * it'll be populated on demand (in the get_categories() function)
1124 	*/
1125 	if (value && *value) {
1126 		prop = icalproperty_new_categories (value);
1127 		icalcomponent_add_property (comp_data->icalcomp, prop);
1128 	}
1129 }
1130 
1131 static void
1132 set_classification (ECalModelComponent *comp_data,
1133                     const gchar *value)
1134 {
1135 	icalproperty *prop;
1136 
1137 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CLASS_PROPERTY);
1138 	if (!value || !(*value)) {
1139 		if (prop) {
1140 			icalcomponent_remove_property (comp_data->icalcomp, prop);
1141 			icalproperty_free (prop);
1142 		}
1143 	} else {
1144 	  icalproperty_class ical_class;
1145 
1146 	  if (!g_ascii_strcasecmp (value, "PUBLIC"))
1147 	    ical_class = ICAL_CLASS_PUBLIC;
1148 	  else if (!g_ascii_strcasecmp (value, "PRIVATE"))
1149 	    ical_class = ICAL_CLASS_PRIVATE;
1150 	  else if (!g_ascii_strcasecmp (value, "CONFIDENTIAL"))
1151 	    ical_class = ICAL_CLASS_CONFIDENTIAL;
1152 	  else
1153 	    ical_class = ICAL_CLASS_NONE;
1154 
1155 		if (!prop) {
1156 			prop = icalproperty_new_class (ical_class);
1157 			icalcomponent_add_property (comp_data->icalcomp, prop);
1158 		} else
1159 			icalproperty_set_class (prop, ical_class);
1160 	}
1161 }
1162 
1163 static void
1164 set_description (ECalModelComponent *comp_data,
1165                  const gchar *value)
1166 {
1167 	icalproperty *prop;
1168 
1169 	/* remove old description(s) */
1170 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY);
1171 	while (prop) {
1172 		icalproperty *next;
1173 
1174 		next = icalcomponent_get_next_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY);
1175 
1176 		icalcomponent_remove_property (comp_data->icalcomp, prop);
1177 		icalproperty_free (prop);
1178 
1179 		prop = next;
1180 	}
1181 
1182 	/* now add the new description */
1183 	if (!value || !(*value))
1184 		return;
1185 
1186 	prop = icalproperty_new_description (value);
1187 	icalcomponent_add_property (comp_data->icalcomp, prop);
1188 }
1189 
1190 static void
1191 datetime_to_zone (ECalClient *client,
1192                   struct icaltimetype *tt,
1193                   icaltimezone *tt_zone,
1194                   const gchar *tzid)
1195 {
1196 	icaltimezone *from, *to;
1197 	const gchar *tt_tzid = NULL;
1198 
1199 	g_return_if_fail (tt != NULL);
1200 
1201 	if (tt_zone)
1202 		tt_tzid = icaltimezone_get_tzid (tt_zone);
1203 
1204 	if (tt_tzid == NULL || tzid == NULL ||
1205 	    tt_tzid == tzid || g_str_equal (tt_tzid, tzid))
1206 		return;
1207 
1208 	from = tt_zone;
1209 	to = icaltimezone_get_builtin_timezone_from_tzid (tzid);
1210 	if (!to) {
1211 		/* do not check failure here, maybe the zone is not available there */
1212 		e_cal_client_get_timezone_sync (client, tzid, &to, NULL, NULL);
1213 	}
1214 
1215 	icaltimezone_convert_time (tt, from, to);
1216 }
1217 
1218 /* updates time in a component, and keeps the timezone used in it, if exists */
1219 void
1220 e_cal_model_update_comp_time (ECalModel *model,
1221                               ECalModelComponent *comp_data,
1222                               gconstpointer time_value,
1223                               icalproperty_kind kind,
1224                               void (*set_func) (icalproperty *prop,
1225                                                 struct icaltimetype v),
1226                               icalproperty * (*new_func) (struct icaltimetype v))
1227 {
1228 	ECellDateEditValue *dv = (ECellDateEditValue *) time_value;
1229 	icalproperty *prop;
1230 	icalparameter *param;
1231 	struct icaltimetype tt;
1232 
1233 	g_return_if_fail (model != NULL);
1234 	g_return_if_fail (comp_data != NULL);
1235 	g_return_if_fail (set_func != NULL);
1236 	g_return_if_fail (new_func != NULL);
1237 
1238 	prop = icalcomponent_get_first_property (comp_data->icalcomp, kind);
1239 	if (prop)
1240 		param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
1241 	else
1242 		param = NULL;
1243 
1244 	/* If we are setting the property to NULL (i.e. removing it), then
1245 	 * we remove it if it exists. */
1246 	if (!dv) {
1247 		if (prop) {
1248 			icalcomponent_remove_property (comp_data->icalcomp, prop);
1249 			icalproperty_free (prop);
1250 		}
1251 
1252 		return;
1253 	}
1254 
1255 	tt = dv->tt;
1256 	datetime_to_zone (comp_data->client, &tt, e_cal_model_get_timezone (model), param ? icalparameter_get_tzid (param) : NULL);
1257 
1258 	if (prop) {
1259 		set_func (prop, tt);
1260 	} else {
1261 		prop = new_func (tt);
1262 		icalcomponent_add_property (comp_data->icalcomp, prop);
1263 	}
1264 
1265 	if (param) {
1266 		const gchar *tzid = icalparameter_get_tzid (param);
1267 
1268 		/* If the TZID is set to "UTC", we don't want to save the TZID. */
1269 		if (tzid && strcmp (tzid, "UTC")) {
1270 			if (param) {
1271 				icalparameter_set_tzid (param, (gchar *) tzid);
1272 			} else {
1273 				param = icalparameter_new_tzid ((gchar *) tzid);
1274 				icalproperty_add_parameter (prop, param);
1275 			}
1276 		} else {
1277 			icalproperty_remove_parameter (prop, ICAL_TZID_PARAMETER);
1278 		}
1279 	}
1280 }
1281 
1282 static void
1283 set_dtstart (ECalModel *model,
1284              ECalModelComponent *comp_data,
1285              gconstpointer value)
1286 {
1287 	e_cal_model_update_comp_time (
1288 		model, comp_data, value,
1289 		ICAL_DTSTART_PROPERTY,
1290 		icalproperty_set_dtstart,
1291 		icalproperty_new_dtstart);
1292 }
1293 
1294 static void
1295 set_summary (ECalModelComponent *comp_data,
1296              const gchar *value)
1297 {
1298 	icalproperty *prop;
1299 
1300 	prop = icalcomponent_get_first_property (
1301 		comp_data->icalcomp, ICAL_SUMMARY_PROPERTY);
1302 
1303 	if (string_is_empty (value)) {
1304 		if (prop) {
1305 			icalcomponent_remove_property (comp_data->icalcomp, prop);
1306 			icalproperty_free (prop);
1307 		}
1308 	} else {
1309 		if (prop)
1310 			icalproperty_set_summary (prop, value);
1311 		else {
1312 			prop = icalproperty_new_summary (value);
1313 			icalcomponent_add_property (comp_data->icalcomp, prop);
1314 		}
1315 	}
1316 }
1317 
1318 static void
1319 ecm_set_value_at (ETableModel *etm,
1320                   gint col,
1321                   gint row,
1322                   gconstpointer value)
1323 {
1324 	ECalModelPrivate *priv;
1325 	ECalModelComponent *comp_data;
1326 	ECalModel *model = (ECalModel *) etm;
1327 	GError *error = NULL;
1328 
1329 	g_return_if_fail (E_IS_CAL_MODEL (model));
1330 
1331 	priv = model->priv;
1332 
1333 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST);
1334 	g_return_if_fail (row >= 0 && row < priv->objects->len);
1335 
1336 	comp_data = g_ptr_array_index (priv->objects, row);
1337 	g_return_if_fail (comp_data != NULL);
1338 
1339 	switch (col) {
1340 	case E_CAL_MODEL_FIELD_CATEGORIES :
1341 		set_categories (comp_data, value);
1342 		break;
1343 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1344 		set_classification (comp_data, value);
1345 		break;
1346 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1347 		set_description (comp_data, value);
1348 		break;
1349 	case E_CAL_MODEL_FIELD_DTSTART :
1350 		set_dtstart (model, comp_data, value);
1351 		break;
1352 	case E_CAL_MODEL_FIELD_SUMMARY :
1353 		set_summary (comp_data, value);
1354 		break;
1355 	}
1356 
1357 	/* FIXME ask about mod type */
1358 	e_cal_client_modify_object_sync (
1359 		comp_data->client, comp_data->icalcomp,
1360 		CALOBJ_MOD_ALL, NULL, &error);
1361 
1362 	if (error != NULL) {
1363 		g_warning (
1364 			G_STRLOC ": Could not modify the object! %s",
1365 			error->message);
1366 
1367 		/* FIXME Show error dialog */
1368 		g_error_free (error);
1369 	}
1370 }
1371 
1372 /**
1373  * e_cal_model_test_row_editable
1374  * @model: an #ECalModel
1375  * @row: Row of our interest. -1 is editable only when default client is
1376  * editable.
1377  *
1378  * Checks if component at @row is editable or not.  It doesn't check bounds
1379  * for @row.
1380  *
1381  * Returns: Whether @row is editable or not.
1382  **/
1383 gboolean
1384 e_cal_model_test_row_editable (ECalModel *model,
1385                                gint row)
1386 {
1387 	gboolean readonly;
1388 	ECalClient *client = NULL;
1389 
1390 	if (row != -1) {
1391 		ECalModelComponent *comp_data;
1392 
1393 		comp_data = e_cal_model_get_component_at (model, row);
1394 
1395 		if (comp_data)
1396 			client = comp_data->client;
1397 
1398 	} else {
1399 		client = e_cal_model_get_default_client (model);
1400 	}
1401 
1402 	readonly = client == NULL;
1403 
1404 	if (!readonly)
1405 		readonly = e_client_is_readonly (E_CLIENT (client));
1406 
1407 	return !readonly;
1408 }
1409 
1410 static gboolean
1411 ecm_is_cell_editable (ETableModel *etm,
1412                       gint col,
1413                       gint row)
1414 {
1415 	ECalModelPrivate *priv;
1416 	ECalModel *model = (ECalModel *) etm;
1417 
1418 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1419 
1420 	priv = model->priv;
1421 
1422 	g_return_val_if_fail (col >= 0 && col <= E_CAL_MODEL_FIELD_LAST, FALSE);
1423 	g_return_val_if_fail (row >= -1 || (row >= 0 && row < priv->objects->len), FALSE);
1424 
1425 	if (!e_cal_model_test_row_editable (E_CAL_MODEL (etm), row))
1426 		return FALSE;
1427 
1428 	switch (col) {
1429 	case E_CAL_MODEL_FIELD_CATEGORIES :
1430 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1431 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1432 	case E_CAL_MODEL_FIELD_DTSTART :
1433 	case E_CAL_MODEL_FIELD_SUMMARY :
1434 		return TRUE;
1435 	}
1436 
1437 	return FALSE;
1438 }
1439 
1440 static void
1441 ecm_append_row (ETableModel *etm,
1442                 ETableModel *source,
1443                 gint row)
1444 {
1445 	ECalModelClass *model_class;
1446 	ECalModelComponent *comp_data;
1447 	ECalModel *model = (ECalModel *) etm;
1448 	gchar *uid = NULL;
1449 	GError *error = NULL;
1450 
1451 	g_return_if_fail (E_IS_CAL_MODEL (model));
1452 	g_return_if_fail (E_IS_TABLE_MODEL (source));
1453 
1454 	comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
1455 
1456 	comp_data->client = e_cal_model_get_default_client (model);
1457 	if (comp_data->client)
1458 		g_object_ref (comp_data->client);
1459 
1460 	/* guard against saving before the calendar is open */
1461 	if (!comp_data->client || !e_client_is_opened (E_CLIENT (comp_data->client))) {
1462 		g_object_unref (comp_data);
1463 		return;
1464 	}
1465 
1466 	comp_data->icalcomp = e_cal_model_create_component_with_defaults (model, FALSE);
1467 
1468 	/* set values for our fields */
1469 	set_categories (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CATEGORIES, row));
1470 	set_classification (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CLASSIFICATION, row));
1471 	set_description (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_DESCRIPTION, row));
1472 	set_summary (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_SUMMARY, row));
1473 
1474 	if (e_table_model_value_at (source, E_CAL_MODEL_FIELD_DTSTART, row)) {
1475 		set_dtstart (model, comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_DTSTART, row));
1476 	} else if (model->priv->get_default_time) {
1477 		time_t tt = model->priv->get_default_time (model, model->priv->get_default_time_user_data);
1478 
1479 		if (tt > 0) {
1480 			struct icaltimetype itt = icaltime_from_timet_with_zone (tt, FALSE, e_cal_model_get_timezone (model));
1481 			icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY);
1482 
1483 			if (prop) {
1484 				icalproperty_set_dtstart (prop, itt);
1485 			} else {
1486 				prop = icalproperty_new_dtstart (itt);
1487 				icalcomponent_add_property (comp_data->icalcomp, prop);
1488 			}
1489 		}
1490 	}
1491 
1492 	/* call the class' method for filling the component */
1493 	model_class = (ECalModelClass *) G_OBJECT_GET_CLASS (model);
1494 	if (model_class->fill_component_from_model != NULL) {
1495 		model_class->fill_component_from_model (model, comp_data, source, row);
1496 	}
1497 
1498 	e_cal_client_create_object_sync (
1499 		comp_data->client, comp_data->icalcomp, &uid, NULL, &error);
1500 
1501 	if (error != NULL) {
1502 		g_warning (
1503 			G_STRLOC ": Could not create the object! %s",
1504 			error->message);
1505 
1506 		/* FIXME: show error dialog */
1507 		g_error_free (error);
1508 	} else {
1509 		if (uid)
1510 			icalcomponent_set_uid (comp_data->icalcomp, uid);
1511 
1512 		g_signal_emit (model, signals[ROW_APPENDED], 0);
1513 	}
1514 
1515 	g_free (uid);
1516 	g_object_unref (comp_data);
1517 }
1518 
1519 static gpointer
1520 ecm_duplicate_value (ETableModel *etm,
1521                      gint col,
1522                      gconstpointer value)
1523 {
1524 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1525 
1526 	switch (col) {
1527 	case E_CAL_MODEL_FIELD_CATEGORIES :
1528 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1529 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1530 	case E_CAL_MODEL_FIELD_SUMMARY :
1531 		return g_strdup (value);
1532 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1533 	case E_CAL_MODEL_FIELD_ICON :
1534 	case E_CAL_MODEL_FIELD_COLOR :
1535 		return (gpointer) value;
1536 	case E_CAL_MODEL_FIELD_COMPONENT :
1537 		return icalcomponent_new_clone ((icalcomponent *) value);
1538 	case E_CAL_MODEL_FIELD_DTSTART :
1539 	case E_CAL_MODEL_FIELD_CREATED :
1540 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1541 		if (value) {
1542 			ECellDateEditValue *dv, *orig_dv;
1543 
1544 			orig_dv = (ECellDateEditValue *) value;
1545 			dv = g_new0 (ECellDateEditValue, 1);
1546 			*dv = *orig_dv;
1547 
1548 			return dv;
1549 		}
1550 		break;
1551 	}
1552 
1553 	return NULL;
1554 }
1555 
1556 static void
1557 ecm_free_value (ETableModel *etm,
1558                 gint col,
1559                 gpointer value)
1560 {
1561 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST);
1562 
1563 	switch (col) {
1564 	case E_CAL_MODEL_FIELD_CATEGORIES :
1565 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1566 	case E_CAL_MODEL_FIELD_SUMMARY :
1567 		if (value)
1568 			g_free (value);
1569 		break;
1570 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1571 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1572 	case E_CAL_MODEL_FIELD_ICON :
1573 	case E_CAL_MODEL_FIELD_COLOR :
1574 		break;
1575 	case E_CAL_MODEL_FIELD_DTSTART :
1576 	case E_CAL_MODEL_FIELD_CREATED :
1577 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1578 		if (value)
1579 			g_free (value);
1580 		break;
1581 	case E_CAL_MODEL_FIELD_COMPONENT :
1582 		if (value)
1583 			icalcomponent_free ((icalcomponent *) value);
1584 		break;
1585 	}
1586 }
1587 
1588 static gpointer
1589 ecm_initialize_value (ETableModel *etm,
1590                       gint col)
1591 {
1592 	ECalModelPrivate *priv;
1593 	ECalModel *model = (ECalModel *) etm;
1594 
1595 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1596 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1597 
1598 	priv = model->priv;
1599 
1600 	switch (col) {
1601 	case E_CAL_MODEL_FIELD_CATEGORIES :
1602 		return g_strdup (priv->default_category ? priv->default_category:"");
1603 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1604 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1605 	case E_CAL_MODEL_FIELD_SUMMARY :
1606 		return g_strdup ("");
1607 	case E_CAL_MODEL_FIELD_DTSTART :
1608 	case E_CAL_MODEL_FIELD_CREATED :
1609 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1610 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1611 	case E_CAL_MODEL_FIELD_ICON :
1612 	case E_CAL_MODEL_FIELD_COLOR :
1613 	case E_CAL_MODEL_FIELD_COMPONENT :
1614 		return NULL;
1615 	}
1616 
1617 	return NULL;
1618 }
1619 
1620 static gboolean
1621 ecm_value_is_empty (ETableModel *etm,
1622                     gint col,
1623                     gconstpointer value)
1624 {
1625 	ECalModelPrivate *priv;
1626 	ECalModel *model = (ECalModel *) etm;
1627 
1628 	g_return_val_if_fail (E_IS_CAL_MODEL (model), TRUE);
1629 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, TRUE);
1630 
1631 	priv = model->priv;
1632 
1633 	switch (col) {
1634 	case E_CAL_MODEL_FIELD_CATEGORIES :
1635 		/* This could be a hack or not.  If the categories field only
1636 		 * contains the default category, then it possibly means that
1637 		 * the user has not entered anything at all in the click-to-add;
1638 		 * the category is in the value because we put it there in
1639 		 * ecm_initialize_value().
1640 		 */
1641 		if (priv->default_category && value && strcmp (priv->default_category, value) == 0)
1642 			return TRUE;
1643 		else
1644 			return string_is_empty (value);
1645 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1646 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1647 	case E_CAL_MODEL_FIELD_SUMMARY :
1648 		return string_is_empty (value);
1649 	case E_CAL_MODEL_FIELD_DTSTART :
1650 	case E_CAL_MODEL_FIELD_CREATED :
1651 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1652 		return value ? FALSE : TRUE;
1653 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1654 	case E_CAL_MODEL_FIELD_ICON :
1655 	case E_CAL_MODEL_FIELD_COLOR :
1656 	case E_CAL_MODEL_FIELD_COMPONENT :
1657 		return TRUE;
1658 	}
1659 
1660 	return TRUE;
1661 }
1662 
1663 static gchar *
1664 ecm_value_to_string (ETableModel *etm,
1665                      gint col,
1666                      gconstpointer value)
1667 {
1668 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, g_strdup (""));
1669 
1670 	switch (col) {
1671 	case E_CAL_MODEL_FIELD_CATEGORIES :
1672 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1673 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1674 	case E_CAL_MODEL_FIELD_SUMMARY :
1675 		return g_strdup (value);
1676 	case E_CAL_MODEL_FIELD_DTSTART :
1677 	case E_CAL_MODEL_FIELD_CREATED :
1678 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1679 		return e_cal_model_date_value_to_string (E_CAL_MODEL (etm), value);
1680 	case E_CAL_MODEL_FIELD_ICON :
1681 		if (GPOINTER_TO_INT (value) == 0)
1682 			return g_strdup (_("Normal"));
1683 		else if (GPOINTER_TO_INT (value) == 1)
1684 			return g_strdup (_("Recurring"));
1685 		else
1686 			return g_strdup (_("Assigned"));
1687 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1688 		return g_strdup (value ? _("Yes") : _("No"));
1689 	case E_CAL_MODEL_FIELD_COLOR :
1690 	case E_CAL_MODEL_FIELD_COMPONENT :
1691 		return g_strdup ("");
1692 	}
1693 
1694 	return g_strdup ("");
1695 }
1696 
1697 /* ECalModel class methods */
1698 
1699 typedef struct {
1700 	const gchar *color;
1701 	GList *uids;
1702 } AssignedColorData;
1703 
1704 static const gchar *
1705 ecm_get_color_for_component (ECalModel *model,
1706                              ECalModelComponent *comp_data)
1707 {
1708 	ESource *source;
1709 	ESourceSelectable *extension;
1710 	const gchar *color_spec;
1711 	const gchar *extension_name;
1712 	const gchar *uid;
1713 	gint i, first_empty = 0;
1714 
1715 	static AssignedColorData assigned_colors[] = {
1716 		{ "#BECEDD", NULL }, /* 190 206 221     Blue */
1717 		{ "#E2F0EF", NULL }, /* 226 240 239     Light Blue */
1718 		{ "#C6E2B7", NULL }, /* 198 226 183     Green */
1719 		{ "#E2F0D3", NULL }, /* 226 240 211     Light Green */
1720 		{ "#E2D4B7", NULL }, /* 226 212 183     Khaki */
1721 		{ "#EAEAC1", NULL }, /* 234 234 193     Light Khaki */
1722 		{ "#F0B8B7", NULL }, /* 240 184 183     Pink */
1723 		{ "#FED4D3", NULL }, /* 254 212 211     Light Pink */
1724 		{ "#E2C6E1", NULL }, /* 226 198 225     Purple */
1725 		{ "#F0E2EF", NULL }  /* 240 226 239     Light Purple */
1726 	};
1727 
1728 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1729 
1730 	switch (e_cal_client_get_source_type (comp_data->client)) {
1731 		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
1732 			extension_name = E_SOURCE_EXTENSION_CALENDAR;
1733 			break;
1734 		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
1735 			extension_name = E_SOURCE_EXTENSION_TASK_LIST;
1736 			break;
1737 		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
1738 			extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
1739 			break;
1740 		default:
1741 			g_return_val_if_reached (NULL);
1742 	}
1743 
1744 	source = e_client_get_source (E_CLIENT (comp_data->client));
1745 	extension = e_source_get_extension (source, extension_name);
1746 	color_spec = e_source_selectable_get_color (extension);
1747 
1748 	if (color_spec != NULL) {
1749 		g_free (comp_data->color);
1750 		comp_data->color = g_strdup (color_spec);
1751 		return comp_data->color;
1752 	}
1753 
1754 	uid = e_source_get_uid (source);
1755 
1756 	for (i = 0; i < G_N_ELEMENTS (assigned_colors); i++) {
1757 		GList *l;
1758 
1759 		if (assigned_colors[i].uids == NULL) {
1760 			first_empty = i;
1761 			continue;
1762 		}
1763 
1764 		for (l = assigned_colors[i].uids; l != NULL; l = l->next)
1765 			if (g_strcmp0 (l->data, uid) == 0)
1766 				return assigned_colors[i].color;
1767 	}
1768 
1769 	/* return the first unused color */
1770 	assigned_colors[first_empty].uids = g_list_append (
1771 		assigned_colors[first_empty].uids, g_strdup (uid));
1772 
1773 	return assigned_colors[first_empty].color;
1774 }
1775 
1776 gboolean
1777 e_cal_model_get_confirm_delete (ECalModel *model)
1778 {
1779 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1780 
1781 	return model->priv->confirm_delete;
1782 }
1783 
1784 void
1785 e_cal_model_set_confirm_delete (ECalModel *model,
1786                                 gboolean confirm_delete)
1787 {
1788 	g_return_if_fail (E_IS_CAL_MODEL (model));
1789 
1790 	if (model->priv->confirm_delete == confirm_delete)
1791 		return;
1792 
1793 	model->priv->confirm_delete = confirm_delete;
1794 
1795 	g_object_notify (G_OBJECT (model), "confirm-delete");
1796 }
1797 
1798 icalcomponent_kind
1799 e_cal_model_get_component_kind (ECalModel *model)
1800 {
1801 	g_return_val_if_fail (E_IS_CAL_MODEL (model), ICAL_NO_COMPONENT);
1802 
1803 	return model->priv->kind;
1804 }
1805 
1806 void
1807 e_cal_model_set_component_kind (ECalModel *model,
1808                                 icalcomponent_kind kind)
1809 {
1810 	g_return_if_fail (E_IS_CAL_MODEL (model));
1811 
1812 	model->priv->kind = kind;
1813 }
1814 
1815 ECalModelFlags
1816 e_cal_model_get_flags (ECalModel *model)
1817 {
1818 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
1819 
1820 	return model->priv->flags;
1821 }
1822 
1823 void
1824 e_cal_model_set_flags (ECalModel *model,
1825                        ECalModelFlags flags)
1826 {
1827 	g_return_if_fail (E_IS_CAL_MODEL (model));
1828 
1829 	model->priv->flags = flags;
1830 }
1831 
1832 ESourceRegistry *
1833 e_cal_model_get_registry (ECalModel *model)
1834 {
1835 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1836 
1837 	return model->priv->registry;
1838 }
1839 
1840 icaltimezone *
1841 e_cal_model_get_timezone (ECalModel *model)
1842 {
1843 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1844 
1845 	return model->priv->zone;
1846 }
1847 
1848 void
1849 e_cal_model_set_timezone (ECalModel *model,
1850                           icaltimezone *zone)
1851 {
1852 	icaltimezone *old_zone;
1853 	g_return_if_fail (E_IS_CAL_MODEL (model));
1854 
1855 	if (model->priv->zone == zone)
1856 		return;
1857 
1858 	e_table_model_pre_change (E_TABLE_MODEL (model));
1859 	old_zone = model->priv->zone;
1860 	model->priv->zone = zone;
1861 
1862 	/* the timezone affects the times shown for date fields,
1863 	 * so we need to redisplay everything */
1864 	e_table_model_changed (E_TABLE_MODEL (model));
1865 	redo_queries (model);
1866 
1867 	g_object_notify (G_OBJECT (model), "timezone");
1868 	g_signal_emit (
1869 		model, signals[TIMEZONE_CHANGED], 0,
1870 		old_zone, zone);
1871 }
1872 
1873 gboolean
1874 e_cal_model_get_compress_weekend (ECalModel *model)
1875 {
1876 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1877 
1878 	return model->priv->compress_weekend;
1879 }
1880 
1881 void
1882 e_cal_model_set_compress_weekend (ECalModel *model,
1883                                   gboolean compress_weekend)
1884 {
1885 	g_return_if_fail (E_IS_CAL_MODEL (model));
1886 
1887 	if (model->priv->compress_weekend == compress_weekend)
1888 		return;
1889 
1890 	model->priv->compress_weekend = compress_weekend;
1891 
1892 	g_object_notify (G_OBJECT (model), "compress-weekend");
1893 }
1894 
1895 void
1896 e_cal_model_set_default_category (ECalModel *model,
1897                                   const gchar *default_category)
1898 {
1899 	g_return_if_fail (E_IS_CAL_MODEL (model));
1900 
1901 	g_free (model->priv->default_category);
1902 	model->priv->default_category = g_strdup (default_category);
1903 }
1904 
1905 gint
1906 e_cal_model_get_default_reminder_interval (ECalModel *model)
1907 {
1908 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
1909 
1910 	return model->priv->default_reminder_interval;
1911 }
1912 
1913 void
1914 e_cal_model_set_default_reminder_interval (ECalModel *model,
1915                                            gint default_reminder_interval)
1916 {
1917 	g_return_if_fail (E_IS_CAL_MODEL (model));
1918 
1919 	if (model->priv->default_reminder_interval == default_reminder_interval)
1920 		return;
1921 
1922 	model->priv->default_reminder_interval = default_reminder_interval;
1923 
1924 	g_object_notify (G_OBJECT (model), "default-reminder-interval");
1925 }
1926 
1927 EDurationType
1928 e_cal_model_get_default_reminder_units (ECalModel *model)
1929 {
1930 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
1931 
1932 	return model->priv->default_reminder_units;
1933 }
1934 
1935 void
1936 e_cal_model_set_default_reminder_units (ECalModel *model,
1937                                         EDurationType default_reminder_units)
1938 {
1939 	g_return_if_fail (E_IS_CAL_MODEL (model));
1940 
1941 	if (model->priv->default_reminder_units == default_reminder_units)
1942 		return;
1943 
1944 	model->priv->default_reminder_units = default_reminder_units;
1945 
1946 	g_object_notify (G_OBJECT (model), "default-reminder-units");
1947 }
1948 
1949 gboolean
1950 e_cal_model_get_use_24_hour_format (ECalModel *model)
1951 {
1952 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1953 
1954 	return model->priv->use_24_hour_format;
1955 }
1956 
1957 void
1958 e_cal_model_set_use_24_hour_format (ECalModel *model,
1959                                     gboolean use_24_hour_format)
1960 {
1961 	g_return_if_fail (E_IS_CAL_MODEL (model));
1962 
1963 	if (model->priv->use_24_hour_format == use_24_hour_format)
1964 		return;
1965 
1966 	e_table_model_pre_change (E_TABLE_MODEL (model));
1967 	model->priv->use_24_hour_format = use_24_hour_format;
1968 
1969 	/* Get the views to redraw themselves. */
1970 	e_table_model_changed (E_TABLE_MODEL (model));
1971 
1972 	g_object_notify (G_OBJECT (model), "use-24-hour-format");
1973 }
1974 
1975 gboolean
1976 e_cal_model_get_use_default_reminder (ECalModel *model)
1977 {
1978 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1979 
1980 	return model->priv->use_default_reminder;
1981 }
1982 
1983 void
1984 e_cal_model_set_use_default_reminder (ECalModel *model,
1985                                       gboolean use_default_reminder)
1986 {
1987 	g_return_if_fail (E_IS_CAL_MODEL (model));
1988 
1989 	if (model->priv->use_default_reminder == use_default_reminder)
1990 		return;
1991 
1992 	model->priv->use_default_reminder = use_default_reminder;
1993 
1994 	g_object_notify (G_OBJECT (model), "use-default-reminder");
1995 }
1996 
1997 gint
1998 e_cal_model_get_week_start_day (ECalModel *model)
1999 {
2000 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2001 
2002 	return model->priv->week_start_day;
2003 }
2004 
2005 void
2006 e_cal_model_set_week_start_day (ECalModel *model,
2007                                 gint week_start_day)
2008 {
2009 	g_return_if_fail (E_IS_CAL_MODEL (model));
2010 	g_return_if_fail (week_start_day >= 0);
2011 	g_return_if_fail (week_start_day < 7);
2012 
2013 	if (model->priv->week_start_day == week_start_day)
2014 		return;
2015 
2016 	model->priv->week_start_day = week_start_day;
2017 
2018 	g_object_notify (G_OBJECT (model), "week-start-day");
2019 }
2020 
2021 gint
2022 e_cal_model_get_work_day_end_hour (ECalModel *model)
2023 {
2024 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2025 
2026 	return model->priv->work_day_end_hour;
2027 }
2028 
2029 void
2030 e_cal_model_set_work_day_end_hour (ECalModel *model,
2031                                    gint work_day_end_hour)
2032 {
2033 	g_return_if_fail (E_IS_CAL_MODEL (model));
2034 
2035 	if (model->priv->work_day_end_hour == work_day_end_hour)
2036 		return;
2037 
2038 	model->priv->work_day_end_hour = work_day_end_hour;
2039 
2040 	g_object_notify (G_OBJECT (model), "work-day-end-hour");
2041 }
2042 
2043 gint
2044 e_cal_model_get_work_day_end_minute (ECalModel *model)
2045 {
2046 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2047 
2048 	return model->priv->work_day_end_minute;
2049 }
2050 
2051 void
2052 e_cal_model_set_work_day_end_minute (ECalModel *model,
2053                                    gint work_day_end_minute)
2054 {
2055 	g_return_if_fail (E_IS_CAL_MODEL (model));
2056 
2057 	if (model->priv->work_day_end_minute == work_day_end_minute)
2058 		return;
2059 
2060 	model->priv->work_day_end_minute = work_day_end_minute;
2061 
2062 	g_object_notify (G_OBJECT (model), "work-day-end-minute");
2063 }
2064 
2065 gint
2066 e_cal_model_get_work_day_start_hour (ECalModel *model)
2067 {
2068 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2069 
2070 	return model->priv->work_day_start_hour;
2071 }
2072 
2073 void
2074 e_cal_model_set_work_day_start_hour (ECalModel *model,
2075                                    gint work_day_start_hour)
2076 {
2077 	g_return_if_fail (E_IS_CAL_MODEL (model));
2078 
2079 	if (model->priv->work_day_start_hour == work_day_start_hour)
2080 		return;
2081 
2082 	model->priv->work_day_start_hour = work_day_start_hour;
2083 
2084 	g_object_notify (G_OBJECT (model), "work-day-start-hour");
2085 }
2086 
2087 gint
2088 e_cal_model_get_work_day_start_minute (ECalModel *model)
2089 {
2090 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2091 
2092 	return model->priv->work_day_start_minute;
2093 }
2094 
2095 void
2096 e_cal_model_set_work_day_start_minute (ECalModel *model,
2097                                    gint work_day_start_minute)
2098 {
2099 	g_return_if_fail (E_IS_CAL_MODEL (model));
2100 
2101 	if (model->priv->work_day_start_minute == work_day_start_minute)
2102 		return;
2103 
2104 	model->priv->work_day_start_minute = work_day_start_minute;
2105 
2106 	g_object_notify (G_OBJECT (model), "work-day-start-minute");
2107 }
2108 
2109 ECalClient *
2110 e_cal_model_get_default_client (ECalModel *model)
2111 {
2112 	ECalModelPrivate *priv;
2113 	ECalModelClient *client_data;
2114 
2115 	g_return_val_if_fail (model != NULL, NULL);
2116 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2117 
2118 	priv = model->priv;
2119 
2120 	/* FIXME Should we force the client to be open? */
2121 
2122 	/* we always return a valid ECal, since we rely on it in many places */
2123 	if (priv->default_client)
2124 		return priv->default_client;
2125 
2126 	if (!priv->clients)
2127 		return NULL;
2128 
2129 	client_data = (ECalModelClient *) priv->clients->data;
2130 
2131 	return client_data ? client_data->client : NULL;
2132 }
2133 
2134 void
2135 e_cal_model_set_default_client (ECalModel *model,
2136                                 ECalClient *client)
2137 {
2138 	ECalModelPrivate *priv;
2139 	ECalModelClient *client_data;
2140 
2141 	g_return_if_fail (E_IS_CAL_MODEL (model));
2142 
2143 	if (client != NULL)
2144 		g_return_if_fail (E_IS_CAL_CLIENT (client));
2145 
2146 	priv = model->priv;
2147 
2148 	if (priv->default_client == client)
2149 		return;
2150 
2151 	if (priv->default_client) {
2152 		client_data = find_client_data (model, priv->default_client);
2153 		if (!client_data) {
2154 			g_warning ("client_data is NULL\n");
2155 		} else {
2156 			if (!client_data->do_query)
2157 				remove_client (model, client_data);
2158 		}
2159 	}
2160 
2161 	if (client != NULL) {
2162 		/* Make sure its in the model */
2163 		client_data = add_new_client (model, client, FALSE);
2164 
2165 		/* Store the default client */
2166 		priv->default_client = client_data->client;
2167 	} else
2168 		priv->default_client = NULL;
2169 
2170 	g_object_notify (G_OBJECT (model), "default-client");
2171 }
2172 
2173 GList *
2174 e_cal_model_get_client_list (ECalModel *model)
2175 {
2176 	GList *list = NULL, *l;
2177 	ECalClient *default_client;
2178 
2179 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2180 
2181 	default_client = model->priv->default_client;
2182 
2183 	for (l = model->priv->clients; l != NULL; l = l->next) {
2184 		ECalModelClient *client_data = (ECalModelClient *) l->data;
2185 
2186 		/* Exclude the default client if we're not querying it. */
2187 		if (client_data->client == default_client && !client_data->do_query)
2188 			continue;
2189 
2190 		list = g_list_append (list, client_data->client);
2191 	}
2192 
2193 	return list;
2194 }
2195 
2196 /**
2197  * e_cal_model_get_client_for_source:
2198  * @model: an #ECalModel
2199  * @source: an #ESource
2200  */
2201 ECalClient *
2202 e_cal_model_get_client_for_source (ECalModel *model,
2203                                    ESource *source)
2204 {
2205 	GList *link;
2206 
2207 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2208 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2209 
2210 	for (link = model->priv->clients; link != NULL; link = link->next) {
2211 		ECalModelClient *client_data;
2212 		ESource *client_source;
2213 		EClient *client;
2214 
2215 		client_data = (ECalModelClient *) link->data;
2216 		client = E_CLIENT (client_data->client);
2217 		client_source = e_client_get_source (client);
2218 
2219 		if (e_source_equal (source, client_source))
2220 			return client_data->client;
2221 	}
2222 
2223 	return NULL;
2224 }
2225 
2226 static ECalModelClient *
2227 find_client_data (ECalModel *model,
2228                   ECalClient *client)
2229 {
2230 	ECalModelPrivate *priv;
2231 	GList *l;
2232 
2233 	priv = model->priv;
2234 
2235 	for (l = priv->clients; l != NULL; l = l->next) {
2236 		ECalModelClient *client_data = (ECalModelClient *) l->data;
2237 
2238 		if (client_data->client == client)
2239 			return client_data;
2240 	}
2241 
2242 	return NULL;
2243 }
2244 
2245 static ECalModelComponent *
2246 search_by_id_and_client (ECalModelPrivate *priv,
2247                          ECalClient *client,
2248                          const ECalComponentId *id)
2249 {
2250 	gint i;
2251 
2252 	for (i = 0; i < priv->objects->len; i++) {
2253 		ECalModelComponent *comp_data = g_ptr_array_index (priv->objects, i);
2254 
2255 		if (comp_data) {
2256 			const gchar *uid;
2257 			gchar *rid = NULL;
2258 			struct icaltimetype icalrid;
2259 			gboolean has_rid = (id->rid && *id->rid);
2260 
2261 			uid = icalcomponent_get_uid (comp_data->icalcomp);
2262 			icalrid = icalcomponent_get_recurrenceid (comp_data->icalcomp);
2263 			if (!icaltime_is_null_time (icalrid))
2264 				rid = icaltime_as_ical_string_r (icalrid);
2265 
2266 			if (uid && *uid) {
2267 				if ((!client || comp_data->client == client) && !strcmp (id->uid, uid)) {
2268 					if (has_rid) {
2269 						if (!(rid && *rid && !strcmp (rid, id->rid))) {
2270 							g_free (rid);
2271 							continue;
2272 						}
2273 					}
2274 					g_free (rid);
2275 					return comp_data;
2276 				}
2277 			}
2278 
2279 			g_free (rid);
2280 		}
2281 	}
2282 
2283 	return NULL;
2284 }
2285 
2286 static void
2287 remove_all_for_id_and_client (ECalModel *model,
2288                               ECalClient *client,
2289                               const ECalComponentId *id)
2290 {
2291 	ECalModelComponent *comp_data;
2292 
2293 	while ((comp_data = search_by_id_and_client (model->priv, client, id))) {
2294 		gint pos;
2295 		GSList *list = NULL;
2296 
2297 		pos = get_position_in_array (model->priv->objects, comp_data);
2298 
2299 		if (!g_ptr_array_remove (model->priv->objects, comp_data))
2300 			continue;
2301 
2302 		list = g_slist_append (list, comp_data);
2303 		g_signal_emit (model, signals[COMPS_DELETED], 0, list);
2304 
2305 		g_slist_free (list);
2306 		g_object_unref (comp_data);
2307 
2308 		e_table_model_pre_change (E_TABLE_MODEL (model));
2309 		e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
2310 	}
2311 }
2312 
2313 typedef struct {
2314 	ECalClient *client;
2315 	ECalClientView *view;
2316 	ECalModel *model;
2317 	icalcomponent *icalcomp;
2318 } RecurrenceExpansionData;
2319 
2320 static void
2321 free_rdata (gpointer data)
2322 {
2323 	RecurrenceExpansionData *rdata = data;
2324 
2325 	if (!rdata)
2326 		return;
2327 
2328 	g_object_unref (rdata->client);
2329 	g_object_unref (rdata->view);
2330 	g_object_unref (rdata->model);
2331 	g_free (rdata);
2332 }
2333 
2334 static gboolean
2335 add_instance_cb (ECalComponent *comp,
2336                  time_t instance_start,
2337                  time_t instance_end,
2338                  gpointer user_data)
2339 {
2340 	ECalModelComponent *comp_data;
2341 	ECalModelPrivate *priv;
2342 	RecurrenceExpansionData *rdata = user_data;
2343 	icaltimetype time;
2344 	ECalComponentDateTime datetime, to_set;
2345 	icaltimezone *zone = NULL;
2346 	ECalComponentId *id;
2347 
2348 	g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), TRUE);
2349 
2350 	priv = rdata->model->priv;
2351 
2352 	id = e_cal_component_get_id (comp);
2353 	remove_all_for_id_and_client (rdata->model, rdata->client, id);
2354 	e_cal_component_free_id (id);
2355 
2356 	e_table_model_pre_change (E_TABLE_MODEL (rdata->model));
2357 
2358 	/* set the right instance start date to component */
2359 	e_cal_component_get_dtstart (comp, &datetime);
2360 	if (datetime.tzid)
2361 		e_cal_client_get_timezone_sync (rdata->client, datetime.tzid, &zone, NULL, NULL);
2362 	time = icaltime_from_timet_with_zone (instance_start, FALSE, zone ? zone : priv->zone);
2363 	to_set.value = &time;
2364 	to_set.tzid = datetime.tzid;
2365 	e_cal_component_set_dtstart (comp, &to_set);
2366 	e_cal_component_free_datetime (&datetime);
2367 
2368 	/* set the right instance end date to component*/
2369 	e_cal_component_get_dtend (comp, &datetime);
2370 	zone = NULL;
2371 	if (datetime.tzid)
2372 		e_cal_client_get_timezone_sync (rdata->client, datetime.tzid, &zone, NULL, NULL);
2373 	time = icaltime_from_timet_with_zone (instance_end, FALSE, zone ? zone : priv->zone);
2374 	to_set.value = &time;
2375 	to_set.tzid = datetime.tzid;
2376 	e_cal_component_set_dtend (comp, &to_set);
2377 	e_cal_component_free_datetime (&datetime);
2378 
2379 	comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
2380 	comp_data->client = g_object_ref (rdata->client);
2381 	comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2382 	comp_data->instance_start = instance_start;
2383 	comp_data->instance_end = instance_end;
2384 
2385 	g_ptr_array_add (priv->objects, comp_data);
2386 	e_table_model_row_inserted (E_TABLE_MODEL (rdata->model), priv->objects->len - 1);
2387 
2388 	return TRUE;
2389 }
2390 
2391 /* We do this check since the calendar items are downloaded from the server
2392  * in the open_method, since the default timezone might not be set there. */
2393 static void
2394 ensure_dates_are_in_default_zone (ECalModel *model,
2395                                   icalcomponent *icalcomp)
2396 {
2397 	icaltimetype dt;
2398 	icaltimezone *zone;
2399 
2400 	zone = e_cal_model_get_timezone (model);
2401 	if (!zone)
2402 		return;
2403 
2404 	dt = icalcomponent_get_dtstart (icalcomp);
2405 	if (dt.is_utc) {
2406 		dt = icaltime_convert_to_zone (dt, zone);
2407 		icalcomponent_set_dtstart (icalcomp, dt);
2408 	}
2409 
2410 	dt = icalcomponent_get_dtend (icalcomp);
2411 	if (dt.is_utc) {
2412 		dt = icaltime_convert_to_zone (dt, zone);
2413 		icalcomponent_set_dtend (icalcomp, dt);
2414 	}
2415 }
2416 
2417 static gint
2418 place_master_object_first_cb (gconstpointer p1,
2419                               gconstpointer p2)
2420 {
2421 	icalcomponent *c1 = (icalcomponent *) p1, *c2 = (icalcomponent *) p2;
2422 	const gchar *uid1, *uid2;
2423 	gint res;
2424 
2425 	g_return_val_if_fail (c1 != NULL, 0);
2426 	g_return_val_if_fail (c2 != NULL, 0);
2427 
2428 	uid1 = icalcomponent_get_uid (c1);
2429 	uid2 = icalcomponent_get_uid (c2);
2430 
2431 	res = g_strcmp0 (uid1, uid2);
2432 	if (res == 0) {
2433 		struct icaltimetype rid1, rid2;
2434 
2435 		rid1 = icalcomponent_get_recurrenceid (c1);
2436 		rid2 = icalcomponent_get_recurrenceid (c2);
2437 
2438 		if (icaltime_is_null_time (rid1)) {
2439 			if (!icaltime_is_null_time (rid2))
2440 				res = -1;
2441 		} else if (icaltime_is_null_time (rid2)) {
2442 			res = 1;
2443 		} else {
2444 			res = icaltime_compare (rid1, rid2);
2445 		}
2446 	}
2447 
2448 	return res;
2449 }
2450 
2451 static void client_view_objects_added_cb (ECalClientView *view, const GSList *objects, ECalModel *model);
2452 
2453 static void
2454 process_added (ECalClientView *view,
2455                const GSList *objects,
2456                ECalModel *model)
2457 {
2458 	ECalModelPrivate *priv;
2459 	const GSList *l;
2460 	GSList *copy;
2461 
2462 	priv = model->priv;
2463 
2464 	/* order matters, process master object first, then detached instances */
2465 	copy = g_slist_sort (g_slist_copy ((GSList *) objects), place_master_object_first_cb);
2466 
2467 	for (l = copy; l; l = l->next) {
2468 		ECalModelComponent *comp_data;
2469 		ECalComponentId *id;
2470 		ECalComponent *comp = e_cal_component_new ();
2471 		ECalClient *client = e_cal_client_view_get_client (view);
2472 
2473 		/* This will fail for alarm or VCalendar component */
2474 		if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
2475 			g_object_unref (comp);
2476 			continue;
2477 		}
2478 
2479 		id = e_cal_component_get_id (comp);
2480 
2481 		/* remove the components if they are already present and re-add them */
2482 		remove_all_for_id_and_client (model, client, id);
2483 
2484 		e_cal_component_free_id (id);
2485 		g_object_unref (comp);
2486 		ensure_dates_are_in_default_zone (model, l->data);
2487 
2488 		if (e_cal_util_component_has_recurrences (l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) {
2489 			ECalModelClient *client_data = find_client_data (model, client);
2490 
2491 			if (client_data) {
2492 				RecurrenceExpansionData *rdata = g_new0 (RecurrenceExpansionData, 1);
2493 				rdata->client = g_object_ref (client);
2494 				rdata->view = g_object_ref (view);
2495 				rdata->model = g_object_ref (model);
2496 
2497 				e_cal_client_generate_instances_for_object (rdata->client, l->data, priv->start, priv->end, client_data->cancellable,
2498 									    (ECalRecurInstanceFn) add_instance_cb, rdata, free_rdata);
2499 			}
2500 		} else {
2501 			e_table_model_pre_change (E_TABLE_MODEL (model));
2502 
2503 			comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
2504 			comp_data->client = g_object_ref (client);
2505 			comp_data->icalcomp = icalcomponent_new_clone (l->data);
2506 			e_cal_model_set_instance_times (comp_data, priv->zone);
2507 
2508 			g_ptr_array_add (priv->objects, comp_data);
2509 			e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1);
2510 		}
2511 	}
2512 
2513 	g_slist_free (copy);
2514 }
2515 
2516 static void
2517 process_modified (ECalClientView *view,
2518                   const GSList *objects,
2519                   ECalModel *model)
2520 {
2521 	ECalModelPrivate *priv;
2522 	const GSList *l;
2523 	GSList *list = NULL;
2524 
2525 	priv = model->priv;
2526 
2527 	/*  re-add only the recurrence objects */
2528 	for (l = objects; l != NULL; l = g_slist_next (l)) {
2529 		if (!e_cal_util_component_is_instance (l->data) && e_cal_util_component_has_recurrences (l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES))
2530 			list = g_slist_prepend (list, l->data);
2531 		else {
2532 			gint pos;
2533 			ECalModelComponent *comp_data;
2534 			ECalComponentId *id;
2535 			ECalComponent *comp = e_cal_component_new ();
2536 			ECalClient *client = e_cal_client_view_get_client (view);
2537 
2538 			if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
2539 				g_object_unref (comp);
2540 				continue;
2541 			}
2542 
2543 			e_table_model_pre_change (E_TABLE_MODEL (model));
2544 
2545 			id = e_cal_component_get_id (comp);
2546 
2547 			comp_data = search_by_id_and_client (priv, client, id);
2548 
2549 			e_cal_component_free_id (id);
2550 			g_object_unref (comp);
2551 
2552 			if (!comp_data) {
2553 				/* the modified component is not in the model yet, just skip it */
2554 				continue;
2555 			}
2556 
2557 			if (comp_data->icalcomp)
2558 				icalcomponent_free (comp_data->icalcomp);
2559 			if (comp_data->dtstart) {
2560 				g_free (comp_data->dtstart);
2561 				comp_data->dtstart = NULL;
2562 			}
2563 			if (comp_data->dtend) {
2564 				g_free (comp_data->dtend);
2565 				comp_data->dtend = NULL;
2566 			}
2567 			if (comp_data->due) {
2568 				g_free (comp_data->due);
2569 				comp_data->due = NULL;
2570 			}
2571 			if (comp_data->completed) {
2572 				g_free (comp_data->completed);
2573 				comp_data->completed = NULL;
2574 			}
2575 			if (comp_data->created) {
2576 				g_free (comp_data->created);
2577 				comp_data->created = NULL;
2578 			}
2579 			if (comp_data->lastmodified) {
2580 				g_free (comp_data->lastmodified);
2581 				comp_data->lastmodified = NULL;
2582 			}
2583 			if (comp_data->color) {
2584 				g_free (comp_data->color);
2585 				comp_data->color = NULL;
2586 			}
2587 
2588 			comp_data->icalcomp = icalcomponent_new_clone (l->data);
2589 			e_cal_model_set_instance_times (comp_data, priv->zone);
2590 
2591 			pos = get_position_in_array (priv->objects, comp_data);
2592 
2593 			e_table_model_row_changed (E_TABLE_MODEL (model), pos);
2594 		}
2595 	}
2596 
2597 	client_view_objects_added_cb (view, list, model);
2598 	g_slist_free (list);
2599 }
2600 
2601 static void
2602 process_removed (ECalClientView *view,
2603                  const GSList *ids,
2604                  ECalModel *model)
2605 {
2606 	ECalModelPrivate *priv;
2607 	const GSList *l;
2608 
2609 	priv = model->priv;
2610 
2611 	for (l = ids; l; l = l->next) {
2612 		ECalModelComponent *comp_data = NULL;
2613 		ECalComponentId *id = l->data;
2614 		gint pos;
2615 
2616 		/* make sure we remove all objects with this UID */
2617 		while ((comp_data = search_by_id_and_client (priv, e_cal_client_view_get_client (view), id))) {
2618 			GSList *l = NULL;
2619 
2620 			pos = get_position_in_array (priv->objects, comp_data);
2621 
2622 			if (!g_ptr_array_remove (priv->objects, comp_data))
2623 				continue;
2624 
2625 			l = g_slist_append (l, comp_data);
2626 			g_signal_emit (model, signals[COMPS_DELETED], 0, l);
2627 
2628 			g_slist_free (l);
2629 			g_object_unref (comp_data);
2630 
2631 			e_table_model_pre_change (E_TABLE_MODEL (model));
2632 			e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
2633 		}
2634 	}
2635 
2636 	/* to notify about changes, because in call of row_deleted there are still all events */
2637 	e_table_model_changed (E_TABLE_MODEL (model));
2638 }
2639 
2640 static gpointer
2641 copy_comp_id (gpointer id)
2642 {
2643 	ECalComponentId *comp_id = (ECalComponentId *) id, *copy;
2644 
2645 	g_return_val_if_fail (comp_id != NULL, NULL);
2646 
2647 	copy = g_new0 (ECalComponentId, 1);
2648 	copy->uid = g_strdup (comp_id->uid);
2649 	copy->rid = g_strdup (comp_id->rid);
2650 
2651 	return copy;
2652 }
2653 
2654 static void
2655 free_comp_id (gpointer id)
2656 {
2657 	ECalComponentId *comp_id = (ECalComponentId *) id;
2658 
2659 	g_return_if_fail (comp_id != NULL);
2660 
2661 	g_free (comp_id->uid);
2662 	g_free (comp_id->rid);
2663 	g_free (comp_id);
2664 }
2665 
2666 static void
2667 process_event (ECalClientView *view,
2668                const GSList *objects,
2669                ECalModel *model,
2670                void (*process_fn) (ECalClientView *view,
2671                                    const GSList *objects,
2672                                    ECalModel *model),
2673                gboolean *in,
2674                GHashTable *save_hash,
2675                gpointer (*copy_fn) (gpointer data),
2676                void (*free_fn) (gpointer data))
2677 {
2678 	gboolean skip = FALSE;
2679 	const GSList *l;
2680 
2681 	g_return_if_fail (save_hash != NULL);
2682 
2683 	g_mutex_lock (model->priv->notify_lock);
2684 	if (*in) {
2685 		GSList *save_list = g_hash_table_lookup (save_hash, view);
2686 
2687 		skip = TRUE;
2688 		for (l = objects; l; l = l->next) {
2689 			if (l->data)
2690 				save_list = g_slist_append (save_list, copy_fn (l->data));
2691 		}
2692 
2693 		g_hash_table_insert (save_hash, g_object_ref (view), save_list);
2694 	} else {
2695 		*in = TRUE;
2696 	}
2697 
2698 	g_mutex_unlock (model->priv->notify_lock);
2699 
2700 	if (skip)
2701 		return;
2702 
2703 	/* do it */
2704 	process_fn (view, objects, model);
2705 
2706 	g_mutex_lock (model->priv->notify_lock);
2707 	while (g_hash_table_size (save_hash)) {
2708 		gpointer key = NULL, value = NULL;
2709 		GHashTableIter iter;
2710 		GSList *save_list;
2711 
2712 		g_hash_table_iter_init (&iter, save_hash);
2713 		if (!g_hash_table_iter_next (&iter, &key, &value)) {
2714 			g_debug ("%s: Failed to get first item of the save_hash", G_STRFUNC);
2715 			break;
2716 		}
2717 
2718 		save_list = value;
2719 		view = g_object_ref (key);
2720 
2721 		g_hash_table_remove (save_hash, view);
2722 
2723 		g_mutex_unlock (model->priv->notify_lock);
2724 
2725 		/* do it */
2726 		process_fn (view, save_list, model);
2727 
2728 		for (l = save_list; l; l = l->next) {
2729 			if (l->data) {
2730 				free_fn (l->data);
2731 			}
2732 		}
2733 		g_slist_free (save_list);
2734 		g_object_unref (view);
2735 
2736 		g_mutex_lock (model->priv->notify_lock);
2737 	}
2738 
2739 	*in = FALSE;
2740 	g_mutex_unlock (model->priv->notify_lock);
2741 }
2742 
2743 static void
2744 client_view_objects_added_cb (ECalClientView *view,
2745                               const GSList *objects,
2746                               ECalModel *model)
2747 {
2748 	process_event (
2749 		view, objects, model, process_added,
2750 		&model->priv->in_added,
2751 		model->priv->notify_added,
2752 		(gpointer (*)(gpointer)) icalcomponent_new_clone,
2753 		(void (*)(gpointer)) icalcomponent_free);
2754 }
2755 
2756 static void
2757 client_view_objects_modified_cb (ECalClientView *view,
2758                                  const GSList *objects,
2759                                  ECalModel *model)
2760 {
2761 	process_event (
2762 		view, objects, model, process_modified,
2763 		&model->priv->in_modified,
2764 		model->priv->notify_modified,
2765 		(gpointer (*)(gpointer)) icalcomponent_new_clone,
2766 		(void (*)(gpointer)) icalcomponent_free);
2767 }
2768 
2769 static void
2770 client_view_objects_removed_cb (ECalClientView *view,
2771                                 const GSList *ids,
2772                                 ECalModel *model)
2773 {
2774 	process_event (
2775 		view, ids, model, process_removed,
2776 		&model->priv->in_removed,
2777 		model->priv->notify_removed,
2778 		copy_comp_id, free_comp_id);
2779 }
2780 
2781 static void
2782 client_view_progress_cb (ECalClientView *view,
2783                          gint percent,
2784                          const gchar *message,
2785                          gpointer user_data)
2786 {
2787 	ECalModel *model = (ECalModel *) user_data;
2788 	ECalClient *client = e_cal_client_view_get_client (view);
2789 
2790 	g_return_if_fail (E_IS_CAL_MODEL (model));
2791 
2792 	g_signal_emit (
2793 		model, signals[CAL_VIEW_PROGRESS], 0, message,
2794 		percent, e_cal_client_get_source_type (client));
2795 }
2796 
2797 static void
2798 client_view_complete_cb (ECalClientView *view,
2799                          const GError *error,
2800                          gpointer user_data)
2801 {
2802 	ECalModel *model = (ECalModel *) user_data;
2803 	ECalClient *client = e_cal_client_view_get_client (view);
2804 
2805 	g_return_if_fail (E_IS_CAL_MODEL (model));
2806 
2807 	g_signal_emit (
2808 		model, signals[CAL_VIEW_COMPLETE], 0, error,
2809 		e_cal_client_get_source_type (client));
2810 }
2811 
2812 struct get_view_data
2813 {
2814 	ECalModel *model; /* do not touch this, if cancelled */
2815 	ECalModelClient *client_data; /* do not touch this, if cancelled */
2816 	GCancellable *cancellable;
2817 	guint tries;
2818 };
2819 
2820 static void
2821 free_get_view_data (struct get_view_data *gvd)
2822 {
2823 	if (!gvd)
2824 		return;
2825 
2826 	g_object_unref (gvd->cancellable);
2827 	g_free (gvd);
2828 }
2829 
2830 static gboolean retry_get_view_timeout_cb (gpointer user_data);
2831 
2832 static void
2833 get_view_cb (GObject *source_object,
2834              GAsyncResult *result,
2835              gpointer user_data)
2836 {
2837 	struct get_view_data *gvd = user_data;
2838 	GError *error = NULL;
2839 	ECalClientView *view = NULL;
2840 
2841 	g_return_if_fail (source_object != NULL);
2842 	g_return_if_fail (result != NULL);
2843 	g_return_if_fail (gvd != NULL);
2844 	g_return_if_fail (gvd->model != NULL);
2845 	g_return_if_fail (gvd->client_data != NULL);
2846 
2847 	e_cal_client_get_view_finish (
2848 		E_CAL_CLIENT (source_object), result, &view, &error);
2849 
2850 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2851 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2852 		free_get_view_data (gvd);
2853 		g_error_free (error);
2854 		return;
2855 	}
2856 
2857 	if (error != NULL) {
2858 		if (gvd->tries < 10) {
2859 			gvd->tries++;
2860 			g_timeout_add (500, retry_get_view_timeout_cb, gvd);
2861 			g_error_free (error);
2862 			return;
2863 		}
2864 
2865 		g_warning (
2866 			"%s: Failed to get view: %s",
2867 			G_STRFUNC, error->message);
2868 		g_error_free (error);
2869 
2870 	} else {
2871 		gvd->client_data->view = view;
2872 
2873 		g_signal_connect (
2874 			gvd->client_data->view, "objects-added",
2875 			G_CALLBACK (client_view_objects_added_cb), gvd->model);
2876 		g_signal_connect (
2877 			gvd->client_data->view, "objects-modified",
2878 			G_CALLBACK (client_view_objects_modified_cb), gvd->model);
2879 		g_signal_connect (
2880 			gvd->client_data->view, "objects-removed",
2881 			G_CALLBACK (client_view_objects_removed_cb), gvd->model);
2882 		g_signal_connect (
2883 			gvd->client_data->view, "progress",
2884 			G_CALLBACK (client_view_progress_cb), gvd->model);
2885 		g_signal_connect (
2886 			gvd->client_data->view, "complete",
2887 			G_CALLBACK (client_view_complete_cb), gvd->model);
2888 
2889 		e_cal_client_view_start (gvd->client_data->view, &error);
2890 
2891 		if (error != NULL) {
2892 			g_warning (
2893 				"%s: Failed to start view: %s",
2894 				G_STRFUNC, error->message);
2895 			g_error_free (error);
2896 		}
2897 	}
2898 
2899 	free_get_view_data (gvd);
2900 }
2901 
2902 static gboolean
2903 retry_get_view_timeout_cb (gpointer user_data)
2904 {
2905 	struct get_view_data *gvd = user_data;
2906 
2907 	if (g_cancellable_is_cancelled (gvd->cancellable)) {
2908 		free_get_view_data (gvd);
2909 		return FALSE;
2910 	}
2911 
2912 	e_cal_client_get_view (gvd->client_data->client, gvd->model->priv->full_sexp, gvd->cancellable, get_view_cb, gvd);
2913 
2914 	return FALSE;
2915 }
2916 
2917 static void
2918 update_e_cal_view_for_client (ECalModel *model,
2919                               ECalModelClient *client_data)
2920 {
2921 	ECalModelPrivate *priv;
2922 	struct get_view_data *gvd;
2923 
2924 	priv = model->priv;
2925 
2926 	/* Skip if this client has not finished loading yet */
2927 	if (!e_client_is_opened (E_CLIENT (client_data->client)))
2928 		return;
2929 
2930 	/* free the previous view, if any */
2931 	if (client_data->view) {
2932 		g_signal_handlers_disconnect_matched (
2933 			client_data->view, G_SIGNAL_MATCH_DATA,
2934 			0, 0, NULL, NULL, model);
2935 		g_object_unref (client_data->view);
2936 		client_data->view = NULL;
2937 	}
2938 
2939 	/* prepare the view */
2940 	g_return_if_fail (priv->full_sexp != NULL);
2941 
2942 	/* Don't create the new query if we won't use it */
2943 	if (!client_data->do_query)
2944 		return;
2945 
2946 	if (client_data->cancellable) {
2947 		g_cancellable_cancel (client_data->cancellable);
2948 		g_object_unref (client_data->cancellable);
2949 	}
2950 
2951 	client_data->cancellable = g_cancellable_new ();
2952 
2953 	gvd = g_new0 (struct get_view_data, 1);
2954 	gvd->client_data = client_data;
2955 	gvd->model = model;
2956 	gvd->tries = 0;
2957 	gvd->cancellable = g_object_ref (client_data->cancellable);
2958 
2959 	e_cal_client_get_view (client_data->client, priv->full_sexp, gvd->cancellable, get_view_cb, gvd);
2960 }
2961 
2962 void
2963 e_cal_model_update_status_message (ECalModel *model,
2964                                    const gchar *message,
2965                                    gdouble percent)
2966 {
2967 	g_return_if_fail (model != NULL);
2968 
2969 	g_signal_emit (model, signals[STATUS_MESSAGE], 0, message, percent);
2970 }
2971 
2972 static void
2973 backend_died_cb (ECalClient *client,
2974                  gpointer user_data)
2975 {
2976 	ECalModel *model;
2977 
2978 	model = E_CAL_MODEL (user_data);
2979 
2980 	e_cal_model_remove_client (model, client);
2981 }
2982 
2983 static void
2984 cal_model_retrieve_capabilies_cb (GObject *source_object,
2985                                   GAsyncResult *result,
2986                                   gpointer user_data)
2987 {
2988 	ECalClient *client = E_CAL_CLIENT (source_object);
2989 	ECalModel *model = user_data;
2990 	ECalModelClient *client_data;
2991 	gchar *capabilities = NULL;
2992 
2993 	g_return_if_fail (client != NULL);
2994 	g_return_if_fail (model != NULL);
2995 
2996 	e_client_retrieve_capabilities_finish (
2997 		E_CLIENT (client), result, &capabilities, NULL);
2998 	g_free (capabilities);
2999 
3000 	e_cal_model_update_status_message (model, NULL, -1.0);
3001 
3002 	client_data = find_client_data (model, client);
3003 	g_return_if_fail (client_data);
3004 
3005 	update_e_cal_view_for_client (model, client_data);
3006 }
3007 
3008 struct RetryOpenData
3009 {
3010 	EClient *client;
3011 	ECalModel *model;
3012 	GCancellable *cancellable;
3013 };
3014 
3015 static void
3016 free_retry_open_data (gpointer data)
3017 {
3018 	struct RetryOpenData *rod = data;
3019 
3020 	if (!rod)
3021 		return;
3022 
3023 	g_object_unref (rod->client);
3024 	g_object_unref (rod->cancellable);
3025 	g_free (rod);
3026 }
3027 
3028 static gboolean cal_model_retry_open_timeout_cb (gpointer user_data);
3029 
3030 static void
3031 client_opened_cb (GObject *source_object,
3032                   GAsyncResult *result,
3033                   gpointer user_data)
3034 {
3035 	ECalClient *client = E_CAL_CLIENT (source_object);
3036 	ECalModel *model = (ECalModel *) user_data;
3037 	GError *error = NULL;
3038 
3039 	e_client_open_finish (E_CLIENT (client), result, &error);
3040 
3041 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
3042 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
3043 		g_error_free (error);
3044 		return;
3045 	}
3046 
3047 	if (error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
3048 		struct RetryOpenData *rod;
3049 
3050 		rod = g_new0 (struct RetryOpenData, 1);
3051 		rod->client = g_object_ref (client);
3052 		rod->model = model;
3053 		rod->cancellable = g_object_ref (model->priv->loading_clients);
3054 
3055 		/* postpone for 1/2 of a second, backend is busy now */
3056 		g_timeout_add_full (
3057 			G_PRIORITY_DEFAULT, 500,
3058 			cal_model_retry_open_timeout_cb,
3059 			rod, free_retry_open_data);
3060 
3061 		g_error_free (error);
3062 
3063 		return;
3064 	}
3065 
3066 	if (error != NULL) {
3067 		ESource *source;
3068 
3069 		source = e_client_get_source (E_CLIENT (client));
3070 		e_cal_model_remove_client (model, client);
3071 		g_warning (
3072 			"%s: Failed to open '%s': %s",
3073 			G_STRFUNC,
3074 			e_source_get_display_name (source),
3075 			error->message);
3076 		g_error_free (error);
3077 		e_cal_model_update_status_message (model, NULL, -1.0);
3078 		return;
3079 	}
3080 
3081 	/* to have them ready for later use */
3082 	e_client_retrieve_capabilities (
3083 		E_CLIENT (client), model->priv->loading_clients,
3084 		cal_model_retrieve_capabilies_cb, model);
3085 }
3086 
3087 static gboolean
3088 cal_model_retry_open_timeout_cb (gpointer user_data)
3089 {
3090 	struct RetryOpenData *rod = user_data;
3091 
3092 	g_return_val_if_fail (rod != NULL, FALSE);
3093 	g_return_val_if_fail (rod->client != NULL, FALSE);
3094 	g_return_val_if_fail (rod->model != NULL, FALSE);
3095 
3096 	e_client_open (
3097 		rod->client, TRUE, rod->cancellable,
3098 		client_opened_cb, rod->model);
3099 
3100 	return FALSE;
3101 }
3102 
3103 static ECalModelClient *
3104 add_new_client (ECalModel *model,
3105                 ECalClient *client,
3106                 gboolean do_query)
3107 {
3108 	ECalModelPrivate *priv;
3109 	ECalModelClient *client_data;
3110 
3111 	priv = model->priv;
3112 
3113 	/* DEBUG the load state should always be loaded here
3114 	if (e_cal_get_load_state (client) != E_CAL_LOAD_LOADED) {
3115 		g_assert_not_reached ();
3116 	} */
3117 
3118 	/* Look to see if we already have this client */
3119 	client_data = find_client_data (model, client);
3120 	if (client_data) {
3121 		if (client_data->do_query)
3122 			return client_data;
3123 		else
3124 			client_data->do_query = do_query;
3125 
3126 		goto load;
3127 	}
3128 
3129 	client_data = g_new0 (ECalModelClient, 1);
3130 	client_data->client = g_object_ref (client);
3131 	client_data->view = NULL;
3132 	client_data->do_query = do_query;
3133 
3134 	priv->clients = g_list_append (priv->clients, client_data);
3135 
3136 	g_signal_connect (
3137 		client_data->client, "backend_died",
3138 		G_CALLBACK (backend_died_cb), model);
3139 
3140  load:
3141 	if (e_client_is_opened (E_CLIENT (client))) {
3142 		update_e_cal_view_for_client (model, client_data);
3143 	} else {
3144 		ESource *source;
3145 		const gchar *display_name;
3146 		gchar *msg;
3147 
3148 		source = e_client_get_source (E_CLIENT (client));
3149 		display_name = e_source_get_display_name (source);
3150 		msg = g_strdup_printf (_("Opening %s"), display_name);
3151 		e_cal_model_update_status_message (model, msg, -1.0);
3152 		g_free (msg);
3153 
3154 		e_cal_client_set_default_timezone (client, e_cal_model_get_timezone (model));
3155 
3156 		e_client_open (E_CLIENT (client), TRUE, model->priv->loading_clients, client_opened_cb, model);
3157 	}
3158 
3159 	return client_data;
3160 }
3161 
3162 /**
3163  * e_cal_model_add_client
3164  */
3165 void
3166 e_cal_model_add_client (ECalModel *model,
3167                         ECalClient *client)
3168 {
3169 	g_return_if_fail (E_IS_CAL_MODEL (model));
3170 	g_return_if_fail (E_IS_CAL_CLIENT (client));
3171 
3172 	add_new_client (model, client, TRUE);
3173 }
3174 
3175 static void
3176 remove_client_objects (ECalModel *model,
3177                        ECalModelClient *client_data)
3178 {
3179 	gint i;
3180 
3181 	/* remove all objects belonging to this client */
3182 	for (i = model->priv->objects->len; i > 0; i--) {
3183 		ECalModelComponent *comp_data = (ECalModelComponent *) g_ptr_array_index (model->priv->objects, i - 1);
3184 
3185 		g_return_if_fail (comp_data != NULL);
3186 
3187 		if (comp_data->client == client_data->client) {
3188 			GSList *l = NULL;
3189 
3190 			g_ptr_array_remove (model->priv->objects, comp_data);
3191 
3192 			l = g_slist_append (l, comp_data);
3193 			g_signal_emit (model, signals[COMPS_DELETED], 0, l);
3194 
3195 			g_slist_free (l);
3196 			g_object_unref (comp_data);
3197 
3198 			e_table_model_pre_change (E_TABLE_MODEL (model));
3199 			e_table_model_row_deleted (E_TABLE_MODEL (model), i - 1);
3200 		}
3201 	}
3202 
3203 	/* to notify about changes, because in call of row_deleted there are still all events */
3204 	e_table_model_changed (E_TABLE_MODEL (model));
3205 }
3206 
3207 static void
3208 remove_client (ECalModel *model,
3209                ECalModelClient *client_data)
3210 {
3211 	/* FIXME We might not want to disconnect the open signal for the default client */
3212 	g_signal_handlers_disconnect_matched (client_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model);
3213 	if (client_data->view)
3214 		g_signal_handlers_disconnect_matched (client_data->view, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model);
3215 
3216 	remove_client_objects (model, client_data);
3217 
3218 	/* If this is the default client and we were querying (so it
3219 	 * was also a source), keep it around but don't query it */
3220 	if (model->priv->default_client == client_data->client && client_data->do_query) {
3221 		client_data->do_query = FALSE;
3222 
3223 		return;
3224 	}
3225 
3226 	if (model->priv->default_client == client_data->client)
3227 		model->priv->default_client = NULL;
3228 
3229 	/* Remove the client from the list */
3230 	model->priv->clients = g_list_remove (model->priv->clients, client_data);
3231 
3232 	/* free all remaining memory */
3233 	g_object_unref (client_data->client);
3234 	if (client_data->view)
3235 		g_object_unref (client_data->view);
3236 	g_free (client_data);
3237 }
3238 
3239 /**
3240  * e_cal_model_remove_client
3241  */
3242 void
3243 e_cal_model_remove_client (ECalModel *model,
3244                            ECalClient *client)
3245 {
3246 	ECalModelClient *client_data;
3247 
3248 	g_return_if_fail (E_IS_CAL_MODEL (model));
3249 	g_return_if_fail (E_IS_CAL_CLIENT (client));
3250 
3251 	client_data = find_client_data (model, client);
3252 	if (client_data)
3253 		remove_client (model, client_data);
3254 }
3255 
3256 /**
3257  * e_cal_model_remove_all_clients
3258  */
3259 void
3260 e_cal_model_remove_all_clients (ECalModel *model)
3261 {
3262 	ECalModelPrivate *priv;
3263 
3264 	g_return_if_fail (E_IS_CAL_MODEL (model));
3265 
3266 	priv = model->priv;
3267 	while (priv->clients != NULL) {
3268 		ECalModelClient *client_data = (ECalModelClient *) priv->clients->data;
3269 		remove_client (model, client_data);
3270 	}
3271 }
3272 
3273 static GSList *
3274 get_objects_as_list (ECalModel *model)
3275 {
3276 	gint i;
3277 	GSList *l = NULL;
3278 	ECalModelPrivate *priv = model->priv;
3279 
3280 	for (i = 0; i < priv->objects->len; i++) {
3281 		ECalModelComponent *comp_data;
3282 
3283 		comp_data = g_ptr_array_index (priv->objects, i);
3284 		if (comp_data == NULL) {
3285 			g_warning ("comp_data is null\n");
3286 			continue;
3287 		}
3288 
3289 		l = g_slist_prepend (l, comp_data);
3290 	}
3291 
3292 	return l;
3293 }
3294 
3295 struct cc_data
3296 {
3297 	ECalModel *model;
3298 	EFlag *eflag;
3299 };
3300 
3301 static gboolean
3302 cleanup_content_cb (gpointer user_data)
3303 {
3304 	ECalModel *model;
3305 	ECalModelPrivate *priv;
3306 	GSList *slist;
3307 	gint len;
3308 	struct cc_data *data = user_data;
3309 
3310 	g_return_val_if_fail (data != NULL, FALSE);
3311 	g_return_val_if_fail (data->model != NULL, FALSE);
3312 	g_return_val_if_fail (data->eflag != NULL, FALSE);
3313 
3314 	model = data->model;
3315 	priv = model->priv;
3316 
3317 	g_return_val_if_fail (priv != NULL, FALSE);
3318 
3319 	e_table_model_pre_change (E_TABLE_MODEL (model));
3320 	len = priv->objects->len;
3321 
3322 	slist = get_objects_as_list (model);
3323 	g_ptr_array_set_size (priv->objects, 0);
3324 	g_signal_emit (model, signals[COMPS_DELETED], 0, slist);
3325 
3326 	e_table_model_rows_deleted (E_TABLE_MODEL (model), 0, len);
3327 
3328 	g_slist_foreach (slist, (GFunc) g_object_unref, NULL);
3329 	g_slist_free (slist);
3330 
3331 	e_flag_set (data->eflag);
3332 
3333 	return FALSE;
3334 }
3335 
3336 static void
3337 redo_queries (ECalModel *model)
3338 {
3339 	ECalModelPrivate *priv;
3340 	GList *l;
3341 	struct cc_data data;
3342 
3343 	priv = model->priv;
3344 
3345 	if (priv->full_sexp)
3346 		g_free (priv->full_sexp);
3347 
3348 	if (priv->start != -1 && priv->end != -1) {
3349 		gchar *iso_start, *iso_end;
3350 		const gchar *default_tzloc = NULL;
3351 
3352 		iso_start = isodate_from_time_t (priv->start);
3353 		iso_end = isodate_from_time_t (priv->end);
3354 
3355 		if (priv->zone && priv->zone != icaltimezone_get_utc_timezone ())
3356 			default_tzloc = icaltimezone_get_location (priv->zone);
3357 		if (!default_tzloc)
3358 			default_tzloc = "";
3359 
3360 		if (priv->search_sexp) {
3361 			priv->full_sexp = g_strdup_printf (
3362 				"(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") %s)",
3363 				iso_start, iso_end, default_tzloc,
3364 				priv->search_sexp ? priv->search_sexp : "");
3365 		} else {
3366 			priv->full_sexp = g_strdup_printf (
3367 				"(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
3368 				iso_start, iso_end, default_tzloc);
3369 		}
3370 
3371 		g_free (iso_start);
3372 		g_free (iso_end);
3373 	} else if (priv->search_sexp) {
3374 		priv->full_sexp = g_strdup (priv->search_sexp);
3375 	} else {
3376 		priv->full_sexp = g_strdup ("#f");
3377 	}
3378 
3379 	/* clean up the current contents, which should be done
3380 	 * always from the main thread, because of gtk calls during removal */
3381 	data.model = model;
3382 	data.eflag = e_flag_new ();
3383 
3384 	if (!g_main_context_is_owner (g_main_context_default ())) {
3385 		/* function called from other than main thread */
3386 		g_timeout_add (10, cleanup_content_cb, &data);
3387 		e_flag_wait (data.eflag);
3388 	} else {
3389 		cleanup_content_cb (&data);
3390 	}
3391 
3392 	e_flag_free (data.eflag);
3393 
3394 	/* update the view for all clients */
3395 	for (l = priv->clients; l != NULL; l = l->next) {
3396 		ECalModelClient *client_data;
3397 
3398 		client_data = (ECalModelClient *) l->data;
3399 		update_e_cal_view_for_client (model, client_data);
3400 	}
3401 }
3402 
3403 void
3404 e_cal_model_get_time_range (ECalModel *model,
3405                             time_t *start,
3406                             time_t *end)
3407 {
3408 	ECalModelPrivate *priv;
3409 
3410 	g_return_if_fail (model != NULL);
3411 	g_return_if_fail (E_IS_CAL_MODEL (model));
3412 
3413 	priv = model->priv;
3414 
3415 	if (start)
3416 		*start = priv->start;
3417 
3418 	if (end)
3419 		*end = priv->end;
3420 }
3421 
3422 void
3423 e_cal_model_set_time_range (ECalModel *model,
3424                             time_t start,
3425                             time_t end)
3426 {
3427 	ECalModelPrivate *priv;
3428 
3429 	g_return_if_fail (model != NULL);
3430 	g_return_if_fail (E_IS_CAL_MODEL (model));
3431 	g_return_if_fail (start >= 0 && end >= 0);
3432 	g_return_if_fail (start <= end);
3433 
3434 	priv = model->priv;
3435 
3436 	if (priv->start == start && priv->end == end)
3437 		return;
3438 
3439 	priv->start = start;
3440 	priv->end = end;
3441 
3442 	g_signal_emit (model, signals[TIME_RANGE_CHANGED], 0, start, end);
3443 	redo_queries (model);
3444 }
3445 
3446 const gchar *
3447 e_cal_model_get_search_query (ECalModel *model)
3448 {
3449 	ECalModelPrivate *priv;
3450 
3451 	g_return_val_if_fail (model != NULL, NULL);
3452 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3453 
3454 	priv = model->priv;
3455 
3456 	return priv->search_sexp;
3457 }
3458 
3459 /**
3460  * e_cal_model_set_query
3461  */
3462 void
3463 e_cal_model_set_search_query (ECalModel *model,
3464                               const gchar *sexp)
3465 {
3466 	ECalModelPrivate *priv;
3467 
3468 	g_return_if_fail (E_IS_CAL_MODEL (model));
3469 
3470 	priv = model->priv;
3471 
3472 	if (!strcmp (sexp ? sexp : "", priv->search_sexp ? priv->search_sexp : ""))
3473 		return;
3474 
3475 	if (priv->search_sexp)
3476 		g_free (priv->search_sexp);
3477 
3478 	if (!sexp || !*sexp)
3479 		priv->search_sexp = NULL;
3480 	else
3481 		priv->search_sexp = g_strdup (sexp);
3482 
3483 	redo_queries (model);
3484 }
3485 
3486 /**
3487  * e_cal_model_set_query
3488  */
3489 void
3490 e_cal_model_set_search_query_with_time_range (ECalModel *model,
3491                                               const gchar *sexp,
3492                                               time_t start,
3493                                               time_t end)
3494 {
3495 	ECalModelPrivate *priv;
3496 	gboolean do_query = FALSE;
3497 
3498 	g_return_if_fail (E_IS_CAL_MODEL (model));
3499 
3500 	priv = model->priv;
3501 
3502 	if (strcmp (sexp ? sexp : "", priv->search_sexp ? priv->search_sexp : "")) {
3503 		if (priv->search_sexp)
3504 			g_free (priv->search_sexp);
3505 
3506 		if (!sexp || !*sexp)
3507 			priv->search_sexp = NULL;
3508 		else
3509 			priv->search_sexp = g_strdup (sexp);
3510 		do_query = TRUE;
3511 	}
3512 
3513 	if (!(priv->start == start && priv->end == end)) {
3514 		priv->start = start;
3515 		priv->end = end;
3516 		do_query = TRUE;
3517 
3518 		g_signal_emit (model, signals[TIME_RANGE_CHANGED], 0, start, end);
3519 	}
3520 
3521 	if (do_query)
3522 		redo_queries (model);
3523 }
3524 
3525 /**
3526  * e_cal_model_create_component_with_defaults
3527  */
3528 icalcomponent *
3529 e_cal_model_create_component_with_defaults (ECalModel *model,
3530                                             gboolean all_day)
3531 {
3532 	ECalModelPrivate *priv;
3533 	ECalComponent *comp;
3534 	icalcomponent *icalcomp;
3535 	ECalClient *client;
3536 
3537 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3538 
3539 	priv = model->priv;
3540 
3541 	g_return_val_if_fail (priv->clients != NULL, NULL);
3542 
3543 	client = e_cal_model_get_default_client (model);
3544 	if (!client)
3545 		return icalcomponent_new (priv->kind);
3546 
3547 	switch (priv->kind) {
3548 	case ICAL_VEVENT_COMPONENT :
3549 		comp = cal_comp_event_new_with_defaults (
3550 			client, all_day,
3551 			e_cal_model_get_use_default_reminder (model),
3552 			e_cal_model_get_default_reminder_interval (model),
3553 			e_cal_model_get_default_reminder_units (model));
3554 		break;
3555 	case ICAL_VTODO_COMPONENT :
3556 		comp = cal_comp_task_new_with_defaults (client);
3557 		break;
3558 	case ICAL_VJOURNAL_COMPONENT :
3559 		comp = cal_comp_memo_new_with_defaults (client);
3560 		break;
3561 	default:
3562 		return NULL;
3563 	}
3564 
3565 	if (!comp)
3566 		return icalcomponent_new (priv->kind);
3567 
3568 	icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
3569 	g_object_unref (comp);
3570 
3571 	/* make sure the component has an UID */
3572 	if (!icalcomponent_get_uid (icalcomp)) {
3573 		gchar *uid;
3574 
3575 		uid = e_cal_component_gen_uid ();
3576 		icalcomponent_set_uid (icalcomp, uid);
3577 
3578 		g_free (uid);
3579 	}
3580 
3581 	return icalcomp;
3582 }
3583 
3584 /**
3585  * Returns information about attendees in the component.
3586  * If there are no attendees, the function returns NULL.
3587  *
3588  * The information is like "Status: Accepted: X   Declined: Y  ...".
3589  *
3590  * Free returned pointer with g_free.
3591  **/
3592 gchar *
3593 e_cal_model_get_attendees_status_info (ECalModel *model,
3594                                        ECalComponent *comp,
3595                                        ECalClient *cal_client)
3596 {
3597 	struct _values {
3598 		icalparameter_partstat status;
3599 		const gchar *caption;
3600 		gint count;
3601 	} values[] = {
3602 		{ ICAL_PARTSTAT_ACCEPTED,    N_("Accepted"),     0 },
3603 		{ ICAL_PARTSTAT_DECLINED,    N_("Declined"),     0 },
3604 		{ ICAL_PARTSTAT_TENTATIVE,   N_("Tentative"),    0 },
3605 		{ ICAL_PARTSTAT_DELEGATED,   N_("Delegated"),    0 },
3606 		{ ICAL_PARTSTAT_NEEDSACTION, N_("Needs action"), 0 },
3607 		{ ICAL_PARTSTAT_NONE,        N_("Other"),        0 },
3608 		{ ICAL_PARTSTAT_X,           NULL,              -1 }
3609 	};
3610 
3611 	ESourceRegistry *registry;
3612 	GSList *attendees = NULL, *a;
3613 	gboolean have = FALSE;
3614 	gchar *res = NULL;
3615 	gint i;
3616 
3617 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3618 
3619 	registry = e_cal_model_get_registry (model);
3620 
3621 	if (!comp || !e_cal_component_has_attendees (comp) ||
3622 	    !itip_organizer_is_user_ex (registry, comp, cal_client, TRUE))
3623 		return NULL;
3624 
3625 	e_cal_component_get_attendee_list (comp, &attendees);
3626 
3627 	for (a = attendees; a; a = a->next) {
3628 		ECalComponentAttendee *att = a->data;
3629 
3630 		if (att && att->cutype == ICAL_CUTYPE_INDIVIDUAL &&
3631 		    (att->role == ICAL_ROLE_CHAIR ||
3632 		     att->role == ICAL_ROLE_REQPARTICIPANT ||
3633 		     att->role == ICAL_ROLE_OPTPARTICIPANT)) {
3634 			have = TRUE;
3635 
3636 			for (i = 0; values[i].count != -1; i++) {
3637 				if (att->status == values[i].status || values[i].status == ICAL_PARTSTAT_NONE) {
3638 					values[i].count++;
3639 					break;
3640 				}
3641 			}
3642 		}
3643 	}
3644 
3645 	if (have) {
3646 		GString *str = g_string_new ("");
3647 
3648 		for (i = 0; values[i].count != -1; i++) {
3649 			if (values[i].count > 0) {
3650 				if (str->str && *str->str)
3651 					g_string_append (str, "   ");
3652 
3653 				g_string_append_printf (str, "%s: %d", _(values[i].caption), values[i].count);
3654 			}
3655 		}
3656 
3657 		g_string_prepend (str, ": ");
3658 
3659 		/* To Translators: 'Status' here means the state of the attendees, the resulting string will be in a form:
3660 		 * Status: Accepted: X   Declined: Y   ... */
3661 		g_string_prepend (str, _("Status"));
3662 
3663 		res = g_string_free (str, FALSE);
3664 	}
3665 
3666 	if (attendees)
3667 		e_cal_component_free_attendee_list (attendees);
3668 
3669 	return res;
3670 }
3671 
3672 /**
3673  * e_cal_model_get_color_for_component
3674  */
3675 const gchar *
3676 e_cal_model_get_color_for_component (ECalModel *model,
3677                                      ECalModelComponent *comp_data)
3678 {
3679 	ECalModelClass *model_class;
3680 	const gchar *color = NULL;
3681 
3682 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3683 	g_return_val_if_fail (comp_data != NULL, NULL);
3684 
3685 	model_class = (ECalModelClass *) G_OBJECT_GET_CLASS (model);
3686 	if (model_class->get_color_for_component != NULL)
3687 		color = model_class->get_color_for_component (model, comp_data);
3688 
3689 	if (!color)
3690 		color = ecm_get_color_for_component (model, comp_data);
3691 
3692 	return color;
3693 }
3694 
3695 /**
3696  * e_cal_model_get_rgb_color_for_component
3697  */
3698 gboolean
3699 e_cal_model_get_rgb_color_for_component (ECalModel *model,
3700                                          ECalModelComponent *comp_data,
3701                                          gdouble *red,
3702                                          gdouble *green,
3703                                          gdouble *blue)
3704 {
3705 	GdkColor gdk_color;
3706 	const gchar *color;
3707 
3708 	color = e_cal_model_get_color_for_component (model, comp_data);
3709 	if (color && gdk_color_parse (color, &gdk_color)) {
3710 
3711 		if (red)
3712 			*red = ((gdouble) gdk_color.red)/0xffff;
3713 		if (green)
3714 			*green = ((gdouble) gdk_color.green)/0xffff;
3715 		if (blue)
3716 			*blue = ((gdouble) gdk_color.blue)/0xffff;
3717 
3718 		return TRUE;
3719 	}
3720 
3721 	return FALSE;
3722 }
3723 
3724 /**
3725  * e_cal_model_get_component_at
3726  */
3727 ECalModelComponent *
3728 e_cal_model_get_component_at (ECalModel *model,
3729                               gint row)
3730 {
3731 	ECalModelPrivate *priv;
3732 
3733 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3734 
3735 	priv = model->priv;
3736 
3737 	g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL);
3738 
3739 	return g_ptr_array_index (priv->objects, row);
3740 }
3741 
3742 ECalModelComponent *
3743 e_cal_model_get_component_for_uid (ECalModel *model,
3744                                    const ECalComponentId *id)
3745 {
3746 	ECalModelPrivate *priv;
3747 
3748 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3749 
3750 	priv = model->priv;
3751 
3752 	return search_by_id_and_client (priv, NULL, id);
3753 }
3754 
3755 /**
3756  * e_cal_model_date_value_to_string
3757  */
3758 gchar *
3759 e_cal_model_date_value_to_string (ECalModel *model,
3760                                   gconstpointer value)
3761 {
3762 	ECalModelPrivate *priv;
3763 	ECellDateEditValue *dv = (ECellDateEditValue *) value;
3764 	struct icaltimetype tt;
3765 	struct tm tmp_tm;
3766 	gchar buffer[64];
3767 
3768 	g_return_val_if_fail (E_IS_CAL_MODEL (model), g_strdup (""));
3769 
3770 	priv = model->priv;
3771 
3772 	if (!dv)
3773 		return g_strdup ("");
3774 
3775 	/* We currently convert all the dates to the current timezone. */
3776 	tt = dv->tt;
3777 	icaltimezone_convert_time (&tt, dv->zone, priv->zone);
3778 
3779 	tmp_tm.tm_year = tt.year - 1900;
3780 	tmp_tm.tm_mon = tt.month - 1;
3781 	tmp_tm.tm_mday = tt.day;
3782 	tmp_tm.tm_hour = tt.hour;
3783 	tmp_tm.tm_min = tt.minute;
3784 	tmp_tm.tm_sec = tt.second;
3785 	tmp_tm.tm_isdst = -1;
3786 
3787 	tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, tt.year);
3788 
3789 	memset (buffer, 0, sizeof (buffer));
3790 	e_time_format_date_and_time (&tmp_tm, priv->use_24_hour_format,
3791 				     TRUE, FALSE,
3792 				     buffer, sizeof (buffer));
3793 	return g_strdup (buffer);
3794 }
3795 
3796 /* FIXME is it still needed ?
3797 static ECellDateEditValue *
3798 copy_ecdv (ECellDateEditValue *ecdv)
3799 {
3800 	ECellDateEditValue *new_ecdv;
3801  *
3802 	new_ecdv = g_new0 (ECellDateEditValue, 1);
3803 	new_ecdv->tt = ecdv ? ecdv->tt : icaltime_null_time ();
3804 	new_ecdv->zone = ecdv ? ecdv->zone : NULL;
3805  *
3806 	return new_ecdv;
3807 } */
3808 
3809 static void e_cal_model_component_finalize (GObject *object);
3810 
3811 /* Class initialization function for the calendar component object */
3812 static void
3813 e_cal_model_component_class_init (ECalModelComponentClass *class)
3814 {
3815 	GObjectClass *object_class;
3816 
3817 	object_class = (GObjectClass *) class;
3818 	g_type_class_add_private (class, sizeof (ECalModelComponentPrivate));
3819 
3820 	object_class->finalize = e_cal_model_component_finalize;
3821 }
3822 
3823 static void
3824 e_cal_model_component_finalize (GObject *object)
3825 {
3826 	ECalModelComponent *comp_data = E_CAL_MODEL_COMPONENT (object);
3827 
3828 	if (comp_data->client) {
3829 		g_object_unref (comp_data->client);
3830 		comp_data->client = NULL;
3831 	}
3832 	if (comp_data->icalcomp) {
3833 		icalcomponent_free (comp_data->icalcomp);
3834 		comp_data->icalcomp = NULL;
3835 	}
3836 	if (comp_data->dtstart) {
3837 		g_free (comp_data->dtstart);
3838 		comp_data->dtstart = NULL;
3839 	}
3840 	if (comp_data->dtend) {
3841 		g_free (comp_data->dtend);
3842 		comp_data->dtend = NULL;
3843 	}
3844 	if (comp_data->due) {
3845 		g_free (comp_data->due);
3846 		comp_data->due = NULL;
3847 	}
3848 	if (comp_data->completed) {
3849 		g_free (comp_data->completed);
3850 		comp_data->completed = NULL;
3851 	}
3852 	if (comp_data->created) {
3853 		g_free (comp_data->created);
3854 		comp_data->created = NULL;
3855 	}
3856 	if (comp_data->lastmodified) {
3857 		g_free (comp_data->lastmodified);
3858 		comp_data->lastmodified = NULL;
3859 	}
3860 	if (comp_data->color) {
3861 		g_free (comp_data->color);
3862 		comp_data->color = NULL;
3863 	}
3864 
3865 	if (comp_data->priv->categories_str)
3866 		g_string_free (comp_data->priv->categories_str, TRUE);
3867 	comp_data->priv->categories_str = NULL;
3868 
3869 	/* Chain up to parent's finalize() method. */
3870 	G_OBJECT_CLASS (e_cal_model_component_parent_class)->finalize (object);
3871 }
3872 
3873 static void
3874 e_cal_model_component_init (ECalModelComponent *comp)
3875 {
3876 	comp->priv = E_CAL_MODEL_COMPONENT_GET_PRIVATE (comp);
3877 }
3878 
3879 /**
3880  * e_cal_model_generate_instances_sync
3881  *
3882  * cb function is not called with cb_data, but with ECalModelGenerateInstancesData which contains cb_data
3883  */
3884 void
3885 e_cal_model_generate_instances_sync (ECalModel *model,
3886                                      time_t start,
3887                                      time_t end,
3888                                      ECalRecurInstanceFn cb,
3889                                      gpointer cb_data)
3890 {
3891 	ECalModelGenerateInstancesData mdata;
3892 	gint i, n;
3893 
3894 	n = e_table_model_row_count (E_TABLE_MODEL (model));
3895 	for (i = 0; i < n; i++) {
3896 		ECalModelComponent *comp_data = e_cal_model_get_component_at (model, i);
3897 
3898 		mdata.comp_data = comp_data;
3899 		mdata.cb_data = cb_data;
3900 
3901 		if (comp_data->instance_start < end && comp_data->instance_end > start)
3902 			e_cal_client_generate_instances_for_object_sync (comp_data->client, comp_data->icalcomp, start, end, cb, &mdata);
3903 	}
3904 }
3905 
3906 /**
3907  * e_cal_model_get_object_array
3908  */
3909 GPtrArray *
3910 e_cal_model_get_object_array (ECalModel *model)
3911 {
3912 	g_return_val_if_fail (model != NULL, NULL);
3913 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3914 	g_return_val_if_fail (model->priv != NULL, NULL);
3915 
3916 	return model->priv->objects;
3917 }
3918 
3919 void
3920 e_cal_model_set_instance_times (ECalModelComponent *comp_data,
3921                                 const icaltimezone *zone)
3922 {
3923 	struct icaltimetype start_time, end_time;
3924 	icalcomponent_kind kind;
3925 
3926 	kind = icalcomponent_isa (comp_data->icalcomp);
3927 	start_time = icalcomponent_get_dtstart (comp_data->icalcomp);
3928 	end_time = icalcomponent_get_dtend (comp_data->icalcomp);
3929 
3930 	if (kind == ICAL_VEVENT_COMPONENT) {
3931 		if (start_time.is_date && icaltime_is_null_time (end_time)) {
3932 			/* If end_time is null and it's an all day event,
3933 			 * just make start_time = end_time so that end_time
3934 			 * will be a valid date
3935 			 */
3936 			end_time = start_time;
3937 			icaltime_adjust (&end_time, 1, 0, 0, 0);
3938 			icalcomponent_set_dtend (comp_data->icalcomp, end_time);
3939 		} else if (start_time.is_date && end_time.is_date &&
3940 			   (icaltime_compare_date_only (start_time, end_time) == 0)) {
3941 			/* If both DTSTART and DTEND are DATE values, and they are the
3942 			 * same day, we add 1 day to DTEND. This means that most
3943 			 * events created with the old Evolution behavior will still
3944 			 * work OK. */
3945 			icaltime_adjust (&end_time, 1, 0, 0, 0);
3946 			icalcomponent_set_dtend (comp_data->icalcomp, end_time);
3947 		}
3948 	}
3949 
3950 	if (start_time.zone)
3951 		zone = start_time.zone;
3952 	else {
3953 		icalparameter *param = NULL;
3954 		icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY);
3955 
3956 	       if (prop)	{
3957 			param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
3958 
3959 			if (param) {
3960 				const gchar *tzid = NULL;
3961 				icaltimezone *st_zone = NULL;
3962 
3963 				tzid = icalparameter_get_tzid (param);
3964 				if (tzid)
3965 					e_cal_client_get_timezone_sync (comp_data->client, tzid, &st_zone, NULL, NULL);
3966 
3967 				if (st_zone)
3968 					zone = st_zone;
3969 			}
3970 	       }
3971 	}
3972 
3973 	comp_data->instance_start = icaltime_as_timet_with_zone (start_time, zone);
3974 
3975 	if (end_time.zone)
3976 		zone = end_time.zone;
3977 	else {
3978 		icalparameter *param = NULL;
3979 		icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY);
3980 
3981 	       if (prop)	{
3982 			param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
3983 
3984 			if (param) {
3985 				const gchar *tzid = NULL;
3986 				icaltimezone *end_zone = NULL;
3987 
3988 				tzid = icalparameter_get_tzid (param);
3989 				if (tzid)
3990 					e_cal_client_get_timezone_sync (comp_data->client, tzid, &end_zone, NULL, NULL);
3991 
3992 				if (end_zone)
3993 					zone = end_zone;
3994 			}
3995 	       }
3996 
3997 	}
3998 	comp_data->instance_end = icaltime_as_timet_with_zone (end_time, zone);
3999 }
4000 
4001 /**
4002  * e_cal_model_set_default_time_func:
4003  * This function will be used when creating new item from the "click-to-add",
4004  * when user didn't fill a start date there.
4005  **/
4006 void
4007 e_cal_model_set_default_time_func (ECalModel *model,
4008                                    ECalModelDefaultTimeFunc func,
4009                                    gpointer user_data)
4010 {
4011 	g_return_if_fail (E_IS_CAL_MODEL (model));
4012 
4013 	model->priv->get_default_time = func;
4014 	model->priv->get_default_time_user_data = user_data;
4015 }