evolution-3.6.4/mail/em-folder-properties.c

Location Tool Test ID Function Issue
em-folder-properties.c:210:10 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'folder')
em-folder-properties.c:210:10 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'folder')
  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Michael Zucchi <notzed@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include "em-folder-properties.h"
 28 
 29 #include <string.h>
 30 
 31 #include <gtk/gtk.h>
 32 #include <glib/gi18n.h>
 33 
 34 #include <libemail-utils/mail-mt.h>
 35 #include <libemail-engine/e-mail-folder-utils.h>
 36 #include <libemail-engine/mail-ops.h>
 37 
 38 #include "e-mail-backend.h"
 39 #include "e-mail-ui-session.h"
 40 #include "em-config.h"
 41 #include "mail-vfolder-ui.h"
 42 
 43 typedef struct _AsyncContext AsyncContext;
 44 
 45 struct _AsyncContext {
 46 	EActivity *activity;
 47 	CamelFolder *folder;
 48 	GtkWindow *parent_window;
 49 	CamelFolderQuotaInfo *quota_info;
 50 	gint total;
 51 	gint unread;
 52 };
 53 
 54 static void
 55 async_context_free (AsyncContext *context)
 56 {
 57 	if (context->activity != NULL)
 58 		g_object_unref (context->activity);
 59 
 60 	if (context->folder != NULL)
 61 		g_object_unref (context->folder);
 62 
 63 	if (context->parent_window != NULL)
 64 		g_object_unref (context->parent_window);
 65 
 66 	if (context->quota_info != NULL)
 67 		camel_folder_quota_info_free (context->quota_info);
 68 
 69 	g_slice_free (AsyncContext, context);
 70 }
 71 
 72 static void
 73 emfp_free (EConfig *ec,
 74            GSList *items,
 75            gpointer data)
 76 {
 77 	g_slist_free (items);
 78 }
 79 
 80 static gint
 81 add_numbered_row (GtkTable *table,
 82                   gint row,
 83                   const gchar *description,
 84                   const gchar *format,
 85                   gint num)
 86 {
 87 	gchar *str;
 88 	GtkWidget *label;
 89 
 90 	g_return_val_if_fail (table != NULL, row);
 91 	g_return_val_if_fail (description != NULL, row);
 92 	g_return_val_if_fail (format != NULL, row);
 93 
 94 	label = gtk_label_new (description);
 95 	gtk_widget_show (label);
 96 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 97 	gtk_table_attach (
 98 		table, label, 0, 1, row, row + 1,
 99 		GTK_FILL, 0, 0, 0);
100 
101 	str = g_strdup_printf (format, num);
102 
103 	label = gtk_label_new (str);
104 	gtk_widget_show (label);
105 	gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
106 	gtk_table_attach (
107 		table, label, 1, 2, row, row + 1,
108 		GTK_FILL | GTK_EXPAND, 0, 0, 0);
109 
110 	g_free (str);
111 
112 	return row + 1;
113 }
114 
115 static GtkWidget *
116 emfp_get_folder_item (EConfig *ec,
117                       EConfigItem *item,
118                       GtkWidget *parent,
119                       GtkWidget *old,
120                       gint position,
121                       gpointer data)
122 {
123 	GObjectClass *class;
124 	GParamSpec **properties;
125 	GtkWidget *widget, *table;
126 	AsyncContext *context = data;
127 	guint ii, n_properties;
128 	gint row = 0;
129 	gboolean can_apply_filters = FALSE;
130 
131 	if (old)
132 		return old;
133 
134 	table = gtk_table_new (2, 2, FALSE);
135 	gtk_table_set_row_spacings ((GtkTable *) table, 6);
136 	gtk_table_set_col_spacings ((GtkTable *) table, 12);
137 	gtk_widget_show (table);
138 	gtk_box_pack_start ((GtkBox *) parent, table, TRUE, TRUE, 0);
139 
140 	/* To be on the safe side, ngettext is used here,
141 	 * see e.g. comment #3 at bug 272567 */
142 	row = add_numbered_row (
143 		GTK_TABLE (table), row,
144 		ngettext (
145 			"Unread messages:",
146 			"Unread messages:",
147 			context->unread),
148 		"%d", context->unread);
149 
150 	/* TODO: can this be done in a loop? */
151 	/* To be on the safe side, ngettext is used here,
152 	 * see e.g. comment #3 at bug 272567 */
153 	row = add_numbered_row (
154 		GTK_TABLE (table), row,
155 		ngettext (
156 			"Total messages:",
157 			"Total messages:",
158 			context->total),
159 		"%d", context->total);
160 
161 	if (context->quota_info) {
162 		CamelFolderQuotaInfo *info;
163 		CamelFolderQuotaInfo *quota = context->quota_info;
164 
165 		for (info = quota; info; info = info->next) {
166 			gchar *descr;
167 			gint procs;
168 
169 			/* should not happen, but anyway... */
170 			if (!info->total)
171 				continue;
172 
173 			/* Show quota name only when available and we
174 			 * have more than one quota info. */
175 			if (info->name && quota->next)
176 				descr = g_strdup_printf (
177 					_("Quota usage (%s):"), _(info->name));
178 			else
179 				descr = g_strdup_printf (_("Quota usage"));
180 
181 			procs = (gint) ((((gdouble) info->used) /
182 				((gdouble) info->total)) * 100.0 + 0.5);
183 
184 			row = add_numbered_row (
185 				GTK_TABLE (table), row,
186 				descr, "%d%%", procs);
187 
188 			g_free (descr);
189 		}
190 	}
191 
192 	if (context->folder != NULL) {
193 		CamelStore *store;
194 		CamelSession *session;
195 		CamelFolderInfoFlags fi_flags = 0;
196 		MailFolderCache *folder_cache;
197 
198 		store = camel_folder_get_parent_store (context->folder);
199 		session = camel_service_get_session (CAMEL_SERVICE (store));
200 		folder_cache = e_mail_session_get_folder_cache (
201 			E_MAIL_SESSION (session));
202 
203 		can_apply_filters =
204 			!CAMEL_IS_VEE_FOLDER (context->folder) &&
205 			mail_folder_cache_get_folder_info_flags (
206 				folder_cache, context->folder, &fi_flags) &&
207 			(fi_flags & CAMEL_FOLDER_TYPE_MASK) != CAMEL_FOLDER_TYPE_INBOX;
208 	}
209 
210 	class = G_OBJECT_GET_CLASS (context->folder);
Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'folder')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'g_class' results in a dereference of a null pointer (loaded from field 'folder')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

