evolution-3.6.4/plugins/attachment-reminder/attachment-reminder.c

Location Tool Test ID Function Issue
attachment-reminder.c:284:9 clang-analyzer Value stored to 'found' is never read
attachment-reminder.c:284:9 clang-analyzer Value stored to 'found' is never read
  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  *		Johnny Jacob <jjohnny@novell.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 <gtk/gtk.h>
 28 #include <glib/gi18n.h>
 29 #include <string.h>
 30 
 31 #include <e-util/e-util.h>
 32 #include <e-util/e-config.h>
 33 #include <mail/em-config.h>
 34 #include <mail/em-event.h>
 35 
 36 #include <libevolution-utils/e-alert-dialog.h>
 37 #include <e-util/e-plugin.h>
 38 
 39 #include <mail/em-utils.h>
 40 
 41 #include "composer/e-msg-composer.h"
 42 #include "composer/e-composer-actions.h"
 43 #include "widgets/misc/e-attachment-view.h"
 44 #include "widgets/misc/e-attachment-store.h"
 45 
 46 #define CONF_KEY_ATTACH_REMINDER_CLUES "attachment-reminder-clues"
 47 
 48 typedef struct {
 49 	GSettings   *settings;
 50 	GtkWidget   *treeview;
 51 	GtkWidget   *clue_add;
 52 	GtkWidget   *clue_edit;
 53 	GtkWidget   *clue_remove;
 54 	GtkListStore *store;
 55 } UIData;
 56 
 57 enum {
 58 	CLUE_KEYWORD_COLUMN,
 59 	CLUE_N_COLUMNS
 60 };
 61 
 62 gint		e_plugin_lib_enable	(EPlugin *ep,
 63 					 gint enable);
 64 GtkWidget *	e_plugin_lib_get_configure_widget
 65 					(EPlugin *plugin);
 66 void		org_gnome_evolution_attachment_reminder
 67 					(EPlugin *ep,
 68 					 EMEventTargetComposer *t);
 69 GtkWidget *	org_gnome_attachment_reminder_config_option
 70 					(EPlugin *plugin,
 71 					 EConfigHookItemFactoryData *data);
 72 
 73 static gboolean ask_for_missing_attachment (EPlugin *ep, GtkWindow *widget);
 74 static gboolean check_for_attachment_clues (GByteArray *msg_text);
 75 static gboolean check_for_attachment (EMsgComposer *composer);
 76 static void commit_changes (UIData *ui);
 77 
 78 gint
 79 e_plugin_lib_enable (EPlugin *ep,
 80                      gint enable)
 81 {
 82 	return 0;
 83 }
 84 
 85 void
 86 org_gnome_evolution_attachment_reminder (EPlugin *ep,
 87                                          EMEventTargetComposer *t)
 88 {
 89 	GByteArray *raw_msg_barray;
 90 
 91 	/* no need to check for content, when there are attachments */
 92 	if (check_for_attachment (t->composer))
 93 		return;
 94 
 95 	raw_msg_barray = e_msg_composer_get_raw_message_text (t->composer);
 96 	if (!raw_msg_barray)
 97 		return;
 98 
 99 	/* Set presend_check_status for the composer*/
100 	if (check_for_attachment_clues (raw_msg_barray)) {
101 		if (!ask_for_missing_attachment (ep, (GtkWindow *) t->composer))
102 			g_object_set_data (
103 				G_OBJECT (t->composer),
104 				"presend_check_status",
105 				GINT_TO_POINTER (1));
106 	}
107 
108 	g_byte_array_free (raw_msg_barray, TRUE);
109 }
110 
111 static gboolean
112 ask_for_missing_attachment (EPlugin *ep,
113                             GtkWindow *window)
114 {
115 	GtkWidget *check;
116 	GtkWidget *dialog;
117 	GtkWidget *container;
118 	gint response;
119 
120 	dialog = e_alert_dialog_new_for_args (
121 		window, "org.gnome.evolution.plugins.attachment_reminder:"
122 		"attachment-reminder", NULL);
123 
124 	container = e_alert_dialog_get_content_area (E_ALERT_DIALOG (dialog));
125 
126 	/*Check buttons*/
127 	check = gtk_check_button_new_with_mnemonic (
128 		_("_Do not show this message again."));
129 	gtk_box_pack_start (GTK_BOX (container), check, FALSE, FALSE, 0);
130 	gtk_widget_show (check);
131 
132 	response = gtk_dialog_run (GTK_DIALOG (dialog));
133 
134 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)))
135 		e_plugin_enable (ep, FALSE);
136 
137 	gtk_widget_destroy (dialog);
138 
139 	if (response == GTK_RESPONSE_OK)
140 		gtk_action_activate (E_COMPOSER_ACTION_ATTACH (window));
141 
142 	return response == GTK_RESPONSE_YES;
143 }
144 
145 static gboolean
146 get_next_word (GByteArray *msg_text,
147                guint *from,
148                const gchar **word,
149                guint *wlen)
150 {
151 	gboolean new_line;
152 
153 	g_return_val_if_fail (msg_text != NULL, FALSE);
154 	g_return_val_if_fail (from != NULL, FALSE);
155 	g_return_val_if_fail (word != NULL, FALSE);
156 	g_return_val_if_fail (wlen != NULL, FALSE);
157 
158 	if (*from >= msg_text->len)
159 		return FALSE;
160 
161 	new_line = TRUE;
162 	while (new_line) {
163 		new_line = FALSE;
164 
165 		while (*from < msg_text->len && g_ascii_isspace (msg_text->data[*from])) {
166 			new_line = msg_text->data[*from] == '\n';
167 			*from = (*from) + 1;
168 		}
169 
170 		if (*from >= msg_text->len)
171 			return FALSE;
172 
173 		if (new_line && msg_text->data[*from] == '>') {
174 			/* skip quotation lines */
175 			while (*from < msg_text->len && msg_text->data[*from] != '\n') {
176 				*from = (*from) + 1;
177 			}
178 		} else if (new_line && *from + 3 < msg_text->len &&
179 			   strncmp ((const gchar *) (msg_text->data + (*from)), "-- \n", 4) == 0) {
180 			/* signature delimiter finishes message text */
181 			*from = msg_text->len;
182 			return FALSE;
183 		} else {
184 			new_line = FALSE;
185 		}
186 	}
187 
188 	if (*from >= msg_text->len)
189 		return FALSE;
190 
191 	*word = (const gchar *) (msg_text->data + (*from));
192 	*wlen = 0;
193 
194 	while (*from < msg_text->len && !g_ascii_isspace (msg_text->data[*from])) {
195 		*from = (*from) + 1;
196 		*wlen = (*wlen) + 1;
197 	}
198 
199 	return TRUE;
200 }
201 
202 /* 's1' has s1len bytes of text, while 's2' is NULL-terminated
203  * and *s2len contains how many bytes were read */
204 static gboolean
205 utf8_casencmp (const gchar *s1,
206                guint s1len,
207                const gchar *s2,
208                guint *s2len)
209 {
210 	gunichar u1, u2;
211 	guint u1len, u2len;
212 
213 	if (!s1 || !s2 || !s1len || !s2len)
214 		return FALSE;
215 
216 	*s2len = 0;
217 
218 	while (s1len > 0 && *s1 && *s2) {
219 		u1 = g_utf8_get_char_validated (s1, s1len);
220 		u2 = g_utf8_get_char_validated (s2, -1);
221 
222 		if (u1 == -1 || u1 == -2 || u2 == -1 || u2 == -2)
223 			break;
224 
225 		if (u1 != u2 && g_unichar_tolower (u1) != g_unichar_tolower (u2))
226 			break;
227 
228 		u1len = g_unichar_to_utf8 (u1, NULL);
229 		if (s1len < u1len)
230 			break;
231 
232 		u2len = g_unichar_to_utf8 (u2, NULL);
233 
234 		s1len -= u1len;
235 		s1 += u1len;
236 		*s2len = (*s2len) + u2len;
237 		s2 += u2len;
238 	}
239 
240 	return s1len == 0;
241 }
242 
243 /* check for the clues */
244 static gboolean
245 check_for_attachment_clues (GByteArray *msg_text)
246 {
247 	GSettings *settings;
248 	gchar **clue_list;
249 	gboolean found = FALSE;
250 
251 	settings = g_settings_new ("org.gnome.evolution.plugin.attachment-reminder");
252 
253 	/* Get the list from GSettings */
254 	clue_list = g_settings_get_strv (settings, CONF_KEY_ATTACH_REMINDER_CLUES);
255 
256 	g_object_unref (settings);
257 
258 	if (clue_list && clue_list[0]) {
259 		gint ii;
260 		guint from = 0, wlen = 0, clen = 0;
261 		const gchar *word = NULL;
262 
263 		while (!found && get_next_word (msg_text, &from, &word, &wlen)) {
264 			for (ii = 0; !found && clue_list[ii] != NULL; ii++) {
265 				const gchar *clue = clue_list[ii];
266 
267 				if (utf8_casencmp (word, wlen, clue, &clen)) {
268 					found = clue[clen] == 0;
269 
270 					if (!found && g_ascii_isspace (clue[clen])) {
271 						/* clue is a multi-word, then test more words */
272 						guint bfrom = from, blen = 0;
273 						const gchar *bword = NULL;
274 
275 						clue = clue + clen;
276 						while (*clue && g_ascii_isspace (*clue))
277 							clue++;
278 
279 						found = !*clue;
280 						if (!found) {
281 							found = TRUE;
282 
283 							while (found && get_next_word (msg_text, &bfrom, &bword, &blen)) {
284 								found = FALSE;
Value stored to 'found' is never read
(emitted by clang-analyzer)

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

Value stored to 'found' is never read
(emitted by clang-analyzer)

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

285 286 if (utf8_casencmp (bword, blen, clue, &clen)) { 287 found = clue[clen] == 0; 288 if (found) { 289 clue = clue + clen; 290 break; 291 } else if (g_ascii_isspace (clue[clen])) { 292 /* another word in clue */ 293 found = TRUE; 294 295 clue = clue + clen; 296 while (*clue && g_ascii_isspace (*clue)) 297 clue++; 298 } 299 } else { 300 found = FALSE; 301 } 302 } 303 304 found = found && !*clue; 305 } 306 } 307 } 308 } 309 } 310 } 311 312 if (clue_list) { 313 g_strfreev (clue_list); 314 } 315 316 return found; 317 } 318 319 /* check for the any attachment */ 320 static gboolean 321 check_for_attachment (EMsgComposer *composer) 322 { 323 EAttachmentView *view; 324 EAttachmentStore *store; 325 326 view = e_msg_composer_get_attachment_view (composer); 327 store = e_attachment_view_get_store (view); 328 329 return (e_attachment_store_get_num_attachments (store) > 0); 330 } 331 332 static void 333 commit_changes (UIData *ui) 334 { 335 GtkTreeModel *model = NULL; 336 GVariantBuilder b; 337 GVariant *v; 338 GtkTreeIter iter; 339 gboolean valid; 340 341 model = gtk_tree_view_get_model (GTK_TREE_VIEW (ui->treeview)); 342 valid = gtk_tree_model_get_iter_first (model, &iter); 343 344 g_variant_builder_init (&b, G_VARIANT_TYPE ("as")); 345 while (valid) { 346 gchar *keyword; 347 348 gtk_tree_model_get ( 349 model, &iter, CLUE_KEYWORD_COLUMN, &keyword, -1); 350 351 /* Check if the keyword is not empty */ 352 if ((keyword) && (g_utf8_strlen (g_strstrip (keyword), -1) > 0)) 353 g_variant_builder_add (&b, "s", keyword); 354 g_free (keyword); 355 356 valid = gtk_tree_model_iter_next (model, &iter); 357 } 358 359 v = g_variant_builder_end (&b); 360 g_settings_set_value (ui->settings, CONF_KEY_ATTACH_REMINDER_CLUES, v); 361 362 g_variant_unref (v); 363 } 364 365 static void 366 cell_edited_cb (GtkCellRendererText *cell, 367 gchar *path_string, 368 gchar *new_text, 369 UIData *ui) 370 { 371 GtkTreeModel *model; 372 GtkTreeIter iter; 373 374 model = gtk_tree_view_get_model (GTK_TREE_VIEW (ui->treeview)); 375 gtk_tree_model_get_iter_from_string (model, &iter, path_string); 376 377 if (new_text == NULL || *g_strstrip (new_text) == '\0') 378 gtk_button_clicked (GTK_BUTTON (ui->clue_remove)); 379 else { 380 gtk_list_store_set ( 381 GTK_LIST_STORE (model), &iter, 382 CLUE_KEYWORD_COLUMN, new_text, -1); 383 commit_changes (ui); 384 } 385 } 386 387 static void 388 cell_editing_canceled_cb (GtkCellRenderer *cell, 389 UIData *ui) 390 { 391 gtk_button_clicked (GTK_BUTTON (ui->clue_remove)); 392 } 393 394 static void 395 clue_add_clicked (GtkButton *button, 396 UIData *ui) 397 { 398 GtkTreeModel *model; 399 GtkTreeView *tree_view; 400 GtkTreeViewColumn *column; 401 GtkTreePath *path; 402 GtkTreeIter iter; 403 404 tree_view = GTK_TREE_VIEW (ui->treeview); 405 model = gtk_tree_view_get_model (tree_view); 406 407 gtk_list_store_append (GTK_LIST_STORE (model), &iter); 408 409 path = gtk_tree_model_get_path (model, &iter); 410 column = gtk_tree_view_get_column (tree_view, CLUE_KEYWORD_COLUMN); 411 gtk_tree_view_set_cursor (tree_view, path, column, TRUE); 412 gtk_tree_view_row_activated (tree_view, path, column); 413 gtk_tree_path_free (path); 414 } 415 416 static void 417 clue_remove_clicked (GtkButton *button, 418 UIData *ui) 419 { 420 GtkTreeSelection *selection; 421 GtkTreeModel *model; 422 GtkTreeIter iter; 423 GtkTreePath *path; 424 gboolean valid; 425 gint len; 426 427 valid = FALSE; 428 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); 429 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) 430 return; 431 432 /* Get the path and move to the previous node :) */ 433 path = gtk_tree_model_get_path (model, &iter); 434 if (path) 435 valid = gtk_tree_path_prev (path); 436 437 gtk_list_store_remove (GTK_LIST_STORE (model), &iter); 438 439 len = gtk_tree_model_iter_n_children (model, NULL); 440 if (len > 0) { 441 if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (model), &iter)) { 442 gtk_tree_selection_select_iter (selection, &iter); 443 } else { 444 if (path && valid) { 445 gtk_tree_model_get_iter (model, &iter, path); 446 gtk_tree_selection_select_iter (selection, &iter); 447 } 448 } 449 } else { 450 gtk_widget_set_sensitive (ui->clue_edit, FALSE); 451 gtk_widget_set_sensitive (ui->clue_remove, FALSE); 452 } 453 454 gtk_widget_grab_focus (ui->treeview); 455 gtk_tree_path_free (path); 456 457 commit_changes (ui); 458 } 459 460 static void 461 clue_edit_clicked (GtkButton *button, 462 UIData *ui) 463 { 464 GtkTreeSelection *selection; 465 GtkTreeModel *model; 466 GtkTreePath *path; 467 GtkTreeIter iter; 468 GtkTreeViewColumn *focus_col; 469 470 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); 471 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) 472 return; 473 474 focus_col = gtk_tree_view_get_column ( 475 GTK_TREE_VIEW (ui->treeview), CLUE_KEYWORD_COLUMN); 476 path = gtk_tree_model_get_path (model, &iter); 477 478 if (path) { 479 gtk_tree_view_set_cursor ( 480 GTK_TREE_VIEW (ui->treeview), 481 path, focus_col, TRUE); 482 gtk_tree_path_free (path); 483 } 484 } 485 486 static void 487 selection_changed (GtkTreeSelection *selection, 488 UIData *ui) 489 { 490 GtkTreeModel *model; 491 GtkTreeIter iter; 492 493 if (gtk_tree_selection_get_selected (selection, &model, &iter)) { 494 gtk_widget_set_sensitive (ui->clue_edit, TRUE); 495 gtk_widget_set_sensitive (ui->clue_remove, TRUE); 496 } else { 497 gtk_widget_set_sensitive (ui->clue_edit, FALSE); 498 gtk_widget_set_sensitive (ui->clue_remove, FALSE); 499 } 500 } 501 502 static void 503 destroy_ui_data (gpointer data) 504 { 505 UIData *ui = (UIData *) data; 506 507 if (!ui) 508 return; 509 510 g_object_unref (ui->settings); 511 g_free (ui); 512 } 513 514 GtkWidget * 515 e_plugin_lib_get_configure_widget (EPlugin *plugin) 516 { 517 GtkCellRenderer *renderer; 518 GtkTreeSelection *selection; 519 GtkTreeIter iter; 520 GtkWidget *hbox; 521 gchar **clue_list; 522 gint i; 523 524 GtkWidget *reminder_configuration_box; 525 GtkWidget *clue_container; 526 GtkWidget *scrolledwindow1; 527 GtkWidget *clue_treeview; 528 GtkWidget *vbuttonbox2; 529 GtkWidget *clue_add; 530 GtkWidget *clue_edit; 531 GtkWidget *clue_remove; 532 533 UIData *ui = g_new0 (UIData, 1); 534 535 reminder_configuration_box = gtk_vbox_new (FALSE, 6); 536 gtk_widget_show (reminder_configuration_box); 537 gtk_widget_set_size_request (reminder_configuration_box, 385, 189); 538 539 clue_container = gtk_hbox_new (FALSE, 12); 540 gtk_widget_show (clue_container); 541 gtk_box_pack_start ( 542 GTK_BOX (reminder_configuration_box), 543 clue_container, TRUE, TRUE, 0); 544 545 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); 546 gtk_widget_show (scrolledwindow1); 547 gtk_box_pack_start (GTK_BOX (clue_container), scrolledwindow1, TRUE, TRUE, 0); 548 gtk_scrolled_window_set_policy ( 549 GTK_SCROLLED_WINDOW (scrolledwindow1), 550 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 551 552 clue_treeview = gtk_tree_view_new (); 553 gtk_widget_show (clue_treeview); 554 gtk_container_add (GTK_CONTAINER (scrolledwindow1), clue_treeview); 555 gtk_container_set_border_width (GTK_CONTAINER (clue_treeview), 1); 556 557 vbuttonbox2 = gtk_vbutton_box_new (); 558 gtk_widget_show (vbuttonbox2); 559 gtk_box_pack_start (GTK_BOX (clue_container), vbuttonbox2, FALSE, TRUE, 0); 560 gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox2), GTK_BUTTONBOX_START); 561 gtk_box_set_spacing (GTK_BOX (vbuttonbox2), 6); 562 563 clue_add = gtk_button_new_from_stock ("gtk-add"); 564 gtk_widget_show (clue_add); 565 gtk_container_add (GTK_CONTAINER (vbuttonbox2), clue_add); 566 gtk_widget_set_can_default (clue_add, TRUE); 567 568 clue_edit = gtk_button_new_from_stock ("gtk-edit"); 569 gtk_widget_show (clue_edit); 570 gtk_container_add (GTK_CONTAINER (vbuttonbox2), clue_edit); 571 gtk_widget_set_can_default (clue_edit, TRUE); 572 573 clue_remove = gtk_button_new_from_stock ("gtk-remove"); 574 gtk_widget_show (clue_remove); 575 gtk_container_add (GTK_CONTAINER (vbuttonbox2), clue_remove); 576 gtk_widget_set_can_default (clue_remove, TRUE); 577 578 ui->settings = g_settings_new ("org.gnome.evolution.plugin.attachment-reminder"); 579 580 ui->treeview = clue_treeview; 581 582 ui->store = gtk_list_store_new (CLUE_N_COLUMNS, G_TYPE_STRING); 583 584 gtk_tree_view_set_model ( 585 GTK_TREE_VIEW (ui->treeview), 586 GTK_TREE_MODEL (ui->store)); 587 588 renderer = gtk_cell_renderer_text_new (); 589 gtk_tree_view_insert_column_with_attributes ( 590 GTK_TREE_VIEW (ui->treeview), -1, _("Keywords"), 591 renderer, "text", CLUE_KEYWORD_COLUMN, NULL); 592 g_object_set (renderer, "editable", TRUE, NULL); 593 g_signal_connect ( 594 renderer, "edited", 595 G_CALLBACK (cell_edited_cb), ui); 596 g_signal_connect ( 597 renderer, "editing-canceled", 598 G_CALLBACK (cell_editing_canceled_cb), ui); 599 600 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->treeview)); 601 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); 602 g_signal_connect ( 603 selection, "changed", 604 G_CALLBACK (selection_changed), ui); 605 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ui->treeview), TRUE); 606 607 ui->clue_add = clue_add; 608 g_signal_connect ( 609 ui->clue_add, "clicked", 610 G_CALLBACK (clue_add_clicked), ui); 611 612 ui->clue_remove = clue_remove; 613 g_signal_connect ( 614 ui->clue_remove, "clicked", 615 G_CALLBACK (clue_remove_clicked), ui); 616 gtk_widget_set_sensitive (ui->clue_remove, FALSE); 617 618 ui->clue_edit = clue_edit; 619 g_signal_connect ( 620 ui->clue_edit, "clicked", 621 G_CALLBACK (clue_edit_clicked), ui); 622 gtk_widget_set_sensitive (ui->clue_edit, FALSE); 623 624 /* Populate tree view with values from GSettings */ 625 clue_list = g_settings_get_strv (ui->settings, CONF_KEY_ATTACH_REMINDER_CLUES); 626 627 for (i = 0; clue_list[i] != NULL; i++) { 628 gtk_list_store_append (ui->store, &iter); 629 gtk_list_store_set (ui->store, &iter, CLUE_KEYWORD_COLUMN, clue_list[i], -1); 630 } 631 632 if (clue_list) { 633 g_strfreev (clue_list); 634 } 635 636 /* Add the list here */ 637 638 hbox = gtk_vbox_new (FALSE, 0); 639 640 gtk_box_pack_start (GTK_BOX (hbox), reminder_configuration_box, TRUE, TRUE, 0); 641 642 /* to let free data properly on destroy of configuration widget */ 643 g_object_set_data_full (G_OBJECT (hbox), "myui-data", ui, destroy_ui_data); 644 645 return hbox; 646 } 647 648 /* Configuration in Mail Prefs Page goes here */ 649 650 GtkWidget * 651 org_gnome_attachment_reminder_config_option (EPlugin *plugin, 652 struct _EConfigHookItemFactoryData *data) 653 { 654 /* This function and the hook needs to be removed, 655 once the configure code is thoroughly tested */ 656 657 return NULL; 658 659 }