2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* action.c - code for handling the filer action windows.
21 * These routines generally fork() and talk to us via pipes.
29 #include <sys/param.h>
42 #include "gui_support.h"
47 #include "modechange.h"
55 #if defined(HAVE_GETXATTR)
56 # define ATTR_MAN_PAGE N_("See the attr(5) man page for full details.")
57 #elif defined(HAVE_ATTROPEN)
58 # define ATTR_MAN_PAGE N_("See the fsattr(5) man page for full details.")
60 # define ATTR_MAN_PAGE N_("You do not appear to have OS support.")
63 /* Parent->Child messages are one character each:
65 * Y/N Yes/No button clicked
66 * F Force deletion of non-writeable items
68 * E Entry text changed
72 typedef struct _GUIside GUIside
;
73 typedef void ActionChild(gpointer data
);
74 typedef void ForDirCB(const char *path
, const char *dest_path
);
78 ABox
*abox
; /* The action window widget */
80 int from_child
; /* File descriptor */
82 int input_tag
; /* gdk_input_add() */
83 pid_t child
; /* Process ID */
84 int errors
; /* Number of errors so far */
85 gboolean show_info
; /* For Disk Usage */
87 guchar
**default_string
; /* Changed when the entry changes */
88 void (*entry_string_func
)(GtkWidget
*widget
,
89 const guchar
*string
);
94 /* These don't need to be in a structure because we fork() before
97 static gboolean mount_open_dir
= FALSE
;
98 static gboolean mount_mount
= FALSE
; /* (FALSE => unmount) */
99 static int from_parent
= 0;
100 static FILE *to_parent
= NULL
;
101 static gboolean quiet
= FALSE
;
102 static GString
*message
= NULL
;
103 static const char *action_dest
= NULL
;
104 static const char *action_leaf
= NULL
;
105 static void (*action_do_func
)(const char *source
, const char *dest
);
106 static double size_tally
; /* For Disk Usage */
107 static unsigned long dir_counter
; /* For Disk Usage */
108 static unsigned long file_counter
; /* For Disk Usage */
110 static struct mode_change
*mode_change
= NULL
; /* For Permissions */
111 static FindCondition
*find_condition
= NULL
; /* For Find */
112 static MIME_type
*type_change
= NULL
;
114 /* Only used by child */
115 static gboolean o_force
= FALSE
;
116 static gboolean o_brief
= FALSE
;
117 static gboolean o_recurse
= FALSE
;
118 static gboolean o_newer
= FALSE
;
120 static Option o_action_copy
, o_action_move
, o_action_link
;
121 static Option o_action_delete
, o_action_mount
;
122 static Option o_action_force
, o_action_brief
, o_action_recurse
;
123 static Option o_action_newer
;
125 static Option o_action_mount_command
;
126 static Option o_action_umount_command
;
128 /* Whenever the text in these boxes is changed we store a copy of the new
129 * string to be used as the default next time.
131 static guchar
*last_chmod_string
= NULL
;
132 static guchar
*last_find_string
= NULL
;
133 static guchar
*last_settype_string
= NULL
;
135 /* Set to one of the above before forking. This may change over a call to
136 * reply(). It is reset to NULL once the text is parsed.
138 static guchar
*new_entry_string
= NULL
;
140 /* Static prototypes */
141 static void send_done(void);
142 static void send_check_path(const gchar
*path
);
143 static void send_mount_path(const gchar
*path
);
144 static gboolean
printf_send(const char *msg
, ...);
145 static gboolean
send_msg(void);
146 static gboolean
send_error(void);
147 static gboolean
send_dir(const char *dir
);
148 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
);
149 static void do_mount(const guchar
*path
, gboolean mount
);
150 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
151 const char *msg
, ...);
152 static gboolean
remove_pinned_ok(GList
*paths
);
157 /* This is called whenever the user edits the entry box (if any) - send the
160 static void entry_changed(GtkEditable
*entry
, GUIside
*gui_side
)
164 g_return_if_fail(gui_side
->default_string
!= NULL
);
166 text
= gtk_editable_get_chars(entry
, 0, -1);
168 if (gui_side
->entry_string_func
)
169 gui_side
->entry_string_func(GTK_WIDGET(entry
), text
);
171 g_free(*(gui_side
->default_string
));
172 *(gui_side
->default_string
) = text
; /* Gets text's ref */
174 if (!gui_side
->to_child
)
177 fputc('E', gui_side
->to_child
);
178 fputs(text
, gui_side
->to_child
);
179 fputc('\n', gui_side
->to_child
);
180 fflush(gui_side
->to_child
);
183 void show_condition_help(gpointer data
)
188 help
= gtk_dialog_new_with_buttons(
189 _("Find expression reference"),
191 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
193 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
195 text
= gtk_label_new(NULL
);
196 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
197 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
198 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
199 gtk_label_set_markup(GTK_LABEL(text
), _(
200 "<u>Quick Start</u>\n"
201 "Just put the name of the file you're looking for in single quotes:\n"
202 "<b>'index.html'</b> (to find a file called 'index.html')\n"
205 "<b>'*.htm', '*.html'</b> (finds HTML files)\n"
206 "<b>IsDir 'lib'</b> (finds directories called 'lib')\n"
207 "<b>IsReg 'core'</b> (finds a regular file called 'core')\n"
208 "<b>! (IsDir, IsReg)</b> (is neither a directory nor a regular file)\n"
209 "<b>mtime after 1 day ago and size > 1Mb</b> (big, and recently modified)\n"
210 "<b>'CVS' prune, isreg</b> (a regular file not in CVS)\n"
211 "<b>IsReg system(grep -q fred \"%\")</b> (contains the word 'fred')\n"
213 "<u>Simple Tests</u>\n"
214 "<b>IsReg, IsLink, IsDir, IsChar, IsBlock, IsDev, IsPipe, IsSocket, IsDoor</b> "
216 "<b>IsSUID, IsSGID, IsSticky, IsReadable, IsWriteable, IsExecutable</b> "
218 "<b>IsEmpty, IsMine</b>\n"
219 "A pattern in single quotes is a shell-style wildcard pattern to match. If it\n"
220 "contains a slash then the match is against the full path; otherwise it is\n"
221 "against the leafname only.\n"
223 "<u>Comparisons</u>\n"
224 "<b><, <=, =, !=, >, >=, After, Before</b> (compare two values)\n"
225 "<b>5 bytes, 1Kb, 2Mb, 3Gb</b> (file sizes)\n"
226 "<b>2 secs|mins|hours|days|weeks|years ago|hence</b> (times)\n"
227 "<b>atime, ctime, mtime, now, size, inode, nlinks, uid, gid, blocks</b> "
231 "<b>system(command)</b> (true if 'command' returns with a zero exit status;\n"
232 "a % in 'command' is replaced with the path of the current file)\n"
233 "<b>prune</b> (false, and prevents searching the contents of a directory)."));
235 g_signal_connect(help
, "response",
236 G_CALLBACK(gtk_widget_destroy
), NULL
);
238 gtk_widget_show_all(help
);
241 static void show_chmod_help(gpointer data
)
246 help
= gtk_dialog_new_with_buttons(
247 _("Change permissions reference"),
249 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
251 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
253 text
= gtk_label_new(NULL
);
254 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
255 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
256 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
257 gtk_label_set_markup(GTK_LABEL(text
), _(
258 "Normally, you can just select a command from the menu (click \n"
259 "on the arrow beside the command box). Sometimes, you need more...\n"
261 "The format of a command is: <b>CHANGE, CHANGE, ...</b>\n"
262 "Each <b>CHANGE</b> is: <b>WHO HOW PERMISSIONS</b>\n"
263 "<b>WHO</b> is some combination of <b>u</b>, <b>g</b> and <b>o</b> which "
264 "determines whether to\n"
265 "change the permissions for the User (owner), Group or Others.\n"
266 "<b>HOW</b> is <b>+</b>, <b>-</b> or <b>=</b> to add, remove or set "
267 "exactly the permissions.\n"
268 "<b>PERMISSIONS</b> is some combination of the letters <b>rwxXstugo</b>\n"
270 "Bracketed text and spaces are ignored.\n"
273 "<b>u+rw</b>: the file owner gains read and write permission\n"
274 "<b>g=u</b>: the group permissions are set to be the same as the user's\n"
275 "<b>o=u-w</b>: others get the same permissions as the owner, but without "
277 "<b>a+x</b>: <b>a</b>ll get execute/access permission - same as <b>ugo+x</b>\n"
278 "<b>a+X</b>: directories become accessable by everyone; files which were\n"
279 "executable by anyone become executable by everyone\n"
280 "<b>u+rw, go+r</b>: two commands at once!\n"
281 "<b>u+s</b>: set the SetUID bit - often has no effect on script files\n"
282 "<b>755</b>: set the permissions directly\n"
284 "See the chmod(1) man page for full details."));
286 g_signal_connect(help
, "response",
287 G_CALLBACK(gtk_widget_destroy
), NULL
);
289 gtk_widget_show_all(help
);
293 static void show_settype_help(gpointer data
)
298 help
= gtk_dialog_new_with_buttons(
299 _("Set type reference"),
301 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
303 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
305 text
= gtk_label_new(NULL
);
306 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
307 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
308 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
309 gtk_label_set_markup(GTK_LABEL(text
), _(
310 "Normally ROX-Filer determines the type of a regular file\n"
311 "by matching it's name against a pattern. To change the\n"
312 "type of the file you must rename it.\n"
314 "Newer file systems can support something called 'Extended\n"
315 "Attributes' which can be used to store additional data with\n"
316 "each file as named parameters. ROX-Filer uses the\n"
317 "'user.mime_type' attribute to store file types.\n"
319 "File types are only supported for regular files, not\n"
320 "directories, devices, pipes or sockets, and then only\n"
321 "on certain file systems and where the OS implements them.\n"));
323 text
= gtk_label_new(_(ATTR_MAN_PAGE
));
324 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
325 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
327 g_signal_connect(help
, "response",
328 G_CALLBACK(gtk_widget_destroy
), NULL
);
330 gtk_widget_show_all(help
);
333 static void process_message(GUIside
*gui_side
, const gchar
*buffer
)
335 ABox
*abox
= gui_side
->abox
;
338 abox_ask(abox
, buffer
+ 1);
339 else if (*buffer
== 's')
340 dir_check_this(buffer
+ 1); /* Update this item */
341 else if (*buffer
== '=')
342 abox_add_filename(abox
, buffer
+ 1);
343 else if (*buffer
== '#')
344 abox_clear_results(abox
);
345 else if (*buffer
== 'X')
347 filer_close_recursive(buffer
+ 1);
348 /* Let child know it's safe to continue... */
349 fputc('X', gui_side
->to_child
);
350 fflush(gui_side
->to_child
);
352 else if (*buffer
== 'm' || *buffer
== 'M')
354 /* Mount / major changes to this path */
358 mount_user_mount(buffer
+ 1);
360 filer_check_mounted(buffer
+ 1);
362 else if (*buffer
== '/')
363 abox_set_current_object(abox
, buffer
+ 1);
364 else if (*buffer
== 'o')
365 filer_opendir(buffer
+ 1, NULL
, NULL
);
366 else if (*buffer
== '!')
369 abox_log(abox
, buffer
+ 1, "error");
371 else if (*buffer
== '<')
372 abox_set_file(abox
, 0, buffer
+1);
373 else if (*buffer
== '>')
375 abox_set_file(abox
, 1, buffer
+1);
376 abox_show_compare(abox
, TRUE
);
378 else if (*buffer
== '%')
380 abox_set_percentage(abox
, atoi(buffer
+1));
383 abox_log(abox
, buffer
+ 1, NULL
);
386 /* Called when the child sends us a message */
387 static void message_from_child(gpointer data
,
389 GdkInputCondition condition
)
392 GUIside
*gui_side
= (GUIside
*) data
;
393 ABox
*abox
= gui_side
->abox
;
394 GtkTextBuffer
*text_buffer
;
396 text_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
));
398 if (read_exact(source
, buf
, 4))
404 message_len
= strtol(buf
, NULL
, 16);
405 buffer
= g_malloc(message_len
+ 1);
406 if (message_len
> 0 && read_exact(source
, buffer
, message_len
))
408 buffer
[message_len
] = '\0';
409 process_message(gui_side
, buffer
);
413 g_printerr("Child died in the middle of a message.\n");
416 if (gui_side
->abort_attempts
)
417 abox_log(abox
, _("\nProcess terminated.\n"), "error");
419 /* The child is dead */
422 fclose(gui_side
->to_child
);
423 gui_side
->to_child
= NULL
;
424 close(gui_side
->from_child
);
425 g_source_remove(gui_side
->input_tag
);
426 abox_cancel_ask(gui_side
->abox
);
428 if (gui_side
->errors
)
432 if (gui_side
->errors
== 1)
433 report
= g_strdup(_("There was one error.\n"));
435 report
= g_strdup_printf(_("There were %d errors.\n"),
438 gtk_text_buffer_insert_at_cursor(text_buffer
, report
, -1);
442 else if (gui_side
->show_info
== FALSE
)
443 gtk_widget_destroy(GTK_WIDGET(gui_side
->abox
));
446 /* Scans src_dir, calling cb(item, dest_path) for each item */
447 static void for_dir_contents(ForDirCB
*cb
,
449 const char *dest_path
)
453 GList
*list
= NULL
, *next
;
455 d
= mc_opendir(src_dir
);
458 /* Message displayed is "ERROR reading 'path': message" */
459 printf_send("!%s '%s': %s\n", _("ERROR reading"),
460 src_dir
, g_strerror(errno
));
466 while ((ent
= mc_readdir(d
)))
468 if (ent
->d_name
[0] == '.' && (ent
->d_name
[1] == '\0'
469 || (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')))
471 list
= g_list_prepend(list
, g_strdup(make_path(src_dir
,
476 for (next
= list
; next
; next
= next
->next
)
478 cb((char *) next
->data
, dest_path
);
485 /* Read this many bytes into the buffer. TRUE on success. */
486 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
)
491 got
= read(source
, buffer
, len
);
500 static void send_done(void)
502 printf_send(_("'\nDone\n"));
505 /* Notify the filer that this item has been updated */
506 static void send_check_path(const gchar
*path
)
508 printf_send("s%s", path
);
511 /* Notify the filer that this whole subtree has changed (eg, been unmounted) */
512 static void send_mount_path(const gchar
*path
)
514 printf_send("m%s", path
);
517 /* Send a message to the filer process. The first character indicates the
518 * type of the message.
520 static gboolean
printf_send(const char *msg
, ...)
526 tmp
= g_strdup_vprintf(msg
, args
);
529 g_string_assign(message
, tmp
);
535 /* Send 'message' to our parent process. TRUE on success. */
536 static gboolean
send_msg(void)
541 g_return_val_if_fail(message
->len
< 0xffff, FALSE
);
543 sprintf(len_buffer
, "%04" G_GSIZE_MODIFIER
"x", message
->len
);
544 fwrite(len_buffer
, 1, 4, to_parent
);
545 len
= fwrite(message
->str
, 1, message
->len
, to_parent
);
547 return len
== (ssize_t
) message
->len
;
550 /* Set the directory indicator at the top of the window */
551 static gboolean
send_dir(const char *dir
)
553 return printf_send("/%s", dir
);
556 static gboolean
send_error(void)
558 return printf_send("!%s: %s\n", _("ERROR"), g_strerror(errno
));
561 static void response(GtkDialog
*dialog
, gint response
, GUIside
*gui_side
)
565 if (!gui_side
->to_child
)
568 if (response
== GTK_RESPONSE_YES
)
570 else if (response
== GTK_RESPONSE_NO
)
575 fputc(code
, gui_side
->to_child
);
576 fflush(gui_side
->to_child
);
577 abox_show_compare(gui_side
->abox
, FALSE
);
580 static void flag_toggled(ABox
*abox
, gint flag
, GUIside
*gui_side
)
582 if (!gui_side
->to_child
)
585 fputc(flag
, gui_side
->to_child
);
586 fflush(gui_side
->to_child
);
589 static void read_new_entry_text(void)
595 new = g_string_new(NULL
);
599 len
= read(from_parent
, &c
, 1);
602 fprintf(stderr
, "read() error: %s\n",
604 _exit(1); /* Parent died? */
609 g_string_append_c(new, c
);
612 g_free(new_entry_string
);
613 new_entry_string
= new->str
;
614 g_string_free(new, FALSE
);
617 static void process_flag(char flag
)
628 o_recurse
= !o_recurse
;
637 read_new_entry_text();
640 printf_send("!ERROR: Bad message '%c'\n", flag
);
645 /* If the parent has sent any flag toggles, read them */
646 static void check_flags(void)
657 FD_SET(from_parent
, &set
);
660 got
= select(from_parent
+ 1, &set
, NULL
, NULL
, &tv
);
663 g_error("select() failed: %s\n", g_strerror(errno
));
667 got
= read(from_parent
, &retval
, 1);
669 g_error("read() error: %s\n", g_strerror(errno
));
671 process_flag(retval
);
675 /* Read until the user sends a reply. If ignore_quiet is TRUE then
676 * the user MUST click Yes or No, else treat quiet on as Yes.
677 * If the user needs prompting then does send_msg().
679 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
680 const char *msg
, ...)
687 if (quiet
&& !ignore_quiet
)
691 tmp
= g_strdup_vprintf(msg
, args
);
694 g_string_assign(message
, tmp
);
701 len
= read(fd
, &retval
, 1);
704 fprintf(stderr
, "read() error: %s\n",
706 _exit(1); /* Parent died? */
712 printf_send("' %s\n", _("Yes"));
715 printf_send("' %s\n", _("No"));
718 process_flag(retval
);
724 static void abort_operation(GtkWidget
*widget
, gpointer data
)
726 GUIside
*gui_side
= (GUIside
*) data
;
730 if (gui_side
->abort_attempts
== 0)
732 abox_log(ABOX(widget
),
733 _("\nAsking child process to terminate...\n"),
735 kill(-gui_side
->child
, SIGTERM
);
739 abox_log(ABOX(widget
),
740 _("\nTrying to KILL run-away process...\n"),
742 kill(-gui_side
->child
, SIGKILL
);
743 kill(-gui_side
->child
, SIGCONT
);
745 gui_side
->abort_attempts
++;
748 gtk_widget_destroy(widget
);
751 static void destroy_action_window(GtkWidget
*widget
, gpointer data
)
753 GUIside
*gui_side
= (GUIside
*) data
;
757 kill(-gui_side
->child
, SIGTERM
);
758 fclose(gui_side
->to_child
);
759 close(gui_side
->from_child
);
760 g_source_remove(gui_side
->input_tag
);
768 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
769 * (NULL on failure). The child calls func().
771 static GUIside
*start_action(GtkWidget
*abox
, ActionChild
*func
, gpointer data
,
772 int force
, int brief
, int recurse
, int newer
)
775 int filedes
[4]; /* 0 and 2 are for reading */
778 struct sigaction act
;
782 report_error("pipe: %s", g_strerror(errno
));
783 gtk_widget_destroy(abox
);
787 if (pipe(filedes
+ 2))
791 report_error("pipe: %s", g_strerror(errno
));
792 gtk_widget_destroy(abox
);
796 autoq
= gtk_toggle_button_get_active(
797 GTK_TOGGLE_BUTTON(ABOX(abox
)->quiet
));
808 report_error("fork: %s", g_strerror(errno
));
809 gtk_widget_destroy(abox
);
812 /* We are the child */
814 /* Create a new process group */
819 dir_drop_all_dnotifies();
821 /* Reset the SIGCHLD handler */
822 act
.sa_handler
= SIG_DFL
;
823 sigemptyset(&act
.sa_mask
);
825 sigaction(SIGCHLD
, &act
, NULL
);
827 message
= g_string_new(NULL
);
830 to_parent
= fdopen(filedes
[1], "wb");
831 from_parent
= filedes
[2];
837 /* We are the parent */
840 gui_side
= g_new(GUIside
, 1);
841 gui_side
->from_child
= filedes
[0];
842 gui_side
->to_child
= fdopen(filedes
[3], "wb");
843 gui_side
->child
= child
;
844 gui_side
->errors
= 0;
845 gui_side
->show_info
= FALSE
;
846 gui_side
->default_string
= NULL
;
847 gui_side
->entry_string_func
= NULL
;
848 gui_side
->abort_attempts
= 0;
850 gui_side
->abox
= ABOX(abox
);
851 g_signal_connect(abox
, "destroy",
852 G_CALLBACK(destroy_action_window
), gui_side
);
854 g_signal_connect(abox
, "response", G_CALLBACK(response
), gui_side
);
855 g_signal_connect(abox
, "flag_toggled",
856 G_CALLBACK(flag_toggled
), gui_side
);
857 g_signal_connect(abox
, "abort_operation",
858 G_CALLBACK(abort_operation
), gui_side
);
860 gui_side
->input_tag
= gdk_input_add_full(gui_side
->from_child
,
868 /* ACTIONS ON ONE ITEM */
870 /* These may call themselves recursively, or ask questions, etc */
872 /* Updates the global size_tally, file_counter and dir_counter */
873 static void do_usage(const char *src_path
, const char *unused
)
879 if (mc_lstat(src_path
, &info
))
881 printf_send("'%s:\n", src_path
);
884 else if (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
887 size_tally
+= info
.st_size
;
889 else if (S_ISDIR(info
.st_mode
))
892 if (printf_reply(from_parent
, FALSE
,
893 _("?Count contents of %s?"), src_path
))
896 safe_path
= g_strdup(src_path
);
897 for_dir_contents(do_usage
, safe_path
, safe_path
);
905 /* dest_path is the dir containing src_path */
906 static void do_delete(const char *src_path
, const char *unused
)
914 if (mc_lstat(src_path
, &info
))
920 write_prot
= S_ISLNK(info
.st_mode
) ? FALSE
921 : access(src_path
, W_OK
) != 0;
922 if (write_prot
|| !quiet
)
926 printf_send("<%s", src_path
);
928 res
=printf_reply(from_parent
, write_prot
&& !o_force
,
929 _("?Delete %s'%s'?"),
930 write_prot
? _("WRITE-PROTECTED ") : "",
937 printf_send(_("'Deleting '%s'\n"), src_path
);
939 safe_path
= g_strdup(src_path
);
941 if (S_ISDIR(info
.st_mode
))
943 for_dir_contents(do_delete
, safe_path
, safe_path
);
944 if (rmdir(safe_path
))
950 printf_send(_("'Directory '%s' deleted\n"), safe_path
);
951 send_mount_path(safe_path
);
953 else if (unlink(src_path
))
957 send_check_path(safe_path
);
958 if (strcmp(g_basename(safe_path
), ".DirIcon") == 0)
961 dir
= g_path_get_dirname(safe_path
);
962 send_check_path(dir
);
970 static void do_eject(const char *path
)
972 const char *argv
[3] = {NULL
, NULL
, NULL
};
980 printf_send("<%s", path
);
982 res
=printf_reply(from_parent
, !o_force
,
990 printf_send(_("'Eject '%s'\n"), path
);
992 /* Need to close all sub-directories now, or we
993 * can't unmount if dnotify is used.
997 printf_send("X%s", path
);
998 /* Wait until it's safe... */
999 read(from_parent
, &c
, 1);
1000 g_return_if_fail(c
== 'X');
1006 err
= fork_exec_wait(argv
);
1009 printf_send(_("!%s\neject failed\n"), err
);
1013 printf_send("M%s", path
);
1017 /* path is the item to check. If is is a directory then we may recurse
1018 * (unless prune is used).
1020 static void do_find(const char *path
, const char *unused
)
1028 if (!printf_reply(from_parent
, FALSE
, _("?Check '%s'?"), path
))
1034 if (new_entry_string
)
1036 find_condition_free(find_condition
);
1037 find_condition
= find_compile(new_entry_string
);
1038 null_g_free(&new_entry_string
);
1044 printf_send(_("!Invalid find condition - "
1045 "change it and try again\n"));
1046 if (!printf_reply(from_parent
, TRUE
,
1047 _("?Check '%s'?"), path
))
1051 if (mc_lstat(path
, &info
.stats
))
1054 printf_send(_("'(while checking '%s')\n"), path
);
1058 info
.fullpath
= path
;
1059 time(&info
.now
); /* XXX: Not for each check! */
1061 info
.leaf
= g_basename(path
);
1063 if (find_test_condition(find_condition
, &info
))
1064 printf_send("=%s", path
);
1066 if (S_ISDIR(info
.stats
.st_mode
) && !info
.prune
)
1069 safe_path
= g_strdup(path
);
1070 for_dir_contents(do_find
, safe_path
, safe_path
);
1075 /* Like mode_compile(), but ignores spaces and bracketed bits */
1076 static struct mode_change
*nice_mode_compile(const char *mode_string
,
1077 unsigned int masked_ops
)
1081 struct mode_change
*retval
= NULL
;
1083 new = g_string_new(NULL
);
1085 for (; *mode_string
; mode_string
++)
1087 if (*mode_string
== '(')
1089 if (*mode_string
== ')')
1097 if (brackets
== 0 && *mode_string
!= ' ')
1098 g_string_append_c(new, *mode_string
);
1102 retval
= mode_compile(new->str
, masked_ops
);
1103 g_string_free(new, TRUE
);
1107 static void do_chmod(const char *path
, const char *unused
)
1114 if (mc_lstat(path
, &info
))
1119 if (S_ISLNK(info
.st_mode
))
1125 printf_send("<%s", path
);
1127 res
=printf_reply(from_parent
, FALSE
,
1128 _("?Change permissions of '%s'?"), path
);
1134 printf_send(_("'Changing permissions of '%s'\n"), path
);
1138 if (new_entry_string
)
1141 mode_free(mode_change
);
1142 mode_change
= nice_mode_compile(new_entry_string
,
1144 null_g_free(&new_entry_string
);
1151 _("!Invalid mode command - change it and try again\n"));
1152 if (!printf_reply(from_parent
, TRUE
,
1153 _("?Change permissions of '%s'?"), path
))
1157 if (mc_lstat(path
, &info
))
1162 if (S_ISLNK(info
.st_mode
))
1165 new_mode
= mode_adjust(info
.st_mode
, mode_change
);
1166 if (chmod(path
, new_mode
))
1172 send_check_path(path
);
1174 if (S_ISDIR(info
.st_mode
))
1176 send_mount_path(path
);
1181 safe_path
= g_strdup(path
);
1182 for_dir_contents(do_chmod
, safe_path
, safe_path
);
1188 static void do_settype(const char *path
, const char *unused
)
1194 if (mc_lstat(path
, &info
))
1199 if (S_ISLNK(info
.st_mode
))
1205 printf_send("<%s", path
);
1207 res
=printf_reply(from_parent
, FALSE
,
1208 _("?Change type of '%s'?"), path
);
1216 if (new_entry_string
)
1218 type_change
= mime_type_lookup(new_entry_string
);
1219 null_g_free(&new_entry_string
);
1225 printf_send(_("!Invalid type - "
1226 "change it and try again\n"));
1227 if (!printf_reply(from_parent
, TRUE
,
1228 _("?Change type of '%s'?"), path
))
1232 if (mc_lstat(path
, &info
))
1237 if (S_ISLNK(info
.st_mode
))
1240 if (S_ISREG(info
.st_mode
))
1244 const char *comment
;
1246 comment
= mime_type_comment(type_change
);
1247 printf_send(_("'Changing type of '%s' to '%s'\n"), path
,
1251 if (xtype_set(path
, type_change
))
1257 send_check_path(path
);
1259 else if (S_ISDIR(info
.st_mode
))
1264 safe_path
= g_strdup(path
);
1265 for_dir_contents(do_settype
, safe_path
, unused
);
1271 /* We want to copy 'object' into directory 'dir'. If 'action_leaf'
1272 * is set then that is the new leafname, otherwise the leafname stays
1275 static const char *make_dest_path(const char *object
, const char *dir
)
1283 leaf
= strrchr(object
, '/');
1285 leaf
= object
; /* Error? */
1290 return make_path(dir
, leaf
);
1293 /* If action_leaf is not NULL it specifies the new leaf name */
1294 static void do_copy2(const char *path
, const char *dest
)
1296 const char *dest_path
;
1298 struct stat dest_info
;
1302 dest_path
= make_dest_path(path
, dest
);
1304 if (mc_lstat(path
, &info
))
1310 if (mc_lstat(dest_path
, &dest_info
) == 0)
1315 merge
= S_ISDIR(info
.st_mode
) && S_ISDIR(dest_info
.st_mode
);
1317 if (!merge
&& o_newer
&& info
.st_mtime
> dest_info
.st_mtime
)
1319 /* Newer; keep going */
1323 printf_send("<%s", path
);
1324 printf_send(">%s", dest_path
);
1325 if (!printf_reply(from_parent
, TRUE
,
1326 _("?'%s' already exists - %s?"),
1328 merge
? _("merge contents")
1335 if (S_ISDIR(dest_info
.st_mode
))
1336 err
= rmdir(dest_path
);
1338 err
= unlink(dest_path
);
1343 if (errno
!= ENOENT
)
1345 printf_send(_("'Trying copy anyway...\n"));
1351 printf_send("<%s", path
);
1353 if (!printf_reply(from_parent
, FALSE
,
1354 _("?Copy %s as %s?"), path
, dest_path
))
1357 else if (!o_brief
|| S_ISDIR(info
.st_mode
))
1358 printf_send(_("'Copying %s as %s\n"), path
, dest_path
);
1360 if (S_ISDIR(info
.st_mode
))
1362 mode_t mode
= info
.st_mode
;
1363 char *safe_path
, *safe_dest
;
1364 struct stat dest_info
;
1367 safe_path
= g_strdup(path
);
1368 safe_dest
= g_strdup(dest_path
);
1370 exists
= !mc_lstat(dest_path
, &dest_info
);
1372 if (exists
&& !S_ISDIR(dest_info
.st_mode
))
1373 printf_send(_("!ERROR: Destination already exists, "
1374 "but is not a directory\n"));
1375 else if (exists
== FALSE
&& mkdir(dest_path
, 0700 | mode
))
1380 /* (just been created then) */
1381 send_check_path(dest_path
);
1384 for_dir_contents(do_copy2
, safe_path
, safe_dest
);
1385 /* Note: dest_path now invalid... */
1391 /* We may have created the directory with
1392 * more permissions than the source so that
1393 * we could write to it... change it back now.
1395 if (chmod(safe_dest
, mode
))
1397 /* Some filesystems don't support
1398 * SetGID and SetUID bits. Ignore
1405 /* Also, try to preserve the timestamps */
1406 utb
.actime
= info
.st_atime
;
1407 utb
.modtime
= info
.st_mtime
;
1409 utime(safe_dest
, &utb
);
1416 else if (S_ISLNK(info
.st_mode
))
1420 /* Not all versions of cp(1) can make symlinks,
1421 * so we special-case it.
1424 target
= readlink_dup(path
);
1427 if (symlink(target
, dest_path
))
1430 send_check_path(dest_path
);
1441 error
= copy_file(path
, dest_path
);
1445 printf_send(_("!%s\nFailed to copy '%s'\n"),
1450 send_check_path(dest_path
);
1454 /* If action_leaf is not NULL it specifies the new leaf name */
1455 static void do_move2(const char *path
, const char *dest
)
1457 const char *dest_path
;
1458 const char *argv
[] = {"mv", "-f", NULL
, NULL
, NULL
};
1465 dest_path
= make_dest_path(path
, dest
);
1467 is_dir
= mc_lstat(path
, &info2
) == 0 && S_ISDIR(info2
.st_mode
);
1469 if (access(dest_path
, F_OK
) == 0)
1474 if (mc_lstat(dest_path
, &info
))
1480 if (!is_dir
&& o_newer
&& info2
.st_mtime
> info
.st_mtime
)
1482 /* Newer; keep going */
1486 printf_send("<%s", path
);
1487 printf_send(">%s", dest_path
);
1488 if (!printf_reply(from_parent
, TRUE
,
1489 _("?'%s' already exists - overwrite?"),
1494 if (S_ISDIR(info
.st_mode
))
1495 err
= rmdir(dest_path
);
1497 err
= unlink(dest_path
);
1502 if (errno
!= ENOENT
)
1504 printf_send(_("'Trying move anyway...\n"));
1509 printf_send("<%s", path
);
1511 if (!printf_reply(from_parent
, FALSE
,
1512 _("?Move %s as %s?"), path
, dest_path
))
1516 printf_send(_("'Moving %s as %s\n"), path
, dest_path
);
1519 argv
[3] = dest_path
;
1521 err
= fork_exec_wait(argv
);
1524 printf_send(_("!%s\nFailed to move %s as %s\n"),
1525 err
, path
, dest_path
);
1530 send_check_path(dest_path
);
1533 send_mount_path(path
);
1535 send_check_path(path
);
1539 /* Copy path to dest.
1540 * Check that path not copied into itself.
1542 static void do_copy(const char *path
, const char *dest
)
1544 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1545 printf_send(_("!ERROR: Can't copy object into itself\n"));
1548 do_copy2(path
, dest
);
1549 send_check_path(dest
);
1553 /* Move path to dest.
1554 * Check that path not moved into itself.
1556 static void do_move(const char *path
, const char *dest
)
1558 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1560 _("!ERROR: Can't move/rename object into itself\n"));
1563 do_move2(path
, dest
);
1564 send_check_path(dest
);
1568 /* Common code for do_link_relative() and do_link_absolute(). */
1569 static void do_link(const char *path
, const char *dest_path
)
1572 printf_send(_("'Linking %s as %s\n"), path
, dest_path
);
1574 printf_send("<%s", path
);
1576 if (!printf_reply(from_parent
, FALSE
,
1577 _("?Link %s as %s?"), path
, dest_path
))
1581 if (symlink(path
, dest_path
))
1584 send_check_path(dest_path
);
1587 static void do_link_relative(const char *path
, const char *dest
)
1590 const char *dest_path
;
1592 dest_path
= make_dest_path(path
, dest
);
1596 rel_path
= get_relative_path(dest_path
, path
);
1597 do_link(rel_path
, dest_path
);
1601 static void do_link_absolute(const char *path
, const char *dest
)
1604 do_link(path
, make_dest_path(path
, dest
));
1607 /* Mount/umount this item (depending on 'mount') */
1608 static void do_mount(const guchar
*path
, gboolean mount
)
1610 const char *argv
[3] = {NULL
, NULL
, NULL
};
1615 argv
[0] = mount
? o_action_mount_command
.value
1616 : o_action_umount_command
.value
;
1620 printf_send(mount
? _("'Mounting %s\n")
1621 : _("'Unmounting %s\n"),
1623 else if (!printf_reply(from_parent
, FALSE
,
1624 mount
? _("?Mount %s?")
1625 : _("?Unmount %s?"),
1632 /* Need to close all sub-directories now, or we
1633 * can't unmount if dnotify is used.
1635 printf_send("X%s", path
);
1636 /* Wait until it's safe... */
1637 read(from_parent
, &c
, 1);
1638 g_return_if_fail(c
== 'X');
1641 err
= fork_exec_wait(argv
);
1645 _("!%s\nMount failed\n") :
1646 _("!%s\nUnmount failed\n"), err
);
1649 /* Mount may have worked even on error, eg if we try to mount
1650 * a read-only disk read/write, it gets mounted read-only
1653 if (mount
&& mount_is_mounted(path
, NULL
, NULL
))
1654 printf_send(_("'(seems to be mounted now anyway)\n"));
1659 printf_send("M%s", path
);
1660 if (mount
&& mount_open_dir
)
1661 printf_send("o%s", path
);
1664 /* CHILD MAIN LOOPS */
1666 /* After forking, the child calls one of these functions */
1668 /* We use a double for total size in order to count beyond 4Gb */
1669 static void usage_cb(gpointer data
)
1671 GList
*paths
= (GList
*) data
;
1672 double total_size
= 0;
1675 n
=g_list_length(paths
);
1676 dir_counter
= file_counter
= 0;
1678 for (i
=0; paths
; paths
= paths
->next
, i
++)
1680 guchar
*path
= (guchar
*) paths
->data
;
1689 printf_send("%%%d", per
);
1691 do_usage(path
, NULL
);
1693 printf_send("'%s: %s\n",
1695 format_double_size(size_tally
));
1696 total_size
+= size_tally
;
1698 printf_send("%%-1");
1700 g_string_printf(message
, _("'\nTotal: %s ("),
1701 format_double_size(total_size
));
1704 g_string_append_printf(message
,
1705 "%ld %s%s", file_counter
,
1706 file_counter
== 1 ? _("file") : _("files"),
1707 dir_counter
? ", " : ")\n");
1709 if (file_counter
== 0 && dir_counter
== 0)
1710 g_string_append(message
, _("no directories)\n"));
1711 else if (dir_counter
)
1712 g_string_append_printf(message
,
1713 "%ld %s)\n", dir_counter
,
1714 dir_counter
== 1 ? _("directory")
1715 : _("directories"));
1720 #ifdef DO_MOUNT_POINTS
1721 static void mount_cb(gpointer data
)
1723 GList
*paths
= (GList
*) data
;
1724 gboolean mount_points
= FALSE
;
1727 n
=g_list_length(paths
);
1728 for (i
=0; paths
; paths
= paths
->next
, i
++)
1730 guchar
*path
= (guchar
*) paths
->data
;
1733 target
= pathdup(path
);
1740 printf_send("%%%d", per
);
1742 if (mount_is_mounted(target
, NULL
, NULL
) ||
1743 g_hash_table_lookup(fstab_mounts
, target
))
1745 mount_points
= TRUE
;
1746 do_mount(target
, mount_mount
); /* Mount */
1756 printf_send(_("!No mount points selected!\n"));
1760 /* (use g_dirname() instead?) */
1761 static guchar
*dirname(guchar
*path
)
1765 slash
= strrchr(path
, '/');
1766 g_return_val_if_fail(slash
!= NULL
, g_strdup(path
));
1769 return g_strndup(path
, slash
- path
);
1770 return g_strdup("/");
1773 static void delete_cb(gpointer data
)
1775 GList
*paths
= (GList
*) data
;
1778 n
=g_list_length(paths
);
1779 for (i
=0; paths
; paths
= paths
->next
, i
++)
1781 guchar
*path
= (guchar
*) paths
->data
;
1784 dir
= dirname(path
);
1790 printf_send("%%%d", per
);
1792 do_delete(path
, dir
);
1800 static void eject_cb(gpointer data
)
1802 GList
*paths
= (GList
*) data
;
1805 n
=g_list_length(paths
);
1807 for (i
=0; paths
; paths
= paths
->next
, i
++)
1809 guchar
*path
= (guchar
*) paths
->data
;
1814 printf_send("%%%d", per
);
1824 static void find_cb(gpointer data
)
1826 GList
*all_paths
= (GList
*) data
;
1831 for (paths
= all_paths
; paths
; paths
= paths
->next
)
1833 guchar
*path
= (guchar
*) paths
->data
;
1837 do_find(path
, NULL
);
1840 if (!printf_reply(from_parent
, TRUE
,
1841 _("?Another search?")))
1849 static void chmod_cb(gpointer data
)
1851 GList
*paths
= (GList
*) data
;
1854 n
=g_list_length(paths
);
1856 for (i
=0; paths
; paths
= paths
->next
, i
++)
1858 guchar
*path
= (guchar
*) paths
->data
;
1864 printf_send("%%%d", per
);
1868 if (mc_stat(path
, &info
) != 0)
1870 else if (S_ISLNK(info
.st_mode
))
1871 printf_send(_("!'%s' is a symbolic link\n"),
1874 do_chmod(path
, NULL
);
1880 static void settype_cb(gpointer data
)
1882 GList
*paths
= (GList
*) data
;
1885 n
=g_list_length(paths
);
1887 for (i
=0; paths
; paths
= paths
->next
, i
++)
1889 guchar
*path
= (guchar
*) paths
->data
;
1895 printf_send("%%%d", per
);
1899 if (mc_stat(path
, &info
) != 0)
1901 else if (S_ISLNK(info
.st_mode
))
1902 printf_send(_("!'%s' is a symbolic link\n"),
1905 do_settype(path
, NULL
);
1911 static void list_cb(gpointer data
)
1913 GList
*paths
= (GList
*) data
;
1916 n
=g_list_length(paths
);
1918 for (i
=0; paths
; paths
= paths
->next
, i
++)
1923 printf_send("%%%d", per
);
1925 send_dir((char *) paths
->data
);
1927 action_do_func((char *) paths
->data
, action_dest
);
1933 /* EXTERNAL INTERFACE */
1935 void action_find(GList
*paths
)
1942 report_error(_("You need to select some items "
1943 "to search through"));
1947 if (!last_find_string
)
1948 last_find_string
= g_strdup("'core'");
1950 new_entry_string
= last_find_string
;
1952 abox
= abox_new(_("Find"), FALSE
);
1953 gui_side
= start_action(abox
, find_cb
, paths
,
1954 o_action_force
.int_value
,
1955 o_action_brief
.int_value
,
1956 o_action_recurse
.int_value
,
1957 o_action_newer
.int_value
);
1961 abox_add_results(ABOX(abox
));
1963 gui_side
->default_string
= &last_find_string
;
1964 abox_add_entry(ABOX(abox
), last_find_string
,
1965 new_help_button(show_condition_help
, NULL
));
1966 g_signal_connect(ABOX(abox
)->entry
, "changed",
1967 G_CALLBACK(entry_changed
), gui_side
);
1968 set_find_string_colour(ABOX(abox
)->entry
, last_find_string
);
1970 gui_side
->show_info
= TRUE
;
1971 gui_side
->entry_string_func
= set_find_string_colour
;
1973 number_of_windows
++;
1974 gtk_widget_show(abox
);
1977 /* Count disk space used by selected items */
1978 void action_usage(GList
*paths
)
1985 report_error(_("You need to select some items to count"));
1989 abox
= abox_new(_("Disk Usage"), TRUE
);
1990 if(paths
&& paths
->next
)
1991 abox_set_percentage(ABOX(abox
), 0);
1993 gui_side
= start_action(abox
, usage_cb
, paths
,
1994 o_action_force
.int_value
,
1995 o_action_brief
.int_value
,
1996 o_action_recurse
.int_value
,
1997 o_action_newer
.int_value
);
2001 gui_side
->show_info
= TRUE
;
2003 number_of_windows
++;
2005 gtk_widget_show(abox
);
2008 /* Mount/unmount listed items (paths).
2009 * Free the list after this function returns.
2010 * If open_dir is TRUE and the dir is successfully mounted, open it.
2011 * quiet can be -1 for default.
2013 void action_mount(GList
*paths
, gboolean open_dir
, gboolean mount
, int quiet
)
2015 #ifdef DO_MOUNT_POINTS
2020 quiet
= o_action_mount
.int_value
;
2022 mount_open_dir
= open_dir
;
2023 mount_mount
= mount
;
2025 abox
= abox_new(_("Mount / Unmount"), quiet
);
2026 if(paths
&& paths
->next
)
2027 abox_set_percentage(ABOX(abox
), 0);
2028 gui_side
= start_action(abox
, mount_cb
, paths
,
2029 o_action_force
.int_value
,
2030 o_action_brief
.int_value
,
2031 o_action_recurse
.int_value
,
2032 o_action_newer
.int_value
);
2036 number_of_windows
++;
2037 gtk_widget_show(abox
);
2040 _("ROX-Filer does not yet support mount points on your "
2042 #endif /* DO_MOUNT_POINTS */
2045 /* Delete these paths */
2046 void action_delete(GList
*paths
)
2051 if (!remove_pinned_ok(paths
))
2054 abox
= abox_new(_("Delete"), o_action_delete
.int_value
);
2055 if(paths
&& paths
->next
)
2056 abox_set_percentage(ABOX(abox
), 0);
2057 gui_side
= start_action(abox
, delete_cb
, paths
,
2058 o_action_force
.int_value
,
2059 o_action_brief
.int_value
,
2060 o_action_recurse
.int_value
,
2061 o_action_newer
.int_value
);
2065 abox_add_flag(ABOX(abox
),
2066 _("Force"), _("Don't confirm deletion of non-writeable items"),
2067 'F', o_action_force
.int_value
);
2068 abox_add_flag(ABOX(abox
),
2069 _("Brief"), _("Only log directories being deleted"),
2070 'B', o_action_brief
.int_value
);
2072 number_of_windows
++;
2073 gtk_widget_show(abox
);
2076 /* Change the permissions of the selected items */
2077 void action_chmod(GList
*paths
, gboolean force_recurse
, const char *action
)
2081 static GList
*presets
= NULL
;
2082 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2086 report_error(_("You need to select the items "
2087 "whose permissions you want to change"));
2093 presets
= g_list_append(presets
, (gchar
*)
2094 _("a+x (Make executable/searchable)"));
2095 presets
= g_list_append(presets
, (gchar
*)
2096 _("a-x (Make non-executable/non-searchable)"));
2097 presets
= g_list_append(presets
, (gchar
*)
2098 _("u+rw (Give owner read+write)"));
2099 presets
= g_list_append(presets
, (gchar
*)
2100 _("go-rwx (Private - owner access only)"));
2101 presets
= g_list_append(presets
, (gchar
*)
2102 _("go=u-w (Public access, not write)"));
2105 if (!last_chmod_string
)
2106 last_chmod_string
= g_strdup((guchar
*) presets
->data
);
2109 new_entry_string
= g_strdup(action
);
2111 new_entry_string
= g_strdup(last_chmod_string
);
2113 abox
= abox_new(_("Permissions"), FALSE
);
2114 if(paths
&& paths
->next
)
2115 abox_set_percentage(ABOX(abox
), 0);
2116 gui_side
= start_action(abox
, chmod_cb
, paths
,
2117 o_action_force
.int_value
,
2118 o_action_brief
.int_value
,
2120 o_action_newer
.int_value
);
2125 abox_add_flag(ABOX(abox
),
2126 _("Brief"), _("Don't list processed files"),
2127 'B', o_action_brief
.int_value
);
2128 abox_add_flag(ABOX(abox
),
2129 _("Recurse"), _("Also change contents of subdirectories"),
2132 gui_side
->default_string
= &last_chmod_string
;
2133 abox_add_combo(ABOX(abox
), _("Command:"), presets
, new_entry_string
,
2134 new_help_button(show_chmod_help
, NULL
));
2136 g_signal_connect(ABOX(abox
)->entry
, "changed",
2137 G_CALLBACK(entry_changed
), gui_side
);
2139 g_signal_connect_swapped(gui_side
->entry
, "activate",
2140 G_CALLBACK(gtk_button_clicked
),
2144 number_of_windows
++;
2145 gtk_widget_show(abox
);
2148 null_g_free(&new_entry_string
);
2151 /* Set the MIME type of the selected items */
2152 void action_settype(GList
*paths
, gboolean force_recurse
, const char *oldtype
)
2156 GList
*presets
= NULL
;
2157 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2161 report_error(_("You need to select the items "
2162 "whose type you want to change"));
2166 if (!last_settype_string
)
2167 last_settype_string
= g_strdup("text/plain");
2170 new_entry_string
= g_strdup(oldtype
);
2172 new_entry_string
= g_strdup(last_settype_string
);
2174 abox
= abox_new(_("Set type"), FALSE
);
2175 if(paths
&& paths
->next
)
2176 abox_set_percentage(ABOX(abox
), 0);
2177 gui_side
= start_action(abox
, settype_cb
, paths
,
2178 o_action_force
.int_value
,
2179 o_action_brief
.int_value
,
2181 o_action_newer
.int_value
);
2186 abox_add_flag(ABOX(abox
),
2187 _("Brief"), _("Don't list processed files"),
2188 'B', o_action_brief
.int_value
);
2189 abox_add_flag(ABOX(abox
),
2190 _("Recurse"), _("Change contents of subdirectories"),
2193 gui_side
->default_string
= &last_settype_string
;
2195 /* Note: get the list again each time -- it can change */
2196 presets
= mime_type_name_list();
2197 abox_add_combo(ABOX(abox
), _("Type:"), presets
, new_entry_string
,
2198 new_help_button(show_settype_help
, NULL
));
2199 g_list_free(presets
);
2201 g_signal_connect(ABOX(abox
)->entry
, "changed",
2202 G_CALLBACK(entry_changed
), gui_side
);
2204 number_of_windows
++;
2205 gtk_widget_show(abox
);
2208 null_g_free(&new_entry_string
);
2211 /* If leaf is NULL then the copy has the same name as the original.
2212 * quiet can be -1 for default.
2214 void action_copy(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2220 quiet
= o_action_copy
.int_value
;
2224 action_do_func
= do_copy
;
2226 abox
= abox_new(_("Copy"), quiet
);
2227 if(paths
&& paths
->next
)
2228 abox_set_percentage(ABOX(abox
), 0);
2229 gui_side
= start_action(abox
, list_cb
, paths
,
2230 o_action_force
.int_value
,
2231 o_action_brief
.int_value
,
2232 o_action_recurse
.int_value
,
2233 o_action_newer
.int_value
);
2237 abox_add_flag(ABOX(abox
),
2239 _("Only over-write if source is newer than destination."),
2240 'W', o_action_newer
.int_value
);
2241 abox_add_flag(ABOX(abox
),
2242 _("Brief"), _("Only log directories as they are copied"),
2243 'B', o_action_brief
.int_value
);
2245 number_of_windows
++;
2246 gtk_widget_show(abox
);
2249 /* If leaf is NULL then the file is not renamed.
2250 * quiet can be -1 for default.
2252 void action_move(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2258 quiet
= o_action_move
.int_value
;
2262 action_do_func
= do_move
;
2264 abox
= abox_new(_("Move"), quiet
);
2265 if(paths
&& paths
->next
)
2266 abox_set_percentage(ABOX(abox
), 0);
2267 gui_side
= start_action(abox
, list_cb
, paths
,
2268 o_action_force
.int_value
,
2269 o_action_brief
.int_value
,
2270 o_action_recurse
.int_value
,
2271 o_action_newer
.int_value
);
2275 abox_add_flag(ABOX(abox
),
2277 _("Only over-write if source is newer than destination."),
2278 'W', o_action_newer
.int_value
);
2279 abox_add_flag(ABOX(abox
),
2280 _("Brief"), _("Don't log each file as it is moved"),
2281 'B', o_action_brief
.int_value
);
2282 number_of_windows
++;
2283 gtk_widget_show(abox
);
2286 /* If leaf is NULL then the link will have the same name */
2287 void action_link(GList
*paths
, const char *dest
, const char *leaf
,
2296 action_do_func
= do_link_relative
;
2298 action_do_func
= do_link_absolute
;
2300 abox
= abox_new(_("Link"), o_action_link
.int_value
);
2301 if(paths
&& paths
->next
)
2302 abox_set_percentage(ABOX(abox
), 0);
2303 gui_side
= start_action(abox
, list_cb
, paths
,
2304 o_action_force
.int_value
,
2305 o_action_brief
.int_value
,
2306 o_action_recurse
.int_value
,
2307 o_action_newer
.int_value
);
2311 number_of_windows
++;
2312 gtk_widget_show(abox
);
2315 /* Eject these paths */
2316 void action_eject(GList
*paths
)
2321 abox
= abox_new(_("Eject"), TRUE
);
2322 if(paths
&& paths
->next
)
2323 abox_set_percentage(ABOX(abox
), 0);
2324 gui_side
= start_action(abox
, eject_cb
, paths
,
2325 o_action_force
.int_value
,
2326 o_action_brief
.int_value
,
2327 o_action_recurse
.int_value
,
2328 o_action_newer
.int_value
);
2332 number_of_windows
++;
2333 gtk_widget_show(abox
);
2336 void action_init(void)
2338 option_add_int(&o_action_copy
, "action_copy", 1);
2339 option_add_int(&o_action_move
, "action_move", 1);
2340 option_add_int(&o_action_link
, "action_link", 1);
2341 option_add_int(&o_action_delete
, "action_delete", 0);
2342 option_add_int(&o_action_mount
, "action_mount", 1);
2343 option_add_int(&o_action_force
, "action_force", FALSE
);
2344 option_add_int(&o_action_brief
, "action_brief", FALSE
);
2345 option_add_int(&o_action_recurse
, "action_recurse", FALSE
);
2346 option_add_int(&o_action_newer
, "action_newer", FALSE
);
2348 option_add_string(&o_action_mount_command
,
2349 "action_mount_command", "mount");
2350 option_add_string(&o_action_umount_command
,
2351 "action_umount_command", "umount");
2356 /* Check to see if any of the selected items (or their children) are
2357 * on the pinboard or panel. If so, ask for confirmation.
2359 * TRUE if it's OK to lose them.
2361 static gboolean
remove_pinned_ok(GList
*paths
)
2363 GList
*ask
= NULL
, *next
;
2368 for (; paths
; paths
= paths
->next
)
2370 guchar
*path
= (guchar
*) paths
->data
;
2372 if (icons_require(path
))
2374 if (++ask_n
> MAX_ASK
)
2376 ask
= g_list_append(ask
, path
);
2383 if (ask_n
> MAX_ASK
)
2385 message
= g_string_new(_("Deleting items such as "));
2388 else if (ask_n
== 1)
2389 message
= g_string_new(_("Deleting the item "));
2391 message
= g_string_new(_("Deleting the items "));
2394 for (next
= ask
; next
; next
= next
->next
)
2396 guchar
*path
= (guchar
*) next
->data
;
2399 leaf
= strrchr(path
, '/');
2405 g_string_append_c(message
, '`');
2406 g_string_append(message
, leaf
);
2407 g_string_append_c(message
, '\'');
2409 if (i
== ask_n
- 1 && i
> 0)
2410 g_string_append(message
, _(" and "));
2412 g_string_append(message
, ", ");
2418 message
= g_string_append(message
,
2419 _(" will affect some items on the pinboard "
2420 "or panel - really delete it?"));
2423 if (ask_n
> MAX_ASK
)
2424 message
= g_string_append_c(message
, ',');
2425 message
= g_string_append(message
,
2426 _(" will affect some items on the pinboard "
2427 "or panel - really delete them?"));
2430 retval
= confirm(message
->str
, GTK_STOCK_DELETE
, NULL
);
2432 g_string_free(message
, TRUE
);
2437 void set_find_string_colour(GtkWidget
*widget
, const guchar
*string
)
2439 FindCondition
*cond
;
2441 cond
= find_compile(string
);
2442 entry_set_error(widget
, !cond
);
2444 find_condition_free(cond
);