1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  * Copyright (C) 2004 Roberto Majadas
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more av.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301  USA.
20  *
21  * Author:  Roberto Majadas <roberto.majadas@openshine.com>
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <glib/gstdio.h>
33 #include <gtk/gtk.h>
34 #include "caja-sendto-plugin.h"
35 
36 #define CAJA_SENDTO_LAST_MEDIUM	"last-medium"
37 #define CAJA_SENDTO_LAST_COMPRESS	"last-compress"
38 #define CAJA_SENDTO_STATUS_LABEL_TIMEOUT_SECONDS 10
39 
40 #define UNINSTALLED_PLUGINDIR "plugins/removable-devices"
41 
42 #define SOEXT           ("." G_MODULE_SUFFIX)
43 
44 enum {
45 	COLUMN_ICON,
46 	COLUMN_DESCRIPTION,
47 	NUM_COLUMNS,
48 };
49 
50 /* Options */
51 static char **filenames = NULL;
52 
53 GList *file_list = NULL;
54 gboolean has_dirs = FALSE;
55 GList *plugin_list = NULL;
56 GHashTable *hash ;
57 guint option = 0;
58 
59 static GSettings *settings = NULL;
60 
61 typedef struct _NS_ui NS_ui;
62 
63 struct _NS_ui {
64 	GtkWidget *dialog;
65 	GtkWidget *options_combobox;
66 	GtkWidget *send_to_label;
67 	GtkWidget *hbox_contacts_ws;
68 	GtkWidget *cancel_button;
69 	GtkWidget *send_button;
70 	GtkWidget *pack_combobox;
71 	GtkWidget *pack_checkbutton;
72 	GtkWidget *pack_entry;
73 	GList *contact_widgets;
74 
75 	GtkWidget *status_box;
76 	GtkWidget *status_image;
77 	GtkWidget *status_label;
78 	guint status_timeoutid;
79 };
80 
81 static const GOptionEntry entries[] = {
82 	{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, "Files to send", "[FILES...]" },
83 	{ NULL }
84 };
85 
86 static void
destroy_dialog(GtkWidget * widget,gpointer data)87 destroy_dialog (GtkWidget *widget, gpointer data )
88 {
89         gtk_main_quit ();
90 }
91 
92 static char *
get_filename_from_list(void)93 get_filename_from_list (void)
94 {
95 	GList *l;
96 	GString *common_part = NULL;
97 	gboolean matches = TRUE;
98 	guint offset = 0;
99 	const char *encoding;
100 	gboolean use_utf8 = TRUE;
101 
102 	encoding = g_getenv ("G_FILENAME_ENCODING");
103 
104 	if (encoding != NULL && strcasecmp(encoding, "UTF-8") != 0)
105 		use_utf8 = FALSE;
106 
107 	if (file_list == NULL)
108 		return NULL;
109 
110 	common_part = g_string_new("");
111 
112 	while (TRUE) {
113 		gunichar cur_char = '\0';
114 		for (l = file_list; l ; l = l->next) {
115 			char *path = NULL, *name = NULL;
116 			char *offset_name = NULL;
117 
118 			path = g_filename_from_uri ((char *) l->data,
119 					NULL, NULL);
120 			if (!path)
121 				break;
122 
123 			name = g_path_get_basename (path);
124 
125 			if (!use_utf8) {
126 				char *tmp;
127 
128 				tmp = g_filename_to_utf8 (name, -1,
129 						NULL, NULL, NULL);
130 				g_free (name);
131 				name = tmp;
132 			}
133 
134 			if (!name) {
135 				g_free (path);
136 				break;
137 			}
138 
139 			if (offset >= g_utf8_strlen (name, -1)) {
140 				g_free(name);
141 				g_free(path);
142 				matches = FALSE;
143 				break;
144 			}
145 
146 			offset_name = g_utf8_offset_to_pointer (name, offset);
147 
148 			if (offset_name == g_utf8_strrchr (name, -1, '.')) {
149 				g_free (name);
150 				g_free (path);
151 				matches = FALSE;
152 				break;
153 			}
154 			if (cur_char == '\0') {
155 				cur_char = g_utf8_get_char (offset_name);
156 			} else if (cur_char != g_utf8_get_char (offset_name)) {
157 				g_free (name);
158 				g_free (path);
159 				matches = FALSE;
160 				break;
161 			}
162 			g_free (name);
163 			g_free (path);
164 		}
165 		if (matches == TRUE && cur_char != '\0') {
166 			offset++;
167 			common_part = g_string_append_unichar (common_part,
168 					cur_char);
169 		} else {
170 			break;
171 		}
172 	}
173 
174 	if (g_utf8_strlen (common_part->str, -1) < 4) {
175 		g_string_free (common_part, TRUE);
176 		return NULL;
177 	}
178 
179 	return g_string_free (common_part, FALSE);
180 }
181 
182 static char *
pack_files(NS_ui * ui)183 pack_files (NS_ui *ui)
184 {
185 	char *engrampa_cmd;
186 	const char *filename;
187 	GList *l;
188 	GString *cmd, *tmp;
189 	char *pack_type, *tmp_dir, *tmp_work_dir, *packed_file;
190 
191 	engrampa_cmd = g_find_program_in_path ("engrampa");
192 	filename = gtk_entry_get_text(GTK_ENTRY(ui->pack_entry));
193 
194 	g_assert (filename != NULL && *filename != '\0');
195 
196 	tmp_dir = g_strdup_printf ("%s/caja-sendto-%s",
197 				   g_get_tmp_dir(), g_get_user_name());
198 	g_mkdir (tmp_dir, 0700);
199 	tmp_work_dir = g_strdup_printf ("%s/caja-sendto-%s/%li",
200 					g_get_tmp_dir(), g_get_user_name(),
201 					time(NULL));
202 	g_mkdir (tmp_work_dir, 0700);
203 	g_free (tmp_dir);
204 
205 	if (gtk_combo_box_get_active (GTK_COMBO_BOX(ui->pack_combobox)) != 0) {
206 		pack_type = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(ui->pack_combobox));
207 	} else {
208 		pack_type = NULL;
209 		g_assert_not_reached ();
210 	}
211 
212 	g_settings_set_int (settings,
213 			    CAJA_SENDTO_LAST_COMPRESS,
214 			    gtk_combo_box_get_active(GTK_COMBO_BOX(ui->pack_combobox)));
215 
216 	cmd = g_string_new ("");
217 	g_string_printf (cmd, "%s --add-to=\"%s/%s%s\"",
218 			 engrampa_cmd, tmp_work_dir,
219 			 filename,
220 			 pack_type);
221 	g_free (engrampa_cmd);
222 
223 	/* engrampa doesn't understand URIs */
224 	for (l = file_list ; l; l=l->next){
225 		char *file;
226 
227 		file = g_filename_from_uri (l->data, NULL, NULL);
228 		g_string_append_printf (cmd," \"%s\"", file);
229 		g_free (file);
230 	}
231 
232 	g_spawn_command_line_sync (cmd->str, NULL, NULL, NULL, NULL);
233 	g_string_free (cmd, TRUE);
234 	tmp = g_string_new("");
235 	g_string_printf (tmp,"%s/%s%s", tmp_work_dir,
236 			 filename,
237 			 pack_type);
238 	g_free (pack_type);
239 	g_free (tmp_work_dir);
240 	packed_file = g_filename_to_uri (tmp->str, NULL, NULL);
241 	g_string_free(tmp, TRUE);
242 	return packed_file;
243 }
244 
245 static gboolean
status_label_clear(gpointer data)246 status_label_clear (gpointer data)
247 {
248 	NS_ui *ui = (NS_ui *) data;
249 	gtk_label_set_label (GTK_LABEL (ui->status_label), "");
250 	gtk_widget_hide (ui->status_image);
251 
252 	ui->status_timeoutid = 0;
253 
254 	return FALSE;
255 }
256 
257 static void
send_button_cb(GtkWidget * widget,NS_ui * ui)258 send_button_cb (GtkWidget *widget, NS_ui *ui)
259 {
260 	char *error;
261 	NstPlugin *p;
262 	GtkWidget *w;
263 
264 	gtk_widget_set_sensitive (ui->dialog, FALSE);
265 
266 	p = (NstPlugin *) g_list_nth_data (plugin_list, option);
267 	w = (GtkWidget *) g_list_nth_data (ui->contact_widgets, option);
268 
269 	if (ui->status_timeoutid != 0) {
270 		g_source_remove (ui->status_timeoutid);
271 		status_label_clear (ui);
272 	}
273 
274 	if (p == NULL)
275 		return;
276 
277 	if (p->info->validate_destination != NULL) {
278 		error = NULL;
279 		if (p->info->validate_destination (p, w, &error) == FALSE) {
280 			char *message;
281 
282 			message = g_strdup_printf ("<b>%s</b>", error);
283 			g_free (error);
284 			gtk_label_set_markup (GTK_LABEL (ui->status_label), message);
285 			g_free (message);
286 			ui->status_timeoutid = g_timeout_add_seconds (CAJA_SENDTO_STATUS_LABEL_TIMEOUT_SECONDS,
287 								      status_label_clear,
288 								      ui);
289 			gtk_widget_show (ui->status_image);
290 			gtk_widget_show (ui->status_box);
291 			gtk_widget_set_sensitive (ui->dialog, TRUE);
292 			return;
293 		}
294 	}
295 
296 	g_settings_set_string (settings,
297 			       CAJA_SENDTO_LAST_MEDIUM,
298 			       p->info->id);
299 
300 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui->pack_checkbutton))){
301 		char *f;
302 
303 		f = pack_files (ui);
304 		if (f != NULL) {
305 			GList *packed_file = NULL;
306 			packed_file = g_list_append (packed_file, f);
307 			if (!p->info->send_files (p, w, packed_file)) {
308 				g_free (f);
309 				g_list_free (packed_file);
310 				return;
311 			}
312 			g_list_free (packed_file);
313 		} else {
314 			gtk_widget_set_sensitive (ui->dialog, TRUE);
315 			return;
316 		}
317 		g_free (f);
318 	} else {
319 		if (!p->info->send_files (p, w, file_list)) {
320 			g_list_free_full (file_list, g_free);
321 			file_list = NULL;
322 			return;
323 		}
324 		g_list_free (file_list);
325 		file_list = NULL;
326 	}
327 	destroy_dialog (NULL,NULL);
328 }
329 
330 static void
send_if_no_pack_cb(GtkWidget * widget,NS_ui * ui)331 send_if_no_pack_cb (GtkWidget *widget, NS_ui *ui)
332 {
333 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton))) {
334 		if (gtk_widget_is_sensitive (ui->pack_entry)) {
335 			gtk_widget_grab_focus (ui->pack_entry);
336 		} else {
337 			gtk_widget_grab_focus (ui->pack_checkbutton);
338 		}
339 	} else {
340 		send_button_cb (widget, ui);
341 	}
342 }
343 
344 static void
toggle_pack_check(GtkWidget * widget,NS_ui * ui)345 toggle_pack_check (GtkWidget *widget, NS_ui *ui)
346 {
347 	GtkToggleButton *t = GTK_TOGGLE_BUTTON (widget);
348 	gboolean enabled, send_enabled;
349 
350 	enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (t));
351 	gtk_widget_set_sensitive (ui->pack_combobox, enabled);
352 	gtk_widget_set_sensitive (ui->pack_entry, enabled);
353 
354 	send_enabled = TRUE;
355 
356 	if (enabled) {
357 		const char *filename;
358 
359 		filename = gtk_entry_get_text(GTK_ENTRY(ui->pack_entry));
360 		if (filename == NULL || *filename == '\0')
361 			send_enabled = FALSE;
362 	}
363 
364 	gtk_widget_set_sensitive (ui->send_button, send_enabled);
365 }
366 
367 static void
option_changed(GtkComboBox * cb,NS_ui * ui)368 option_changed (GtkComboBox *cb, NS_ui *ui)
369 {
370 	GtkWidget *w;
371 	NstPlugin *p;
372 	gboolean supports_dirs = FALSE;
373 
374 	w = g_list_nth_data (ui->contact_widgets, option);
375 	option = gtk_combo_box_get_active (GTK_COMBO_BOX(cb));
376 	gtk_widget_hide (w);
377 	w = g_list_nth_data (ui->contact_widgets, option);
378 	gtk_widget_show (w);
379 
380 	gtk_label_set_mnemonic_widget (GTK_LABEL (ui->send_to_label), w);
381 
382 	p = (NstPlugin *) g_list_nth_data (plugin_list, option);
383 	supports_dirs = (p->info->capabilities & CAJA_CAPS_SEND_DIRECTORIES);
384 
385 	if (has_dirs == FALSE || supports_dirs != FALSE) {
386 		gboolean toggle;
387 
388 		toggle = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton));
389 		gtk_widget_set_sensitive (ui->pack_combobox, toggle);
390 		gtk_widget_set_sensitive (ui->pack_entry, toggle);
391 		gtk_widget_set_sensitive (ui->pack_checkbutton, TRUE);
392 	} else {
393 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton), TRUE);
394 		gtk_widget_set_sensitive (ui->pack_checkbutton, FALSE);
395 	}
396 }
397 
398 static void
set_contact_widgets(NS_ui * ui)399 set_contact_widgets (NS_ui *ui)
400 {
401 	GList *aux ;
402 	GtkWidget *w;
403 	NstPlugin *p;
404 
405 	ui->contact_widgets = NULL;
406 
407 	for (aux = plugin_list; aux; aux = aux->next){
408 		p = (NstPlugin *) aux->data;
409 		w = p->info->get_contacts_widget(p);
410 		gtk_box_pack_end (GTK_BOX(ui->hbox_contacts_ws),w, TRUE, TRUE, 0);
411 		gtk_widget_hide (GTK_WIDGET(w));
412 		ui->contact_widgets = g_list_append (ui->contact_widgets, w);
413 		if (GTK_IS_ENTRY (w)) {
414 			g_signal_connect_after (G_OBJECT (w), "activate",
415 						G_CALLBACK (send_if_no_pack_cb), ui);
416 		}
417 	}
418 }
419 
420 static gboolean
set_model_for_options_combobox(NS_ui * ui)421 set_model_for_options_combobox (NS_ui *ui)
422 {
423 	GdkPixbuf *pixbuf;
424         GtkTreeIter iter;
425         GtkListStore *model;
426 	GtkIconTheme *it;
427 	GtkCellRenderer *renderer;
428 	GtkWidget *widget;
429 	GList *aux;
430 	NstPlugin *p;
431 	char *last_used = NULL;
432 	int i = 0;
433 	gboolean last_used_support_dirs = FALSE;
434 
435 	it = gtk_icon_theme_get_default ();
436 
437 	model = gtk_list_store_new (NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
438 
439 	last_used = g_settings_get_string (settings,
440 					   CAJA_SENDTO_LAST_MEDIUM);
441 
442 	for (aux = plugin_list; aux; aux = aux->next) {
443 		p = (NstPlugin *) aux->data;
444 		pixbuf = gtk_icon_theme_load_icon (it, p->info->icon, 16,
445 						   GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
446 		gtk_list_store_append (model, &iter);
447 		gtk_list_store_set (model, &iter,
448 		                    COLUMN_ICON, pixbuf,
449 #ifdef ENABLE_NLS
450 		                    COLUMN_DESCRIPTION, g_dgettext (p->info->gettext_package, p->info->description),
451 #else
452 		                    COLUMN_DESCRIPTION, p->info->description,
453 #endif /* ENABLE_NLS */
454 		                    -1);
455 		if (last_used != NULL && !strcmp(last_used, p->info->id)) {
456 			option = i;
457 			last_used_support_dirs = (p->info->capabilities & CAJA_CAPS_SEND_DIRECTORIES);
458 		}
459 		i++;
460 	}
461 	g_free(last_used);
462 
463 	gtk_combo_box_set_model (GTK_COMBO_BOX(ui->options_combobox),
464 				GTK_TREE_MODEL (model));
465 	renderer = gtk_cell_renderer_pixbuf_new ();
466         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->options_combobox),
467                                     renderer,
468                                     FALSE);
469         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (ui->options_combobox),
470 					renderer,
471                                         "pixbuf", COLUMN_ICON,
472                                         NULL);
473         renderer = gtk_cell_renderer_text_new ();
474         g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
475         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->options_combobox),
476                                     renderer,
477                                     TRUE);
478         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (ui->options_combobox),
479 					renderer,
480                                         "text", COLUMN_DESCRIPTION,
481                                         NULL);
482 
483 	g_signal_connect (G_OBJECT (ui->options_combobox), "changed",
484 			  G_CALLBACK (option_changed), ui);
485 
486 	gtk_combo_box_set_active (GTK_COMBO_BOX (ui->options_combobox), option);
487 
488 	/* Grab the focus for the most recently used widget */
489 	widget = g_list_nth_data (ui->contact_widgets, option);
490 	gtk_widget_grab_focus (widget);
491 
492 	return last_used_support_dirs;
493 }
494 
495 static void
pack_entry_changed_cb(GObject * object,GParamSpec * spec,NS_ui * ui)496 pack_entry_changed_cb (GObject *object, GParamSpec *spec, NS_ui *ui)
497 {
498 	gboolean send_enabled;
499 
500 	send_enabled = TRUE;
501 
502 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton))) {
503 		const char *filename;
504 
505 		filename = gtk_entry_get_text(GTK_ENTRY(ui->pack_entry));
506 		if (filename == NULL || *filename == '\0')
507 			send_enabled = FALSE;
508 	}
509 
510 	gtk_widget_set_sensitive (ui->send_button, send_enabled);
511 }
512 
513 static void
update_button_image(GtkSettings * gtk_settings,GParamSpec * spec,GtkWidget * widget)514 update_button_image (GtkSettings *gtk_settings,
515                      GParamSpec  *spec,
516                      GtkWidget   *widget)
517 {
518 	gboolean show_images;
519 
520 	g_object_get (gtk_settings, "gtk-button-images", &show_images, NULL);
521 	if (show_images == FALSE)
522 		gtk_widget_hide (widget);
523 	else
524 		gtk_widget_show (widget);
525 }
526 
527 static void
caja_sendto_create_ui(void)528 caja_sendto_create_ui (void)
529 {
530 	GtkBuilder *builder;
531 	GError* error = NULL;
532 	NS_ui *ui;
533 	gboolean one_file = FALSE;
534 	gboolean supports_dirs;
535 	GtkSettings *gtk_settings;
536 	GtkWidget *button_image;
537 
538 	builder = gtk_builder_new ();
539 	if (gtk_builder_add_from_resource (builder, "/org/mate/caja/extensions/sendto/caja-sendto.ui", &error) == 0) {
540 		g_warning ("Could not parse UI definition: %s", error->message);
541 		g_error_free (error);
542 	}
543 
544 	ui = g_new0 (NS_ui, 1);
545 
546 	ui->hbox_contacts_ws = GTK_WIDGET (gtk_builder_get_object (builder, "hbox_contacts_widgets"));
547 	ui->send_to_label = GTK_WIDGET (gtk_builder_get_object (builder, "send_to_label"));
548 	ui->options_combobox = GTK_WIDGET (gtk_builder_get_object (builder, "options_combobox"));
549 	ui->dialog = GTK_WIDGET (gtk_builder_get_object (builder, "caja_sendto_dialog"));
550 	ui->cancel_button = GTK_WIDGET (gtk_builder_get_object (builder, "cancel_button"));
551 	ui->send_button = GTK_WIDGET (gtk_builder_get_object (builder, "send_button"));
552 	ui->pack_combobox = GTK_WIDGET (gtk_builder_get_object (builder, "pack_combobox"));
553 	ui->pack_entry = GTK_WIDGET (gtk_builder_get_object (builder, "pack_entry"));
554 	ui->pack_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder, "pack_checkbutton"));
555 	ui->status_box = GTK_WIDGET (gtk_builder_get_object (builder, "status_box"));
556 	ui->status_label = GTK_WIDGET (gtk_builder_get_object (builder, "status_label"));
557 	ui->status_image = GTK_WIDGET (gtk_builder_get_object (builder, "status_image"));
558 
559 	gtk_settings = gtk_settings_get_default ();
560 	button_image = GTK_WIDGET (gtk_builder_get_object (builder, "image1"));
561 	g_signal_connect (G_OBJECT (gtk_settings), "notify::gtk-button-images",
562 			  G_CALLBACK (update_button_image), button_image);
563 	update_button_image (gtk_settings, NULL, button_image);
564 
565 	gtk_combo_box_set_active (GTK_COMBO_BOX(ui->pack_combobox),
566 				  g_settings_get_int (settings,
567 						      CAJA_SENDTO_LAST_COMPRESS));
568 
569 	if (file_list != NULL && file_list->next != NULL)
570 		one_file = FALSE;
571 	else if (file_list != NULL)
572 		one_file = TRUE;
573 
574 	gtk_entry_set_text (GTK_ENTRY (ui->pack_entry), _("Files"));
575 
576 	if (one_file) {
577 		char *filepath = NULL, *filename = NULL;
578 
579 		filepath = g_filename_from_uri ((char *)file_list->data,
580 				NULL, NULL);
581 
582 		if (filepath != NULL)
583 			filename = g_path_get_basename (filepath);
584 		if (filename != NULL && filename[0] != '\0')
585 			gtk_entry_set_text (GTK_ENTRY (ui->pack_entry), filename);
586 
587 		g_free (filename);
588 		g_free (filepath);
589 	} else {
590 		char *filename = get_filename_from_list ();
591 		if (filename != NULL && filename[0] != '\0') {
592 			gtk_entry_set_text (GTK_ENTRY (ui->pack_entry),
593 					filename);
594 		}
595 		g_free (filename);
596 	}
597 
598 	set_contact_widgets (ui);
599 	supports_dirs = set_model_for_options_combobox (ui);
600 	g_signal_connect (G_OBJECT (ui->dialog), "destroy",
601                           G_CALLBACK (destroy_dialog), NULL);
602 	g_signal_connect (G_OBJECT (ui->cancel_button), "clicked",
603 			  G_CALLBACK (destroy_dialog), NULL);
604 	g_signal_connect (G_OBJECT (ui->send_button), "clicked",
605 			  G_CALLBACK (send_button_cb), ui);
606 	g_signal_connect (G_OBJECT (ui->pack_entry), "activate",
607 			  G_CALLBACK (send_button_cb), ui);
608 	g_signal_connect (G_OBJECT (ui->pack_entry), "notify::text",
609 			  G_CALLBACK (pack_entry_changed_cb), ui);
610 	g_signal_connect (G_OBJECT (ui->pack_checkbutton), "toggled",
611 			  G_CALLBACK (toggle_pack_check), ui);
612 
613 	g_object_unref (builder);
614 
615 	if (has_dirs == FALSE || supports_dirs != FALSE) {
616 		gboolean toggle;
617 
618 		toggle = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton));
619 		gtk_widget_set_sensitive (ui->pack_combobox, toggle);
620 		gtk_widget_set_sensitive (ui->pack_entry, toggle);
621 	} else {
622 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ui->pack_checkbutton), TRUE);
623 		gtk_widget_set_sensitive (ui->pack_checkbutton, FALSE);
624 	}
625 
626 	gtk_widget_show (ui->dialog);
627 
628 }
629 
630 static void
caja_sendto_plugin_dir_process(const char * plugindir)631 caja_sendto_plugin_dir_process (const char *plugindir)
632 {
633 	GDir *dir;
634 	const char *item;
635 	NstPlugin *p = NULL;
636 	gboolean (*nst_init_plugin)(NstPlugin *p);
637 	GError *err = NULL;
638 
639 	dir = g_dir_open (plugindir, 0, &err);
640 
641 	if (dir == NULL) {
642 		g_warning ("Can't open the plugins dir: %s", err ? err->message : "No reason");
643 		if (err)
644 			g_error_free (err);
645 	} else {
646 		while ((item = g_dir_read_name(dir))) {
647 			if (g_str_has_suffix (item, SOEXT)) {
648 				g_autofree gchar *module_path = NULL;
649 
650 				p = g_new0(NstPlugin, 1);
651 
652 				module_path = g_module_build_path (plugindir, item);
653 				if (!module_path) {
654 					g_free (p);
655 					continue;
656 				}
657 
658 				p->module = g_module_open (module_path, 0);
659 			        if (!p->module) {
660                 			g_warning ("error opening %s: %s", module_path, g_module_error ());
661 					g_free (p);
662 					continue;
663 				}
664 
665 				if (!g_module_symbol (p->module, "nst_init_plugin", (gpointer *) &nst_init_plugin)) {
666 			                g_warning ("error: %s", g_module_error ());
667 					g_module_close (p->module);
668 					g_free (p);
669 					continue;
670 				}
671 
672 				nst_init_plugin (p);
673 				if (p->info->init(p)) {
674 					plugin_list = g_list_append (plugin_list, p);
675 				} else {
676 					g_free (p);
677 				}
678 			}
679 		}
680 		g_dir_close (dir);
681 	}
682 }
683 
684 static gboolean
caja_sendto_plugin_init(void)685 caja_sendto_plugin_init (void)
686 {
687 	if (g_file_test (UNINSTALLED_PLUGINDIR, G_FILE_TEST_IS_DIR) != FALSE) {
688 		/* Try to load the local plugins */
689 		GError *err = NULL;
690 		GDir *dir;
691 		const char *item;
692 
693 		dir = g_dir_open ("plugins/", 0, &err);
694 		if (dir == NULL) {
695 			g_warning ("Can't open the plugins dir: %s", err ? err->message : "No reason");
696 			if (err)
697 				g_error_free (err);
698 			return FALSE;
699 		}
700 		while ((item = g_dir_read_name(dir))) {
701 			char *plugindir;
702 
703 			plugindir = g_strdup_printf ("plugins/%s/.libs/", item);
704 			if (g_file_test (plugindir, G_FILE_TEST_IS_DIR) != FALSE)
705 				caja_sendto_plugin_dir_process (plugindir);
706 			g_free (plugindir);
707 		}
708 		g_dir_close (dir);
709 	}
710 
711 	if (g_list_length (plugin_list) == 0)
712 		caja_sendto_plugin_dir_process (PLUGINDIR);
713 
714 	return g_list_length (plugin_list) != 0;
715 }
716 
717 static char *
escape_ampersands_and_commas(const char * url)718 escape_ampersands_and_commas (const char *url)
719 {
720 	int i;
721 	char *str, *ptr;
722 
723 	/* Count the number of ampersands & commas */
724 	i = 0;
725 	ptr = (char *) url;
726 	while ((ptr = strchr (ptr, '&')) != NULL) {
727 		i++;
728 		ptr++;
729 	}
730 	ptr = (char *) url;
731 	while ((ptr = strchr (ptr, ',')) != NULL) {
732 		i++;
733 		ptr++;
734 	}
735 
736 	/* No ampersands or commas ? */
737 	if (i == 0)
738 		return NULL;
739 
740 	/* Replace the '&' */
741 	str = g_malloc0 (strlen (url) - i + 3 * i + 1);
742 	ptr = str;
743 	for (i = 0; url[i] != '\0'; i++) {
744 		if (url[i] == '&') {
745 			*ptr++ = '%';
746 			*ptr++ = '2';
747 			*ptr++ = '6';
748 		} else if (url[i] == ',') {
749 			*ptr++ = '%';
750 			*ptr++ = '2';
751 			*ptr++ = 'C';
752 		} else {
753 			*ptr++ = url[i];
754 		}
755 	}
756 
757 	return str;
758 }
759 
760 static void
caja_sendto_init(void)761 caja_sendto_init (void)
762 {
763 	int i;
764 
765 	if (g_module_supported() == FALSE)
766 		g_error ("Could not initialize gmodule support");
767 
768 	for (i = 0; filenames != NULL && filenames[i] != NULL; i++) {
769 		GFile *file;
770 		char *filename, *escaped, *uri;
771 
772 		file = g_file_new_for_commandline_arg (filenames[i]);
773 		filename = g_file_get_path (file);
774 		g_object_unref (file);
775 		if (filename == NULL)
776 			continue;
777 
778 		if (g_file_test (filename, G_FILE_TEST_IS_DIR) != FALSE)
779 			has_dirs = TRUE;
780 
781 		uri = g_filename_to_uri (filename, NULL, NULL);
782 		g_free (filename);
783 		escaped = escape_ampersands_and_commas (uri);
784 
785 		if (escaped == NULL) {
786 			file_list = g_list_prepend (file_list, uri);
787 		} else {
788 			file_list = g_list_prepend (file_list, escaped);
789 			g_free (uri);
790 		}
791 	}
792 
793 	if (file_list == NULL) {
794 		g_print (_("Expects URIs or filenames to be passed as options\n"));
795 		exit (1);
796 	}
797 
798 	file_list = g_list_reverse (file_list);
799 }
800 
main(int argc,char ** argv)801 int main (int argc, char **argv)
802 {
803 	GOptionContext *context;
804 	GError *error = NULL;
805 
806 #ifdef ENABLE_NLS
807 	bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
808 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
809 	textdomain (GETTEXT_PACKAGE);
810 #endif /* ENABLE_NLS */
811 
812 	context = g_option_context_new ("");
813 	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
814 	g_option_context_add_group (context, gtk_get_option_group (TRUE));
815 	if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
816 		g_print (_("Could not parse command-line options: %s\n"), error->message);
817 		g_error_free (error);
818 		return 1;
819 	}
820 
821 	settings = g_settings_new ("org.mate.Caja.Sendto");
822 	caja_sendto_init ();
823 	if (caja_sendto_plugin_init () == FALSE) {
824 		GtkWidget *error_dialog;
825 
826 		error_dialog =
827 			gtk_message_dialog_new (NULL,
828 						GTK_DIALOG_MODAL,
829 						GTK_MESSAGE_ERROR,
830 						GTK_BUTTONS_OK,
831 						_("Could not load any plugins."));
832 		gtk_message_dialog_format_secondary_text
833 			(GTK_MESSAGE_DIALOG (error_dialog),
834 			 _("Please verify your installation"));
835 
836 		gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */
837 		gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5);
838 		gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
839 						 GTK_RESPONSE_OK);
840 		gtk_dialog_run (GTK_DIALOG (error_dialog));
841 		return 1;
842 	}
843 	caja_sendto_create_ui ();
844 
845 	gtk_main ();
846 	g_object_unref(settings);
847 
848 	return 0;
849 }
850 
851