211 properties = g_object_class_list_properties (class, &n_properties); 212 213 for (ii = 0; ii < n_properties; ii++) { 214 const gchar *blurb; 215 216 if ((properties[ii]->flags & CAMEL_PARAM_PERSISTENT) == 0) 217 continue; 218 219 if (!can_apply_filters && 220 g_strcmp0 (properties[ii]->name, "apply-filters") == 0) 221 continue; 222 223 blurb = g_param_spec_get_blurb (properties[ii]); 224 225 switch (properties[ii]->value_type) { 226 case G_TYPE_BOOLEAN: 227 widget = gtk_check_button_new_with_mnemonic (blurb); 228 g_object_bind_property ( 229 context->folder, 230 properties[ii]->name, 231 widget, "active", 232 G_BINDING_BIDIRECTIONAL | 233 G_BINDING_SYNC_CREATE); 234 gtk_widget_show (widget); 235 gtk_table_attach ( 236 GTK_TABLE (table), widget, 237 0, 2, row, row + 1, 238 GTK_FILL | GTK_EXPAND, 0, 0, 0); 239 row++; 240 break; 241 default: 242 g_warn_if_reached (); 243 break; 244 } 245 } 246 247 g_free (properties); 248 249 return table; 250 } 251 252 #define EMFP_FOLDER_SECTION (2) 253 254 static EMConfigItem emfp_items[] = { 255 { E_CONFIG_BOOK, (gchar *) "", NULL }, 256 { E_CONFIG_PAGE, (gchar *) "00.general", 257 (gchar *) N_("General") }, 258 { E_CONFIG_SECTION, (gchar *) "00.general/00.folder", 259 NULL /* set by code */ }, 260 { E_CONFIG_ITEM, (gchar *) "00.general/00.folder/00.info", 261 NULL, emfp_get_folder_item }, 262 }; 263 static gboolean emfp_items_translated = FALSE; 264 265 static void 266 emfp_dialog_run (AsyncContext *context) 267 { 268 GtkWidget *dialog, *w; 269 GtkWidget *content_area; 270 GSList *l; 271 gint32 i,deleted; 272 EMConfig *ec; 273 EMConfigTargetFolder *target; 274 CamelStore *parent_store; 275 CamelFolderSummary *summary; 276 gboolean store_is_local; 277 gboolean hide_deleted; 278 GSettings *settings; 279 const gchar *name; 280 const gchar *uid; 281 282 parent_store = camel_folder_get_parent_store (context->folder); 283 284 /* Get number of VISIBLE and DELETED messages, instead of TOTAL 285 * messages. VISIBLE+DELETED gives the correct count that matches 286 * the label below the Send & Receive button. */ 287 summary = context->folder->summary; 288 context->total = camel_folder_summary_get_visible_count (summary); 289 context->unread = camel_folder_summary_get_unread_count (summary); 290 deleted = camel_folder_summary_get_deleted_count (summary); 291 292 settings = g_settings_new ("org.gnome.evolution.mail"); 293 hide_deleted = !g_settings_get_boolean (settings, "show-deleted"); 294 g_object_unref (settings); 295 296 /* 297 * Do the calculation only for those accounts that support VTRASHes 298 */ 299 if (parent_store->flags & CAMEL_STORE_VTRASH) { 300 if (CAMEL_IS_VTRASH_FOLDER (context->folder)) 301 context->total += deleted; 302 else if (!hide_deleted && deleted > 0) 303 context->total += deleted; 304 } 305 306 /* 307 * If the folder is junk folder, get total number of mails. 308 */ 309 if (parent_store->flags & CAMEL_STORE_VJUNK) 310 context->total = camel_folder_summary_count ( 311 context->folder->summary); 312 313 name = camel_folder_get_display_name (context->folder); 314 315 uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); 316 store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); 317 318 if (store_is_local 319 && (!strcmp (name, "Drafts") 320 || !strcmp (name, "Templates") 321 || !strcmp (name, "Inbox") 322 || !strcmp (name, "Outbox") 323 || !strcmp (name, "Sent"))) { 324 emfp_items[EMFP_FOLDER_SECTION].label = gettext (name); 325 if (!emfp_items_translated) { 326 for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) { 327 if (emfp_items[i].label) 328 emfp_items[i].label = _(emfp_items[i].label); 329 } 330 emfp_items_translated = TRUE; 331 } 332 } else if (!strcmp (name, "INBOX")) 333 emfp_items[EMFP_FOLDER_SECTION].label = _("Inbox"); 334 else 335 emfp_items[EMFP_FOLDER_SECTION].label = (gchar *) name; 336 337 dialog = gtk_dialog_new_with_buttons ( 338 _("Folder Properties"), 339 context->parent_window, 340 GTK_DIALOG_DESTROY_WITH_PARENT, 341 GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL); 342 gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160); 343 344 gtk_widget_ensure_style (dialog); 345 346 content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); 347 gtk_container_set_border_width (GTK_CONTAINER (content_area), 12); 348 349 /** @HookPoint-EMConfig: Folder Properties Window 350 * @Id: org.gnome.evolution.mail.folderConfig 351 * @Type: E_CONFIG_BOOK 352 * @Class: org.gnome.evolution.mail.config:1.0 353 * @Target: EMConfigTargetFolder 354 * 355 * The folder properties window. 356 */ 357 ec = em_config_new ( 358 E_CONFIG_BOOK, "org.gnome.evolution.mail.folderConfig"); 359 l = NULL; 360 for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) 361 l = g_slist_prepend (l, &emfp_items[i]); 362 e_config_add_items ((EConfig *) ec, l, emfp_free, context); 363 364 target = em_config_target_new_folder (ec, context->folder); 365 366 e_config_set_target ((EConfig *) ec, (EConfigTarget *) target); 367 w = e_config_create_widget ((EConfig *) ec); 368 369 gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 0); 370 371 /* We do 'apply on ok', since instant apply may start some 372 * very long running tasks. */ 373 374 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 375 e_config_commit ((EConfig *) ec); 376 camel_object_state_write (CAMEL_OBJECT (context->folder)); 377 } else 378 e_config_abort ((EConfig *) ec); 379 380 gtk_widget_destroy (dialog); 381 } 382 383 static void 384 emfp_dialog_got_quota_info (CamelFolder *folder, 385 GAsyncResult *result, 386 AsyncContext *context) 387 { 388 EAlertSink *alert_sink; 389 GError *error = NULL; 390 391 alert_sink = e_activity_get_alert_sink (context->activity); 392 393 context->quota_info = 394 camel_folder_get_quota_info_finish (folder, result, &error); 395 396 /* If the folder does not implement quota info, just continue. */ 397 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { 398 g_warn_if_fail (context->quota_info == NULL); 399 g_error_free (error); 400 401 } else if (e_activity_handle_cancellation (context->activity, error)) { 402 g_warn_if_fail (context->quota_info == NULL); 403 async_context_free (context); 404 g_error_free (error); 405 return; 406 407 /* FIXME Add an EAlert for failing to get quota info. */ 408 } else if (error != NULL) { 409 g_warn_if_fail (context->folder == NULL); 410 e_alert_submit ( 411 alert_sink, "mail:folder-open", 412 error->message, NULL); 413 async_context_free (context); 414 g_error_free (error); 415 return; 416 } 417 418 /* Quota info may still be NULL here if not supported. */ 419 420 /* Finalize the activity here so we don't leave a message 421 * in the task bar while the properties window is shown. */ 422 e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED); 423 g_object_unref (context->activity); 424 context->activity = NULL; 425 426 emfp_dialog_run (context); 427 428 async_context_free (context); 429 } 430 431 static void 432 emfp_dialog_got_folder (CamelStore *store, 433 GAsyncResult *result, 434 AsyncContext *context) 435 { 436 EAlertSink *alert_sink; 437 GCancellable *cancellable; 438 GError *error = NULL; 439 440 alert_sink = e_activity_get_alert_sink (context->activity); 441 cancellable = e_activity_get_cancellable (context->activity); 442 443 context->folder = camel_store_get_folder_finish ( 444 store, result, &error); 445 446 if (e_activity_handle_cancellation (context->activity, error)) { 447 g_warn_if_fail (context->folder == NULL); 448 async_context_free (context); 449 g_error_free (error); 450 return; 451 452 } else if (error != NULL) { 453 g_warn_if_fail (context->folder == NULL); 454 e_alert_submit ( 455 alert_sink, "mail:folder-open", 456 error->message, NULL); 457 async_context_free (context); 458 g_error_free (error); 459 return; 460 } 461 462 g_return_if_fail (CAMEL_IS_FOLDER (context->folder)); 463 464 camel_folder_get_quota_info ( 465 context->folder, G_PRIORITY_DEFAULT, cancellable, 466 (GAsyncReadyCallback) emfp_dialog_got_quota_info, context); 467 } 468 469 /** 470 * em_folder_properties_show: 471 * @store: a #CamelStore 472 * @folder_name: a folder name 473 * @alert_sink: an #EAlertSink 474 * @parent_window: a parent #GtkWindow 475 * 476 * Show folder properties for @folder_name. 477 **/ 478 void 479 em_folder_properties_show (CamelStore *store, 480 const gchar *folder_name, 481 EAlertSink *alert_sink, 482 GtkWindow *parent_window) 483 { 484 CamelService *service; 485 CamelSession *session; 486 GCancellable *cancellable; 487 AsyncContext *context; 488 const gchar *uid; 489 490 g_return_if_fail (CAMEL_IS_STORE (store)); 491 g_return_if_fail (folder_name != NULL); 492 g_return_if_fail (E_IS_ALERT_SINK (alert_sink)); 493 g_return_if_fail (GTK_IS_WINDOW (parent_window)); 494 495 service = CAMEL_SERVICE (store); 496 uid = camel_service_get_uid (service); 497 session = camel_service_get_session (service); 498 499 /* Show the Edit Rule dialog for Search Folders, but not "Unmatched". 500 * "Unmatched" is a special Search Folder which can't be modified. */ 501 if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { 502 if (g_strcmp0 (folder_name, CAMEL_UNMATCHED_NAME) != 0) { 503 gchar *folder_uri; 504 505 folder_uri = e_mail_folder_uri_build ( 506 store, folder_name); 507 vfolder_edit_rule ( 508 E_MAIL_SESSION (session), 509 folder_uri, alert_sink); 510 g_free (folder_uri); 511 return; 512 } 513 } 514 515 /* Open the folder asynchronously. */ 516 517 context = g_slice_new0 (AsyncContext); 518 context->activity = e_activity_new (); 519 context->parent_window = g_object_ref (parent_window); 520 521 e_activity_set_alert_sink (context->activity, alert_sink); 522 523 cancellable = camel_operation_new (); 524 e_activity_set_cancellable (context->activity, cancellable); 525 526 e_mail_ui_session_add_activity ( 527 E_MAIL_UI_SESSION (session), context->activity); 528 529 camel_store_get_folder ( 530 store, folder_name, 0, G_PRIORITY_DEFAULT, cancellable, 531 (GAsyncReadyCallback) emfp_dialog_got_folder, context); 532 533 g_object_unref (cancellable); 534 }