4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2005, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* action.c - code for handling the filer action windows.
23 * These routines generally fork() and talk to us via pipes.
31 #include <sys/param.h>
44 #include "gui_support.h"
49 #include "modechange.h"
57 #if defined(HAVE_GETXATTR)
58 # define ATTR_MAN_PAGE N_("See the attr(5) man page for full details.")
59 #elif defined(HAVE_ATTROPEN)
60 # define ATTR_MAN_PAGE N_("See the fsattr(5) man page for full details.")
62 # define ATTR_MAN_PAGE N_("You do not appear to have OS support.")
65 /* Parent->Child messages are one character each:
67 * Y/N Yes/No button clicked
68 * F Force deletion of non-writeable items
70 * E Entry text changed
74 typedef struct _GUIside GUIside
;
75 typedef void ActionChild(gpointer data
);
76 typedef void ForDirCB(const char *path
, const char *dest_path
);
80 ABox
*abox
; /* The action window widget */
82 int from_child
; /* File descriptor */
84 int input_tag
; /* gdk_input_add() */
85 pid_t child
; /* Process ID */
86 int errors
; /* Number of errors so far */
87 gboolean show_info
; /* For Disk Usage */
89 guchar
**default_string
; /* Changed when the entry changes */
90 void (*entry_string_func
)(GtkWidget
*widget
,
91 const guchar
*string
);
96 /* These don't need to be in a structure because we fork() before
99 static gboolean mount_open_dir
= FALSE
;
100 static gboolean mount_mount
= FALSE
; /* (FALSE => unmount) */
101 static int from_parent
= 0;
102 static FILE *to_parent
= NULL
;
103 static gboolean quiet
= FALSE
;
104 static GString
*message
= NULL
;
105 static const char *action_dest
= NULL
;
106 static const char *action_leaf
= NULL
;
107 static void (*action_do_func
)(const char *source
, const char *dest
);
108 static double size_tally
; /* For Disk Usage */
109 static unsigned long dir_counter
; /* For Disk Usage */
110 static unsigned long file_counter
; /* For Disk Usage */
112 static struct mode_change
*mode_change
= NULL
; /* For Permissions */
113 static FindCondition
*find_condition
= NULL
; /* For Find */
114 static MIME_type
*type_change
= NULL
;
116 /* Only used by child */
117 static gboolean o_force
= FALSE
;
118 static gboolean o_brief
= FALSE
;
119 static gboolean o_recurse
= FALSE
;
120 static gboolean o_newer
= FALSE
;
122 static Option o_action_copy
, o_action_move
, o_action_link
;
123 static Option o_action_delete
, o_action_mount
;
124 static Option o_action_force
, o_action_brief
, o_action_recurse
;
125 static Option o_action_newer
;
127 /* Whenever the text in these boxes is changed we store a copy of the new
128 * string to be used as the default next time.
130 static guchar
*last_chmod_string
= NULL
;
131 static guchar
*last_find_string
= NULL
;
132 static guchar
*last_settype_string
= NULL
;
134 /* Set to one of the above before forking. This may change over a call to
135 * reply(). It is reset to NULL once the text is parsed.
137 static guchar
*new_entry_string
= NULL
;
139 /* Static prototypes */
140 static void send_done(void);
141 static void send_check_path(const gchar
*path
);
142 static void send_mount_path(const gchar
*path
);
143 static gboolean
printf_send(const char *msg
, ...);
144 static gboolean
send_msg(void);
145 static gboolean
send_error(void);
146 static gboolean
send_dir(const char *dir
);
147 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
);
148 static void do_mount(const guchar
*path
, gboolean mount
);
149 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
150 const char *msg
, ...);
151 static gboolean
remove_pinned_ok(GList
*paths
);
156 /* This is called whenever the user edits the entry box (if any) - send the
159 static void entry_changed(GtkEditable
*entry
, GUIside
*gui_side
)
163 g_return_if_fail(gui_side
->default_string
!= NULL
);
165 text
= gtk_editable_get_chars(entry
, 0, -1);
167 if (gui_side
->entry_string_func
)
168 gui_side
->entry_string_func(GTK_WIDGET(entry
), text
);
170 g_free(*(gui_side
->default_string
));
171 *(gui_side
->default_string
) = text
; /* Gets text's ref */
173 if (!gui_side
->to_child
)
176 fputc('E', gui_side
->to_child
);
177 fputs(text
, gui_side
->to_child
);
178 fputc('\n', gui_side
->to_child
);
179 fflush(gui_side
->to_child
);
182 void show_condition_help(gpointer data
)
187 help
= gtk_dialog_new_with_buttons(
188 _("Find expression reference"),
190 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
192 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
194 text
= gtk_label_new(NULL
);
195 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
196 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
197 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
198 gtk_label_set_markup(GTK_LABEL(text
), _(
199 "<u>Quick Start</u>\n"
200 "Just put the name of the file you're looking for in single quotes:\n"
201 "<b>'index.html'</b> (to find a file called 'index.html')\n"
204 "<b>'*.htm', '*.html'</b> (finds HTML files)\n"
205 "<b>IsDir 'lib'</b> (finds directories called 'lib')\n"
206 "<b>IsReg 'core'</b> (finds a regular file called 'core')\n"
207 "<b>! (IsDir, IsReg)</b> (is neither a directory nor a regular file)\n"
208 "<b>mtime after 1 day ago and size > 1Mb</b> (big, and recently modified)\n"
209 "<b>'CVS' prune, isreg</b> (a regular file not in CVS)\n"
210 "<b>IsReg system(grep -q fred \"%\")</b> (contains the word 'fred')\n"
212 "<u>Simple Tests</u>\n"
213 "<b>IsReg, IsLink, IsDir, IsChar, IsBlock, IsDev, IsPipe, IsSocket, IsDoor</b> "
215 "<b>IsSUID, IsSGID, IsSticky, IsReadable, IsWriteable, IsExecutable</b> "
217 "<b>IsEmpty, IsMine</b>\n"
218 "A pattern in single quotes is a shell-style wildcard pattern to match. If it\n"
219 "contains a slash then the match is against the full path; otherwise it is\n"
220 "against the leafname only.\n"
222 "<u>Comparisons</u>\n"
223 "<b><, <=, =, !=, >, >=, After, Before</b> (compare two values)\n"
224 "<b>5 bytes, 1Kb, 2Mb, 3Gb</b> (file sizes)\n"
225 "<b>2 secs|mins|hours|days|weeks|years ago|hence</b> (times)\n"
226 "<b>atime, ctime, mtime, now, size, inode, nlinks, uid, gid, blocks</b> "
230 "<b>system(command)</b> (true if 'command' returns with a zero exit status;\n"
231 "a % in 'command' is replaced with the path of the current file)\n"
232 "<b>prune</b> (false, and prevents searching the contents of a directory)."));
234 g_signal_connect(help
, "response",
235 G_CALLBACK(gtk_widget_destroy
), NULL
);
237 gtk_widget_show_all(help
);
240 static void show_chmod_help(gpointer data
)
245 help
= gtk_dialog_new_with_buttons(
246 _("Change permissions reference"),
248 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
250 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
252 text
= gtk_label_new(NULL
);
253 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
254 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
255 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
256 gtk_label_set_markup(GTK_LABEL(text
), _(
257 "Normally, you can just select a command from the menu (click \n"
258 "on the arrow beside the command box). Sometimes, you need more...\n"
260 "The format of a command is: <b>CHANGE, CHANGE, ...</b>\n"
261 "Each <b>CHANGE</b> is: <b>WHO HOW PERMISSIONS</b>\n"
262 "<b>WHO</b> is some combination of <b>u</b>, <b>g</b> and <b>o</b> which "
263 "determines whether to\n"
264 "change the permissions for the User (owner), Group or Others.\n"
265 "<b>HOW</b> is <b>+</b>, <b>-</b> or <b>=</b> to add, remove or set "
266 "exactly the permissions.\n"
267 "<b>PERMISSIONS</b> is some combination of the letters <b>rwxXstugo</b>\n"
269 "Bracketed text and spaces are ignored.\n"
272 "<b>u+rw</b>: the file owner gains read and write permission\n"
273 "<b>g=u</b>: the group permissions are set to be the same as the user's\n"
274 "<b>o=u-w</b>: others get the same permissions as the owner, but without "
276 "<b>a+x</b>: <b>a</b>ll get execute/access permission - same as <b>ugo+x</b>\n"
277 "<b>a+X</b>: directories become accessable by everyone; files which were\n"
278 "executable by anyone become executable by everyone\n"
279 "<b>u+rw, go+r</b>: two commands at once!\n"
280 "<b>u+s</b>: set the SetUID bit - often has no effect on script files\n"
281 "<b>755</b>: set the permissions directly\n"
283 "See the chmod(1) man page for full details."));
285 g_signal_connect(help
, "response",
286 G_CALLBACK(gtk_widget_destroy
), NULL
);
288 gtk_widget_show_all(help
);
292 static void show_settype_help(gpointer data
)
297 help
= gtk_dialog_new_with_buttons(
298 _("Set type reference"),
300 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
302 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
304 text
= gtk_label_new(NULL
);
305 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
306 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
307 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
308 gtk_label_set_markup(GTK_LABEL(text
), _(
309 "Normally ROX-Filer determines the type of a regular file\n"
310 "by matching it's name against a pattern. To change the\n"
311 "type of the file you must rename it.\n"
313 "Newer file systems can support something called 'Extended\n"
314 "Attributes' which can be used to store additional data with\n"
315 "each file as named parameters. ROX-Filer uses the\n"
316 "'user.mime_type' attribute to store file types.\n"
318 "File types are only supported for regular files, not\n"
319 "directories, devices, pipes or sockets, and then only\n"
320 "on certain file systems and where the OS implements them.\n"));
322 text
= gtk_label_new(_(ATTR_MAN_PAGE
));
323 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
324 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
326 g_signal_connect(help
, "response",
327 G_CALLBACK(gtk_widget_destroy
), NULL
);
329 gtk_widget_show_all(help
);
332 static void process_message(GUIside
*gui_side
, const gchar
*buffer
)
334 ABox
*abox
= gui_side
->abox
;
337 abox_ask(abox
, buffer
+ 1);
338 else if (*buffer
== 's')
339 dir_check_this(buffer
+ 1); /* Update this item */
340 else if (*buffer
== '=')
341 abox_add_filename(abox
, buffer
+ 1);
342 else if (*buffer
== '#')
343 abox_clear_results(abox
);
344 else if (*buffer
== 'X')
346 filer_close_recursive(buffer
+ 1);
347 /* Let child know it's safe to continue... */
348 fputc('X', gui_side
->to_child
);
349 fflush(gui_side
->to_child
);
351 else if (*buffer
== 'm' || *buffer
== 'M')
353 /* Mount / major changes to this path */
357 mount_user_mount(buffer
+ 1);
359 filer_check_mounted(buffer
+ 1);
361 else if (*buffer
== '/')
362 abox_set_current_object(abox
, buffer
+ 1);
363 else if (*buffer
== 'o')
364 filer_opendir(buffer
+ 1, NULL
, NULL
);
365 else if (*buffer
== '!')
368 abox_log(abox
, buffer
+ 1, "error");
370 else if (*buffer
== '<')
371 abox_set_file(abox
, 0, buffer
+1);
372 else if (*buffer
== '>')
374 abox_set_file(abox
, 1, buffer
+1);
375 abox_show_compare(abox
, TRUE
);
377 else if (*buffer
== '%')
379 abox_set_percentage(abox
, atoi(buffer
+1));
382 abox_log(abox
, buffer
+ 1, NULL
);
385 /* Called when the child sends us a message */
386 static void message_from_child(gpointer data
,
388 GdkInputCondition condition
)
391 GUIside
*gui_side
= (GUIside
*) data
;
392 ABox
*abox
= gui_side
->abox
;
393 GtkTextBuffer
*text_buffer
;
395 text_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
));
397 if (read_exact(source
, buf
, 4))
403 message_len
= strtol(buf
, NULL
, 16);
404 buffer
= g_malloc(message_len
+ 1);
405 if (message_len
> 0 && read_exact(source
, buffer
, message_len
))
407 buffer
[message_len
] = '\0';
408 process_message(gui_side
, buffer
);
412 g_printerr("Child died in the middle of a message.\n");
415 if (gui_side
->abort_attempts
)
416 abox_log(abox
, _("\nProcess terminated.\n"), "error");
418 /* The child is dead */
421 fclose(gui_side
->to_child
);
422 gui_side
->to_child
= NULL
;
423 close(gui_side
->from_child
);
424 g_source_remove(gui_side
->input_tag
);
425 abox_cancel_ask(gui_side
->abox
);
427 if (gui_side
->errors
)
431 if (gui_side
->errors
== 1)
432 report
= g_strdup(_("There was one error.\n"));
434 report
= g_strdup_printf(_("There were %d errors.\n"),
437 gtk_text_buffer_insert_at_cursor(text_buffer
, report
, -1);
441 else if (gui_side
->show_info
== FALSE
)
442 gtk_widget_destroy(GTK_WIDGET(gui_side
->abox
));
445 /* Scans src_dir, calling cb(item, dest_path) for each item */
446 static void for_dir_contents(ForDirCB
*cb
,
448 const char *dest_path
)
452 GList
*list
= NULL
, *next
;
454 d
= mc_opendir(src_dir
);
457 /* Message displayed is "ERROR reading 'path': message" */
458 printf_send("!%s '%s': %s\n", _("ERROR reading"),
459 src_dir
, g_strerror(errno
));
465 while ((ent
= mc_readdir(d
)))
467 if (ent
->d_name
[0] == '.' && (ent
->d_name
[1] == '\0'
468 || (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')))
470 list
= g_list_prepend(list
, g_strdup(make_path(src_dir
,
475 for (next
= list
; next
; next
= next
->next
)
477 cb((char *) next
->data
, dest_path
);
484 /* Read this many bytes into the buffer. TRUE on success. */
485 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
)
490 got
= read(source
, buffer
, len
);
499 static void send_done(void)
501 printf_send(_("'\nDone\n"));
504 /* Notify the filer that this item has been updated */
505 static void send_check_path(const gchar
*path
)
507 printf_send("s%s", path
);
510 /* Notify the filer that this whole subtree has changed (eg, been unmounted) */
511 static void send_mount_path(const gchar
*path
)
513 printf_send("m%s", path
);
516 /* Send a message to the filer process. The first character indicates the
517 * type of the message.
519 static gboolean
printf_send(const char *msg
, ...)
525 tmp
= g_strdup_vprintf(msg
, args
);
528 g_string_assign(message
, tmp
);
534 /* Send 'message' to our parent process. TRUE on success. */
535 static gboolean
send_msg(void)
540 g_return_val_if_fail(message
->len
< 0xffff, FALSE
);
542 sprintf(len_buffer
, "%04" G_GSIZE_MODIFIER
"x", message
->len
);
543 fwrite(len_buffer
, 1, 4, to_parent
);
544 len
= fwrite(message
->str
, 1, message
->len
, to_parent
);
546 return len
== (ssize_t
) message
->len
;
549 /* Set the directory indicator at the top of the window */
550 static gboolean
send_dir(const char *dir
)
552 return printf_send("/%s", dir
);
555 static gboolean
send_error(void)
557 return printf_send("!%s: %s\n", _("ERROR"), g_strerror(errno
));
560 static void response(GtkDialog
*dialog
, gint response
, GUIside
*gui_side
)
564 if (!gui_side
->to_child
)
567 if (response
== GTK_RESPONSE_YES
)
569 else if (response
== GTK_RESPONSE_NO
)
574 fputc(code
, gui_side
->to_child
);
575 fflush(gui_side
->to_child
);
576 abox_show_compare(gui_side
->abox
, FALSE
);
579 static void flag_toggled(ABox
*abox
, gint flag
, GUIside
*gui_side
)
581 if (!gui_side
->to_child
)
584 fputc(flag
, gui_side
->to_child
);
585 fflush(gui_side
->to_child
);
588 static void read_new_entry_text(void)
594 new = g_string_new(NULL
);
598 len
= read(from_parent
, &c
, 1);
601 fprintf(stderr
, "read() error: %s\n",
603 _exit(1); /* Parent died? */
608 g_string_append_c(new, c
);
611 g_free(new_entry_string
);
612 new_entry_string
= new->str
;
613 g_string_free(new, FALSE
);
616 static void process_flag(char flag
)
627 o_recurse
= !o_recurse
;
636 read_new_entry_text();
639 printf_send("!ERROR: Bad message '%c'\n", flag
);
644 /* If the parent has sent any flag toggles, read them */
645 static void check_flags(void)
656 FD_SET(from_parent
, &set
);
659 got
= select(from_parent
+ 1, &set
, NULL
, NULL
, &tv
);
662 g_error("select() failed: %s\n", g_strerror(errno
));
666 got
= read(from_parent
, &retval
, 1);
668 g_error("read() error: %s\n", g_strerror(errno
));
670 process_flag(retval
);
674 /* Read until the user sends a reply. If ignore_quiet is TRUE then
675 * the user MUST click Yes or No, else treat quiet on as Yes.
676 * If the user needs prompting then does send_msg().
678 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
679 const char *msg
, ...)
686 if (quiet
&& !ignore_quiet
)
690 tmp
= g_strdup_vprintf(msg
, args
);
693 g_string_assign(message
, tmp
);
700 len
= read(fd
, &retval
, 1);
703 fprintf(stderr
, "read() error: %s\n",
705 _exit(1); /* Parent died? */
711 printf_send("' %s\n", _("Yes"));
714 printf_send("' %s\n", _("No"));
717 process_flag(retval
);
723 static void abort_operation(GtkWidget
*widget
, gpointer data
)
725 GUIside
*gui_side
= (GUIside
*) data
;
729 if (gui_side
->abort_attempts
== 0)
731 abox_log(ABOX(widget
),
732 _("\nAsking child process to terminate...\n"),
734 kill(-gui_side
->child
, SIGTERM
);
738 abox_log(ABOX(widget
),
739 _("\nTrying to KILL run-away process...\n"),
741 kill(-gui_side
->child
, SIGKILL
);
742 kill(-gui_side
->child
, SIGCONT
);
744 gui_side
->abort_attempts
++;
747 gtk_widget_destroy(widget
);
750 static void destroy_action_window(GtkWidget
*widget
, gpointer data
)
752 GUIside
*gui_side
= (GUIside
*) data
;
756 kill(-gui_side
->child
, SIGTERM
);
757 fclose(gui_side
->to_child
);
758 close(gui_side
->from_child
);
759 g_source_remove(gui_side
->input_tag
);
767 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
768 * (NULL on failure). The child calls func().
770 static GUIside
*start_action(GtkWidget
*abox
, ActionChild
*func
, gpointer data
,
771 int force
, int brief
, int recurse
, int newer
)
774 int filedes
[4]; /* 0 and 2 are for reading */
777 struct sigaction act
;
781 report_error("pipe: %s", g_strerror(errno
));
782 gtk_widget_destroy(abox
);
786 if (pipe(filedes
+ 2))
790 report_error("pipe: %s", g_strerror(errno
));
791 gtk_widget_destroy(abox
);
795 autoq
= gtk_toggle_button_get_active(
796 GTK_TOGGLE_BUTTON(ABOX(abox
)->quiet
));
807 report_error("fork: %s", g_strerror(errno
));
808 gtk_widget_destroy(abox
);
811 /* We are the child */
813 /* Create a new process group */
818 dir_drop_all_dnotifies();
820 /* Reset the SIGCHLD handler */
821 act
.sa_handler
= SIG_DFL
;
822 sigemptyset(&act
.sa_mask
);
824 sigaction(SIGCHLD
, &act
, NULL
);
826 message
= g_string_new(NULL
);
829 to_parent
= fdopen(filedes
[1], "wb");
830 from_parent
= filedes
[2];
836 /* We are the parent */
839 gui_side
= g_new(GUIside
, 1);
840 gui_side
->from_child
= filedes
[0];
841 gui_side
->to_child
= fdopen(filedes
[3], "wb");
842 gui_side
->child
= child
;
843 gui_side
->errors
= 0;
844 gui_side
->show_info
= FALSE
;
845 gui_side
->default_string
= NULL
;
846 gui_side
->entry_string_func
= NULL
;
847 gui_side
->abort_attempts
= 0;
849 gui_side
->abox
= ABOX(abox
);
850 g_signal_connect(abox
, "destroy",
851 G_CALLBACK(destroy_action_window
), gui_side
);
853 g_signal_connect(abox
, "response", G_CALLBACK(response
), gui_side
);
854 g_signal_connect(abox
, "flag_toggled",
855 G_CALLBACK(flag_toggled
), gui_side
);
856 g_signal_connect(abox
, "abort_operation",
857 G_CALLBACK(abort_operation
), gui_side
);
859 gui_side
->input_tag
= gdk_input_add_full(gui_side
->from_child
,
867 /* ACTIONS ON ONE ITEM */
869 /* These may call themselves recursively, or ask questions, etc */
871 /* Updates the global size_tally, file_counter and dir_counter */
872 static void do_usage(const char *src_path
, const char *unused
)
878 if (mc_lstat(src_path
, &info
))
880 printf_send("'%s:\n", src_path
);
883 else if (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
886 size_tally
+= info
.st_size
;
888 else if (S_ISDIR(info
.st_mode
))
891 if (printf_reply(from_parent
, FALSE
,
892 _("?Count contents of %s?"), src_path
))
895 safe_path
= g_strdup(src_path
);
896 for_dir_contents(do_usage
, safe_path
, safe_path
);
904 /* dest_path is the dir containing src_path */
905 static void do_delete(const char *src_path
, const char *unused
)
913 if (mc_lstat(src_path
, &info
))
919 write_prot
= S_ISLNK(info
.st_mode
) ? FALSE
920 : access(src_path
, W_OK
) != 0;
921 if (write_prot
|| !quiet
)
925 printf_send("<%s", src_path
);
927 res
=printf_reply(from_parent
, write_prot
&& !o_force
,
928 _("?Delete %s'%s'?"),
929 write_prot
? _("WRITE-PROTECTED ") : "",
936 printf_send(_("'Deleting '%s'\n"), src_path
);
938 safe_path
= g_strdup(src_path
);
940 if (S_ISDIR(info
.st_mode
))
942 for_dir_contents(do_delete
, safe_path
, safe_path
);
943 if (rmdir(safe_path
))
949 printf_send(_("'Directory '%s' deleted\n"), safe_path
);
950 send_mount_path(safe_path
);
952 else if (unlink(src_path
))
956 send_check_path(safe_path
);
957 if (strcmp(g_basename(safe_path
), ".DirIcon") == 0)
960 dir
= g_path_get_dirname(safe_path
);
961 send_check_path(dir
);
969 static void do_eject(const char *path
)
971 const char *argv
[3] = {NULL
, NULL
, NULL
};
979 printf_send("<%s", path
);
981 res
=printf_reply(from_parent
, !o_force
,
989 printf_send(_("'Eject '%s'\n"), path
);
991 /* Need to close all sub-directories now, or we
992 * can't unmount if dnotify is used.
996 printf_send("X%s", path
);
997 /* Wait until it's safe... */
998 read(from_parent
, &c
, 1);
999 g_return_if_fail(c
== 'X');
1005 err
= fork_exec_wait(argv
);
1008 printf_send(_("!%s\neject failed\n"), err
);
1012 printf_send("M%s", path
);
1016 /* path is the item to check. If is is a directory then we may recurse
1017 * (unless prune is used).
1019 static void do_find(const char *path
, const char *unused
)
1027 if (!printf_reply(from_parent
, FALSE
, _("?Check '%s'?"), path
))
1033 if (new_entry_string
)
1035 find_condition_free(find_condition
);
1036 find_condition
= find_compile(new_entry_string
);
1037 null_g_free(&new_entry_string
);
1043 printf_send(_("!Invalid find condition - "
1044 "change it and try again\n"));
1045 if (!printf_reply(from_parent
, TRUE
,
1046 _("?Check '%s'?"), path
))
1050 if (mc_lstat(path
, &info
.stats
))
1053 printf_send(_("'(while checking '%s')\n"), path
);
1057 info
.fullpath
= path
;
1058 time(&info
.now
); /* XXX: Not for each check! */
1060 info
.leaf
= g_basename(path
);
1062 if (find_test_condition(find_condition
, &info
))
1063 printf_send("=%s", path
);
1065 if (S_ISDIR(info
.stats
.st_mode
) && !info
.prune
)
1068 safe_path
= g_strdup(path
);
1069 for_dir_contents(do_find
, safe_path
, safe_path
);
1074 /* Like mode_compile(), but ignores spaces and bracketed bits */
1075 static struct mode_change
*nice_mode_compile(const char *mode_string
,
1076 unsigned int masked_ops
)
1080 struct mode_change
*retval
= NULL
;
1082 new = g_string_new(NULL
);
1084 for (; *mode_string
; mode_string
++)
1086 if (*mode_string
== '(')
1088 if (*mode_string
== ')')
1096 if (brackets
== 0 && *mode_string
!= ' ')
1097 g_string_append_c(new, *mode_string
);
1101 retval
= mode_compile(new->str
, masked_ops
);
1102 g_string_free(new, TRUE
);
1106 static void do_chmod(const char *path
, const char *unused
)
1113 if (mc_lstat(path
, &info
))
1118 if (S_ISLNK(info
.st_mode
))
1124 printf_send("<%s", path
);
1126 res
=printf_reply(from_parent
, FALSE
,
1127 _("?Change permissions of '%s'?"), path
);
1133 printf_send(_("'Changing permissions of '%s'\n"), path
);
1137 if (new_entry_string
)
1140 mode_free(mode_change
);
1141 mode_change
= nice_mode_compile(new_entry_string
,
1143 null_g_free(&new_entry_string
);
1150 _("!Invalid mode command - change it and try again\n"));
1151 if (!printf_reply(from_parent
, TRUE
,
1152 _("?Change permissions of '%s'?"), path
))
1156 if (mc_lstat(path
, &info
))
1161 if (S_ISLNK(info
.st_mode
))
1164 new_mode
= mode_adjust(info
.st_mode
, mode_change
);
1165 if (chmod(path
, new_mode
))
1171 send_check_path(path
);
1173 if (S_ISDIR(info
.st_mode
))
1175 send_mount_path(path
);
1180 safe_path
= g_strdup(path
);
1181 for_dir_contents(do_chmod
, safe_path
, safe_path
);
1187 static void do_settype(const char *path
, const char *unused
)
1193 if (mc_lstat(path
, &info
))
1198 if (S_ISLNK(info
.st_mode
))
1204 printf_send("<%s", path
);
1206 res
=printf_reply(from_parent
, FALSE
,
1207 _("?Change type of '%s'?"), path
);
1215 if (new_entry_string
)
1217 type_change
= mime_type_lookup(new_entry_string
);
1218 null_g_free(&new_entry_string
);
1224 printf_send(_("!Invalid type - "
1225 "change it and try again\n"));
1226 if (!printf_reply(from_parent
, TRUE
,
1227 _("?Change type of '%s'?"), path
))
1231 if (mc_lstat(path
, &info
))
1236 if (S_ISLNK(info
.st_mode
))
1239 if (S_ISREG(info
.st_mode
))
1243 const char *comment
;
1245 comment
= mime_type_comment(type_change
);
1246 printf_send(_("'Changing type of '%s' to '%s'\n"), path
,
1250 if (xtype_set(path
, type_change
))
1256 send_check_path(path
);
1258 else if (S_ISDIR(info
.st_mode
))
1263 safe_path
= g_strdup(path
);
1264 for_dir_contents(do_settype
, safe_path
, unused
);
1270 /* We want to copy 'object' into directory 'dir'. If 'action_leaf'
1271 * is set then that is the new leafname, otherwise the leafname stays
1274 static const char *make_dest_path(const char *object
, const char *dir
)
1282 leaf
= strrchr(object
, '/');
1284 leaf
= object
; /* Error? */
1289 return make_path(dir
, leaf
);
1292 /* If action_leaf is not NULL it specifies the new leaf name */
1293 static void do_copy2(const char *path
, const char *dest
)
1295 const char *dest_path
;
1297 struct stat dest_info
;
1301 dest_path
= make_dest_path(path
, dest
);
1303 if (mc_lstat(path
, &info
))
1309 if (mc_lstat(dest_path
, &dest_info
) == 0)
1314 merge
= S_ISDIR(info
.st_mode
) && S_ISDIR(dest_info
.st_mode
);
1316 if (!merge
&& o_newer
&& info
.st_mtime
> dest_info
.st_mtime
)
1318 /* Newer; keep going */
1322 printf_send("<%s", path
);
1323 printf_send(">%s", dest_path
);
1324 if (!printf_reply(from_parent
, TRUE
,
1325 _("?'%s' already exists - %s?"),
1327 merge
? _("merge contents")
1334 if (S_ISDIR(dest_info
.st_mode
))
1335 err
= rmdir(dest_path
);
1337 err
= unlink(dest_path
);
1342 if (errno
!= ENOENT
)
1344 printf_send(_("'Trying copy anyway...\n"));
1350 printf_send("<%s", path
);
1352 if (!printf_reply(from_parent
, FALSE
,
1353 _("?Copy %s as %s?"), path
, dest_path
))
1356 else if (!o_brief
|| S_ISDIR(info
.st_mode
))
1357 printf_send(_("'Copying %s as %s\n"), path
, dest_path
);
1359 if (S_ISDIR(info
.st_mode
))
1361 mode_t mode
= info
.st_mode
;
1362 char *safe_path
, *safe_dest
;
1363 struct stat dest_info
;
1366 safe_path
= g_strdup(path
);
1367 safe_dest
= g_strdup(dest_path
);
1369 exists
= !mc_lstat(dest_path
, &dest_info
);
1371 if (exists
&& !S_ISDIR(dest_info
.st_mode
))
1372 printf_send(_("!ERROR: Destination already exists, "
1373 "but is not a directory\n"));
1374 else if (exists
== FALSE
&& mkdir(dest_path
, 0700 | mode
))
1379 /* (just been created then) */
1380 send_check_path(dest_path
);
1383 for_dir_contents(do_copy2
, safe_path
, safe_dest
);
1384 /* Note: dest_path now invalid... */
1390 /* We may have created the directory with
1391 * more permissions than the source so that
1392 * we could write to it... change it back now.
1394 if (chmod(safe_dest
, mode
))
1396 /* Some filesystems don't support
1397 * SetGID and SetUID bits. Ignore
1404 /* Also, try to preserve the timestamps */
1405 utb
.actime
= info
.st_atime
;
1406 utb
.modtime
= info
.st_mtime
;
1408 utime(safe_dest
, &utb
);
1415 else if (S_ISLNK(info
.st_mode
))
1419 /* Not all versions of cp(1) can make symlinks,
1420 * so we special-case it.
1423 target
= readlink_dup(path
);
1426 if (symlink(target
, dest_path
))
1429 send_check_path(dest_path
);
1440 error
= copy_file(path
, dest_path
);
1444 printf_send(_("!%s\nFailed to copy '%s'\n"),
1449 send_check_path(dest_path
);
1453 /* If action_leaf is not NULL it specifies the new leaf name */
1454 static void do_move2(const char *path
, const char *dest
)
1456 const char *dest_path
;
1457 const char *argv
[] = {"mv", "-f", NULL
, NULL
, NULL
};
1464 dest_path
= make_dest_path(path
, dest
);
1466 is_dir
= mc_lstat(path
, &info2
) == 0 && S_ISDIR(info2
.st_mode
);
1468 if (access(dest_path
, F_OK
) == 0)
1473 if (mc_lstat(dest_path
, &info
))
1479 if (!is_dir
&& o_newer
&& info2
.st_mtime
> info
.st_mtime
)
1481 /* Newer; keep going */
1485 printf_send("<%s", path
);
1486 printf_send(">%s", dest_path
);
1487 if (!printf_reply(from_parent
, TRUE
,
1488 _("?'%s' already exists - overwrite?"),
1493 if (S_ISDIR(info
.st_mode
))
1494 err
= rmdir(dest_path
);
1496 err
= unlink(dest_path
);
1501 if (errno
!= ENOENT
)
1503 printf_send(_("'Trying move anyway...\n"));
1508 printf_send("<%s", path
);
1510 if (!printf_reply(from_parent
, FALSE
,
1511 _("?Move %s as %s?"), path
, dest_path
))
1515 printf_send(_("'Moving %s as %s\n"), path
, dest_path
);
1518 argv
[3] = dest_path
;
1520 err
= fork_exec_wait(argv
);
1523 printf_send(_("!%s\nFailed to move %s as %s\n"),
1524 err
, path
, dest_path
);
1529 send_check_path(dest_path
);
1532 send_mount_path(path
);
1534 send_check_path(path
);
1538 /* Copy path to dest.
1539 * Check that path not copied into itself.
1541 static void do_copy(const char *path
, const char *dest
)
1543 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1544 printf_send(_("!ERROR: Can't copy object into itself\n"));
1547 do_copy2(path
, dest
);
1548 send_check_path(dest
);
1552 /* Move path to dest.
1553 * Check that path not moved into itself.
1555 static void do_move(const char *path
, const char *dest
)
1557 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1559 _("!ERROR: Can't move/rename object into itself\n"));
1562 do_move2(path
, dest
);
1563 send_check_path(dest
);
1567 /* Common code for do_link_relative() and do_link_absolute(). */
1568 static void do_link(const char *path
, const char *dest_path
)
1571 printf_send(_("'Linking %s as %s\n"), path
, dest_path
);
1573 printf_send("<%s", path
);
1575 if (!printf_reply(from_parent
, FALSE
,
1576 _("?Link %s as %s?"), path
, dest_path
))
1580 if (symlink(path
, dest_path
))
1583 send_check_path(dest_path
);
1586 static void do_link_relative(const char *path
, const char *dest
)
1589 const char *dest_path
;
1591 dest_path
= make_dest_path(path
, dest
);
1595 rel_path
= get_relative_path(dest_path
, path
);
1596 do_link(rel_path
, dest_path
);
1600 static void do_link_absolute(const char *path
, const char *dest
)
1603 do_link(path
, make_dest_path(path
, dest
));
1606 /* Mount/umount this item (depending on 'mount') */
1607 static void do_mount(const guchar
*path
, gboolean mount
)
1609 const char *argv
[3] = {NULL
, NULL
, NULL
};
1614 argv
[0] = mount
? "mount" : "umount";
1618 printf_send(mount
? _("'Mounting %s\n")
1619 : _("'Unmounting %s\n"),
1621 else if (!printf_reply(from_parent
, FALSE
,
1622 mount
? _("?Mount %s?")
1623 : _("?Unmount %s?"),
1630 /* Need to close all sub-directories now, or we
1631 * can't unmount if dnotify is used.
1633 printf_send("X%s", path
);
1634 /* Wait until it's safe... */
1635 read(from_parent
, &c
, 1);
1636 g_return_if_fail(c
== 'X');
1639 err
= fork_exec_wait(argv
);
1643 _("!%s\nMount failed\n") :
1644 _("!%s\nUnmount failed\n"), err
);
1647 /* Mount may have worked even on error, eg if we try to mount
1648 * a read-only disk read/write, it gets mounted read-only
1651 if (mount
&& mount_is_mounted(path
, NULL
, NULL
))
1652 printf_send(_("'(seems to be mounted now anyway)\n"));
1657 printf_send("M%s", path
);
1658 if (mount
&& mount_open_dir
)
1659 printf_send("o%s", path
);
1662 /* CHILD MAIN LOOPS */
1664 /* After forking, the child calls one of these functions */
1666 /* We use a double for total size in order to count beyond 4Gb */
1667 static void usage_cb(gpointer data
)
1669 GList
*paths
= (GList
*) data
;
1670 double total_size
= 0;
1673 n
=g_list_length(paths
);
1674 dir_counter
= file_counter
= 0;
1676 for (i
=0; paths
; paths
= paths
->next
, i
++)
1678 guchar
*path
= (guchar
*) paths
->data
;
1687 printf_send("%%%d", per
);
1689 do_usage(path
, NULL
);
1691 printf_send("'%s: %s\n",
1693 format_double_size(size_tally
));
1694 total_size
+= size_tally
;
1696 printf_send("%%-1");
1698 g_string_printf(message
, _("'\nTotal: %s ("),
1699 format_double_size(total_size
));
1702 g_string_append_printf(message
,
1703 "%ld %s%s", file_counter
,
1704 file_counter
== 1 ? _("file") : _("files"),
1705 dir_counter
? ", " : ")\n");
1707 if (file_counter
== 0 && dir_counter
== 0)
1708 g_string_append(message
, _("no directories)\n"));
1709 else if (dir_counter
)
1710 g_string_append_printf(message
,
1711 "%ld %s)\n", dir_counter
,
1712 dir_counter
== 1 ? _("directory")
1713 : _("directories"));
1718 #ifdef DO_MOUNT_POINTS
1719 static void mount_cb(gpointer data
)
1721 GList
*paths
= (GList
*) data
;
1722 gboolean mount_points
= FALSE
;
1725 n
=g_list_length(paths
);
1726 for (i
=0; paths
; paths
= paths
->next
, i
++)
1728 guchar
*path
= (guchar
*) paths
->data
;
1731 target
= pathdup(path
);
1738 printf_send("%%%d", per
);
1740 if (mount_is_mounted(target
, NULL
, NULL
) ||
1741 g_hash_table_lookup(fstab_mounts
, target
))
1743 mount_points
= TRUE
;
1744 do_mount(target
, mount_mount
); /* Mount */
1754 printf_send(_("!No mount points selected!\n"));
1758 /* (use g_dirname() instead?) */
1759 static guchar
*dirname(guchar
*path
)
1763 slash
= strrchr(path
, '/');
1764 g_return_val_if_fail(slash
!= NULL
, g_strdup(path
));
1767 return g_strndup(path
, slash
- path
);
1768 return g_strdup("/");
1771 static void delete_cb(gpointer data
)
1773 GList
*paths
= (GList
*) data
;
1776 n
=g_list_length(paths
);
1777 for (i
=0; paths
; paths
= paths
->next
, i
++)
1779 guchar
*path
= (guchar
*) paths
->data
;
1782 dir
= dirname(path
);
1788 printf_send("%%%d", per
);
1790 do_delete(path
, dir
);
1798 static void eject_cb(gpointer data
)
1800 GList
*paths
= (GList
*) data
;
1803 n
=g_list_length(paths
);
1805 for (i
=0; paths
; paths
= paths
->next
, i
++)
1807 guchar
*path
= (guchar
*) paths
->data
;
1812 printf_send("%%%d", per
);
1822 static void find_cb(gpointer data
)
1824 GList
*all_paths
= (GList
*) data
;
1829 for (paths
= all_paths
; paths
; paths
= paths
->next
)
1831 guchar
*path
= (guchar
*) paths
->data
;
1835 do_find(path
, NULL
);
1838 if (!printf_reply(from_parent
, TRUE
,
1839 _("?Another search?")))
1847 static void chmod_cb(gpointer data
)
1849 GList
*paths
= (GList
*) data
;
1852 n
=g_list_length(paths
);
1854 for (i
=0; paths
; paths
= paths
->next
, i
++)
1856 guchar
*path
= (guchar
*) paths
->data
;
1862 printf_send("%%%d", per
);
1866 if (mc_stat(path
, &info
) != 0)
1868 else if (S_ISLNK(info
.st_mode
))
1869 printf_send(_("!'%s' is a symbolic link\n"),
1872 do_chmod(path
, NULL
);
1878 static void settype_cb(gpointer data
)
1880 GList
*paths
= (GList
*) data
;
1883 n
=g_list_length(paths
);
1885 for (i
=0; paths
; paths
= paths
->next
, i
++)
1887 guchar
*path
= (guchar
*) paths
->data
;
1893 printf_send("%%%d", per
);
1897 if (mc_stat(path
, &info
) != 0)
1899 else if (S_ISLNK(info
.st_mode
))
1900 printf_send(_("!'%s' is a symbolic link\n"),
1903 do_settype(path
, NULL
);
1909 static void list_cb(gpointer data
)
1911 GList
*paths
= (GList
*) data
;
1914 n
=g_list_length(paths
);
1916 for (i
=0; paths
; paths
= paths
->next
, i
++)
1921 printf_send("%%%d", per
);
1923 send_dir((char *) paths
->data
);
1925 action_do_func((char *) paths
->data
, action_dest
);
1931 /* EXTERNAL INTERFACE */
1933 void action_find(GList
*paths
)
1940 report_error(_("You need to select some items "
1941 "to search through"));
1945 if (!last_find_string
)
1946 last_find_string
= g_strdup("'core'");
1948 new_entry_string
= last_find_string
;
1950 abox
= abox_new(_("Find"), FALSE
);
1951 gui_side
= start_action(abox
, find_cb
, paths
,
1952 o_action_force
.int_value
,
1953 o_action_brief
.int_value
,
1954 o_action_recurse
.int_value
,
1955 o_action_newer
.int_value
);
1959 abox_add_results(ABOX(abox
));
1961 gui_side
->default_string
= &last_find_string
;
1962 abox_add_entry(ABOX(abox
), last_find_string
,
1963 new_help_button(show_condition_help
, NULL
));
1964 g_signal_connect(ABOX(abox
)->entry
, "changed",
1965 G_CALLBACK(entry_changed
), gui_side
);
1966 set_find_string_colour(ABOX(abox
)->entry
, last_find_string
);
1968 gui_side
->show_info
= TRUE
;
1969 gui_side
->entry_string_func
= set_find_string_colour
;
1971 number_of_windows
++;
1972 gtk_widget_show(abox
);
1975 /* Count disk space used by selected items */
1976 void action_usage(GList
*paths
)
1983 report_error(_("You need to select some items to count"));
1987 abox
= abox_new(_("Disk Usage"), TRUE
);
1989 gui_side
= start_action(abox
, usage_cb
, paths
,
1990 o_action_force
.int_value
,
1991 o_action_brief
.int_value
,
1992 o_action_recurse
.int_value
,
1993 o_action_newer
.int_value
);
1997 gui_side
->show_info
= TRUE
;
1999 number_of_windows
++;
2001 gtk_widget_show(abox
);
2004 /* Mount/unmount listed items (paths).
2005 * Free the list after this function returns.
2006 * If open_dir is TRUE and the dir is successfully mounted, open it.
2007 * quiet can be -1 for default.
2009 void action_mount(GList
*paths
, gboolean open_dir
, gboolean mount
, int quiet
)
2011 #ifdef DO_MOUNT_POINTS
2016 quiet
= o_action_mount
.int_value
;
2018 mount_open_dir
= open_dir
;
2019 mount_mount
= mount
;
2021 abox
= abox_new(_("Mount / Unmount"), quiet
);
2022 gui_side
= start_action(abox
, mount_cb
, paths
,
2023 o_action_force
.int_value
,
2024 o_action_brief
.int_value
,
2025 o_action_recurse
.int_value
,
2026 o_action_newer
.int_value
);
2030 number_of_windows
++;
2031 gtk_widget_show(abox
);
2034 _("ROX-Filer does not yet support mount points on your "
2036 #endif /* DO_MOUNT_POINTS */
2039 /* Delete these paths */
2040 void action_delete(GList
*paths
)
2045 if (!remove_pinned_ok(paths
))
2048 abox
= abox_new(_("Delete"), o_action_delete
.int_value
);
2049 gui_side
= start_action(abox
, delete_cb
, paths
,
2050 o_action_force
.int_value
,
2051 o_action_brief
.int_value
,
2052 o_action_recurse
.int_value
,
2053 o_action_newer
.int_value
);
2057 abox_add_flag(ABOX(abox
),
2058 _("Force"), _("Don't confirm deletion of non-writeable items"),
2059 'F', o_action_force
.int_value
);
2060 abox_add_flag(ABOX(abox
),
2061 _("Brief"), _("Only log directories being deleted"),
2062 'B', o_action_brief
.int_value
);
2064 number_of_windows
++;
2065 gtk_widget_show(abox
);
2068 /* Change the permissions of the selected items */
2069 void action_chmod(GList
*paths
, gboolean force_recurse
, const char *action
)
2073 static GList
*presets
= NULL
;
2074 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2078 report_error(_("You need to select the items "
2079 "whose permissions you want to change"));
2085 presets
= g_list_append(presets
, (gchar
*)
2086 _("a+x (Make executable/searchable)"));
2087 presets
= g_list_append(presets
, (gchar
*)
2088 _("a-x (Make non-executable/non-searchable)"));
2089 presets
= g_list_append(presets
, (gchar
*)
2090 _("u+rw (Give owner read+write)"));
2091 presets
= g_list_append(presets
, (gchar
*)
2092 _("go-rwx (Private - owner access only)"));
2093 presets
= g_list_append(presets
, (gchar
*)
2094 _("go=u-w (Public access, not write)"));
2097 if (!last_chmod_string
)
2098 last_chmod_string
= g_strdup((guchar
*) presets
->data
);
2101 new_entry_string
= g_strdup(action
);
2103 new_entry_string
= g_strdup(last_chmod_string
);
2105 abox
= abox_new(_("Permissions"), FALSE
);
2106 gui_side
= start_action(abox
, chmod_cb
, paths
,
2107 o_action_force
.int_value
,
2108 o_action_brief
.int_value
,
2110 o_action_newer
.int_value
);
2115 abox_add_flag(ABOX(abox
),
2116 _("Brief"), _("Don't list processed files"),
2117 'B', o_action_brief
.int_value
);
2118 abox_add_flag(ABOX(abox
),
2119 _("Recurse"), _("Also change contents of subdirectories"),
2122 gui_side
->default_string
= &last_chmod_string
;
2123 abox_add_combo(ABOX(abox
), _("Command:"), presets
, new_entry_string
,
2124 new_help_button(show_chmod_help
, NULL
));
2126 g_signal_connect(ABOX(abox
)->entry
, "changed",
2127 G_CALLBACK(entry_changed
), gui_side
);
2129 g_signal_connect_swapped(gui_side
->entry
, "activate",
2130 G_CALLBACK(gtk_button_clicked
),
2134 number_of_windows
++;
2135 gtk_widget_show(abox
);
2138 null_g_free(&new_entry_string
);
2141 /* Set the MIME type of the selected items */
2142 void action_settype(GList
*paths
, gboolean force_recurse
, const char *oldtype
)
2146 GList
*presets
= NULL
;
2147 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2151 report_error(_("You need to select the items "
2152 "whose type you want to change"));
2156 if (!last_settype_string
)
2157 last_settype_string
= g_strdup("text/plain");
2160 new_entry_string
= g_strdup(oldtype
);
2162 new_entry_string
= g_strdup(last_settype_string
);
2164 abox
= abox_new(_("Set type"), FALSE
);
2165 gui_side
= start_action(abox
, settype_cb
, paths
,
2166 o_action_force
.int_value
,
2167 o_action_brief
.int_value
,
2169 o_action_newer
.int_value
);
2174 abox_add_flag(ABOX(abox
),
2175 _("Brief"), _("Don't list processed files"),
2176 'B', o_action_brief
.int_value
);
2177 abox_add_flag(ABOX(abox
),
2178 _("Recurse"), _("Change contents of subdirectories"),
2181 gui_side
->default_string
= &last_settype_string
;
2183 /* Note: get the list again each time -- it can change */
2184 presets
= mime_type_name_list();
2185 abox_add_combo(ABOX(abox
), _("Type:"), presets
, new_entry_string
,
2186 new_help_button(show_settype_help
, NULL
));
2187 g_list_free(presets
);
2189 g_signal_connect(ABOX(abox
)->entry
, "changed",
2190 G_CALLBACK(entry_changed
), gui_side
);
2192 number_of_windows
++;
2193 gtk_widget_show(abox
);
2196 null_g_free(&new_entry_string
);
2199 /* If leaf is NULL then the copy has the same name as the original.
2200 * quiet can be -1 for default.
2202 void action_copy(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2208 quiet
= o_action_copy
.int_value
;
2212 action_do_func
= do_copy
;
2214 abox
= abox_new(_("Copy"), quiet
);
2215 gui_side
= start_action(abox
, list_cb
, paths
,
2216 o_action_force
.int_value
,
2217 o_action_brief
.int_value
,
2218 o_action_recurse
.int_value
,
2219 o_action_newer
.int_value
);
2223 abox_add_flag(ABOX(abox
),
2225 _("Only over-write if source is newer than destination."),
2226 'W', o_action_newer
.int_value
);
2227 abox_add_flag(ABOX(abox
),
2228 _("Brief"), _("Only log directories as they are copied"),
2229 'B', o_action_brief
.int_value
);
2231 number_of_windows
++;
2232 gtk_widget_show(abox
);
2235 /* If leaf is NULL then the file is not renamed.
2236 * quiet can be -1 for default.
2238 void action_move(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2244 quiet
= o_action_move
.int_value
;
2248 action_do_func
= do_move
;
2250 abox
= abox_new(_("Move"), quiet
);
2251 gui_side
= start_action(abox
, list_cb
, paths
,
2252 o_action_force
.int_value
,
2253 o_action_brief
.int_value
,
2254 o_action_recurse
.int_value
,
2255 o_action_newer
.int_value
);
2259 abox_add_flag(ABOX(abox
),
2261 _("Only over-write if source is newer than destination."),
2262 'W', o_action_newer
.int_value
);
2263 abox_add_flag(ABOX(abox
),
2264 _("Brief"), _("Don't log each file as it is moved"),
2265 'B', o_action_brief
.int_value
);
2266 number_of_windows
++;
2267 gtk_widget_show(abox
);
2270 /* If leaf is NULL then the link will have the same name */
2271 void action_link(GList
*paths
, const char *dest
, const char *leaf
,
2280 action_do_func
= do_link_relative
;
2282 action_do_func
= do_link_absolute
;
2284 abox
= abox_new(_("Link"), o_action_link
.int_value
);
2285 gui_side
= start_action(abox
, list_cb
, paths
,
2286 o_action_force
.int_value
,
2287 o_action_brief
.int_value
,
2288 o_action_recurse
.int_value
,
2289 o_action_newer
.int_value
);
2293 number_of_windows
++;
2294 gtk_widget_show(abox
);
2297 /* Eject these paths */
2298 void action_eject(GList
*paths
)
2303 abox
= abox_new(_("Eject"), TRUE
);
2304 gui_side
= start_action(abox
, eject_cb
, paths
,
2305 o_action_force
.int_value
,
2306 o_action_brief
.int_value
,
2307 o_action_recurse
.int_value
,
2308 o_action_newer
.int_value
);
2312 number_of_windows
++;
2313 gtk_widget_show(abox
);
2316 void action_init(void)
2318 option_add_int(&o_action_copy
, "action_copy", 1);
2319 option_add_int(&o_action_move
, "action_move", 1);
2320 option_add_int(&o_action_link
, "action_link", 1);
2321 option_add_int(&o_action_delete
, "action_delete", 0);
2322 option_add_int(&o_action_mount
, "action_mount", 1);
2323 option_add_int(&o_action_force
, "action_force", FALSE
);
2324 option_add_int(&o_action_brief
, "action_brief", FALSE
);
2325 option_add_int(&o_action_recurse
, "action_recurse", FALSE
);
2326 option_add_int(&o_action_newer
, "action_newer", FALSE
);
2331 /* Check to see if any of the selected items (or their children) are
2332 * on the pinboard or panel. If so, ask for confirmation.
2334 * TRUE if it's OK to lose them.
2336 static gboolean
remove_pinned_ok(GList
*paths
)
2338 GList
*ask
= NULL
, *next
;
2343 for (; paths
; paths
= paths
->next
)
2345 guchar
*path
= (guchar
*) paths
->data
;
2347 if (icons_require(path
))
2349 if (++ask_n
> MAX_ASK
)
2351 ask
= g_list_append(ask
, path
);
2358 if (ask_n
> MAX_ASK
)
2360 message
= g_string_new(_("Deleting items such as "));
2363 else if (ask_n
== 1)
2364 message
= g_string_new(_("Deleting the item "));
2366 message
= g_string_new(_("Deleting the items "));
2369 for (next
= ask
; next
; next
= next
->next
)
2371 guchar
*path
= (guchar
*) next
->data
;
2374 leaf
= strrchr(path
, '/');
2380 g_string_append_c(message
, '`');
2381 g_string_append(message
, leaf
);
2382 g_string_append_c(message
, '\'');
2384 if (i
== ask_n
- 1 && i
> 0)
2385 g_string_append(message
, _(" and "));
2387 g_string_append(message
, ", ");
2393 message
= g_string_append(message
,
2394 _(" will affect some items on the pinboard "
2395 "or panel - really delete it?"));
2398 if (ask_n
> MAX_ASK
)
2399 message
= g_string_append_c(message
, ',');
2400 message
= g_string_append(message
,
2401 _(" will affect some items on the pinboard "
2402 "or panel - really delete them?"));
2405 retval
= confirm(message
->str
, GTK_STOCK_DELETE
, NULL
);
2407 g_string_free(message
, TRUE
);
2412 void set_find_string_colour(GtkWidget
*widget
, const guchar
*string
)
2414 FindCondition
*cond
;
2416 cond
= find_compile(string
);
2417 entry_set_error(widget
, !cond
);
2419 find_condition_free(cond
);