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 int from_parent
= 0;
101 static FILE *to_parent
= NULL
;
102 static gboolean quiet
= FALSE
;
103 static GString
*message
= NULL
;
104 static const char *action_dest
= NULL
;
105 static const char *action_leaf
= NULL
;
106 static void (*action_do_func
)(const char *source
, const char *dest
);
107 static double size_tally
; /* For Disk Usage */
108 static unsigned long dir_counter
; /* For Disk Usage */
109 static unsigned long file_counter
; /* For Disk Usage */
111 static struct mode_change
*mode_change
= NULL
; /* For Permissions */
112 static FindCondition
*find_condition
= NULL
; /* For Find */
113 static MIME_type
*type_change
= NULL
;
115 /* Only used by child */
116 static gboolean o_force
= FALSE
;
117 static gboolean o_brief
= FALSE
;
118 static gboolean o_recurse
= FALSE
;
119 static gboolean o_newer
= FALSE
;
121 static Option o_action_copy
, o_action_move
, o_action_link
;
122 static Option o_action_delete
, o_action_mount
;
123 static Option o_action_force
, o_action_brief
, o_action_recurse
;
124 static Option o_action_newer
;
126 /* Whenever the text in these boxes is changed we store a copy of the new
127 * string to be used as the default next time.
129 static guchar
*last_chmod_string
= NULL
;
130 static guchar
*last_find_string
= NULL
;
131 static guchar
*last_settype_string
= NULL
;
133 /* Set to one of the above before forking. This may change over a call to
134 * reply(). It is reset to NULL once the text is parsed.
136 static guchar
*new_entry_string
= NULL
;
138 /* Static prototypes */
139 static void send_done(void);
140 static void send_check_path(const gchar
*path
);
141 static void send_mount_path(const gchar
*path
);
142 static gboolean
printf_send(const char *msg
, ...);
143 static gboolean
send_msg(void);
144 static gboolean
send_error(void);
145 static gboolean
send_dir(const char *dir
);
146 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
);
147 static void do_mount(const guchar
*path
, gboolean mount
);
148 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
149 const char *msg
, ...);
150 static gboolean
remove_pinned_ok(GList
*paths
);
155 /* This is called whenever the user edits the entry box (if any) - send the
158 static void entry_changed(GtkEditable
*entry
, GUIside
*gui_side
)
162 g_return_if_fail(gui_side
->default_string
!= NULL
);
164 text
= gtk_editable_get_chars(entry
, 0, -1);
166 if (gui_side
->entry_string_func
)
167 gui_side
->entry_string_func(GTK_WIDGET(entry
), text
);
169 g_free(*(gui_side
->default_string
));
170 *(gui_side
->default_string
) = text
; /* Gets text's ref */
172 if (!gui_side
->to_child
)
175 fputc('E', gui_side
->to_child
);
176 fputs(text
, gui_side
->to_child
);
177 fputc('\n', gui_side
->to_child
);
178 fflush(gui_side
->to_child
);
181 void show_condition_help(gpointer data
)
186 help
= gtk_dialog_new_with_buttons(
187 _("Find expression reference"),
189 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
191 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
193 text
= gtk_label_new(NULL
);
194 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
195 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
196 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
197 gtk_label_set_markup(GTK_LABEL(text
), _(
198 "<u>Quick Start</u>\n"
199 "Just put the name of the file you're looking for in single quotes:\n"
200 "<b>'index.html'</b> (to find a file called 'index.html')\n"
203 "<b>'*.htm', '*.html'</b> (finds HTML files)\n"
204 "<b>IsDir 'lib'</b> (finds directories called 'lib')\n"
205 "<b>IsReg 'core'</b> (finds a regular file called 'core')\n"
206 "<b>! (IsDir, IsReg)</b> (is neither a directory nor a regular file)\n"
207 "<b>mtime after 1 day ago and size > 1Mb</b> (big, and recently modified)\n"
208 "<b>'CVS' prune, isreg</b> (a regular file not in CVS)\n"
209 "<b>IsReg system(grep -q fred \"%\")</b> (contains the word 'fred')\n"
211 "<u>Simple Tests</u>\n"
212 "<b>IsReg, IsLink, IsDir, IsChar, IsBlock, IsDev, IsPipe, IsSocket, IsDoor</b> "
214 "<b>IsSUID, IsSGID, IsSticky, IsReadable, IsWriteable, IsExecutable</b> "
216 "<b>IsEmpty, IsMine</b>\n"
217 "A pattern in single quotes is a shell-style wildcard pattern to match. If it\n"
218 "contains a slash then the match is against the full path; otherwise it is\n"
219 "against the leafname only.\n"
221 "<u>Comparisons</u>\n"
222 "<b><, <=, =, !=, >, >=, After, Before</b> (compare two values)\n"
223 "<b>5 bytes, 1Kb, 2Mb, 3Gb</b> (file sizes)\n"
224 "<b>2 secs|mins|hours|days|weeks|years ago|hence</b> (times)\n"
225 "<b>atime, ctime, mtime, now, size, inode, nlinks, uid, gid, blocks</b> "
229 "<b>system(command)</b> (true if 'command' returns with a zero exit status;\n"
230 "a % in 'command' is replaced with the path of the current file)\n"
231 "<b>prune</b> (false, and prevents searching the contents of a directory)."));
233 g_signal_connect(help
, "response",
234 G_CALLBACK(gtk_widget_destroy
), NULL
);
236 gtk_widget_show_all(help
);
239 static void show_chmod_help(gpointer data
)
244 help
= gtk_dialog_new_with_buttons(
245 _("Change permissions reference"),
247 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
249 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
251 text
= gtk_label_new(NULL
);
252 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
253 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
254 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
255 gtk_label_set_markup(GTK_LABEL(text
), _(
256 "Normally, you can just select a command from the menu (click \n"
257 "on the arrow beside the command box). Sometimes, you need more...\n"
259 "The format of a command is: <b>CHANGE, CHANGE, ...</b>\n"
260 "Each <b>CHANGE</b> is: <b>WHO HOW PERMISSIONS</b>\n"
261 "<b>WHO</b> is some combination of <b>u</b>, <b>g</b> and <b>o</b> which "
262 "determines whether to\n"
263 "change the permissions for the User (owner), Group or Others.\n"
264 "<b>HOW</b> is <b>+</b>, <b>-</b> or <b>=</b> to add, remove or set "
265 "exactly the permissions.\n"
266 "<b>PERMISSIONS</b> is some combination of the letters <b>rwxXstugo</b>\n"
268 "Bracketed text and spaces are ignored.\n"
271 "<b>u+rw</b>: the file owner gains read and write permission\n"
272 "<b>g=u</b>: the group permissions are set to be the same as the user's\n"
273 "<b>o=u-w</b>: others get the same permissions as the owner, but without "
275 "<b>a+x</b>: <b>a</b>ll get execute/access permission - same as <b>ugo+x</b>\n"
276 "<b>a+X</b>: directories become accessable by everyone; files which were\n"
277 "executable by anyone become executable by everyone\n"
278 "<b>u+rw, go+r</b>: two commands at once!\n"
279 "<b>u+s</b>: set the SetUID bit - often has no effect on script files\n"
280 "<b>755</b>: set the permissions directly\n"
282 "See the chmod(1) man page for full details."));
284 g_signal_connect(help
, "response",
285 G_CALLBACK(gtk_widget_destroy
), NULL
);
287 gtk_widget_show_all(help
);
291 static void show_settype_help(gpointer data
)
296 help
= gtk_dialog_new_with_buttons(
297 _("Set type reference"),
299 GTK_STOCK_CLOSE
, GTK_RESPONSE_CANCEL
,
301 gtk_dialog_set_default_response(GTK_DIALOG(help
), GTK_RESPONSE_CANCEL
);
303 text
= gtk_label_new(NULL
);
304 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
305 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
306 gtk_label_set_selectable(GTK_LABEL(text
), TRUE
);
307 gtk_label_set_markup(GTK_LABEL(text
), _(
308 "Normally ROX-Filer determines the type of a regular file\n"
309 "by matching it's name against a pattern. To change the\n"
310 "type of the file you must rename it.\n"
312 "Newer file systems can support something called 'Extended\n"
313 "Attributes' which can be used to store additional data with\n"
314 "each file as named parameters. ROX-Filer uses the\n"
315 "'user.mime_type' attribute to store file types.\n"
317 "File types are only supported for regular files, not\n"
318 "directories, devices, pipes or sockets, and then only\n"
319 "on certain file systems and where the OS implements them.\n"));
321 text
= gtk_label_new(_(ATTR_MAN_PAGE
));
322 gtk_misc_set_padding(GTK_MISC(text
), 2, 2);
323 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help
)->vbox
), text
);
325 g_signal_connect(help
, "response",
326 G_CALLBACK(gtk_widget_destroy
), NULL
);
328 gtk_widget_show_all(help
);
331 static void process_message(GUIside
*gui_side
, const gchar
*buffer
)
333 ABox
*abox
= gui_side
->abox
;
336 abox_ask(abox
, buffer
+ 1);
337 else if (*buffer
== 's')
338 dir_check_this(buffer
+ 1); /* Update this item */
339 else if (*buffer
== '=')
340 abox_add_filename(abox
, buffer
+ 1);
341 else if (*buffer
== '#')
342 abox_clear_results(abox
);
343 else if (*buffer
== 'X')
345 filer_close_recursive(buffer
+ 1);
346 /* Let child know it's safe to continue... */
347 fputc('X', gui_side
->to_child
);
348 fflush(gui_side
->to_child
);
350 else if (*buffer
== 'm' || *buffer
== 'M')
352 /* Mount / major changes to this path */
356 mount_user_mount(buffer
+ 1);
358 filer_check_mounted(buffer
+ 1);
360 else if (*buffer
== '/')
361 abox_set_current_object(abox
, buffer
+ 1);
362 else if (*buffer
== 'o')
363 filer_opendir(buffer
+ 1, NULL
, NULL
);
364 else if (*buffer
== '!')
367 abox_log(abox
, buffer
+ 1, "error");
369 else if (*buffer
== '<')
370 abox_set_file(abox
, 0, buffer
+1);
371 else if (*buffer
== '>')
373 abox_set_file(abox
, 1, buffer
+1);
374 abox_show_compare(abox
, TRUE
);
376 else if (*buffer
== '%')
378 abox_set_percentage(abox
, atoi(buffer
+1));
381 abox_log(abox
, buffer
+ 1, NULL
);
384 /* Called when the child sends us a message */
385 static void message_from_child(gpointer data
,
387 GdkInputCondition condition
)
390 GUIside
*gui_side
= (GUIside
*) data
;
391 ABox
*abox
= gui_side
->abox
;
392 GtkTextBuffer
*text_buffer
;
394 text_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
));
396 if (read_exact(source
, buf
, 4))
402 message_len
= strtol(buf
, NULL
, 16);
403 buffer
= g_malloc(message_len
+ 1);
404 if (message_len
> 0 && read_exact(source
, buffer
, message_len
))
406 buffer
[message_len
] = '\0';
407 process_message(gui_side
, buffer
);
411 g_printerr("Child died in the middle of a message.\n");
414 if (gui_side
->abort_attempts
)
415 abox_log(abox
, _("\nProcess terminated.\n"), "error");
417 /* The child is dead */
420 fclose(gui_side
->to_child
);
421 gui_side
->to_child
= NULL
;
422 close(gui_side
->from_child
);
423 g_source_remove(gui_side
->input_tag
);
424 abox_cancel_ask(gui_side
->abox
);
426 if (gui_side
->errors
)
430 if (gui_side
->errors
== 1)
431 report
= g_strdup(_("There was one error.\n"));
433 report
= g_strdup_printf(_("There were %d errors.\n"),
436 gtk_text_buffer_insert_at_cursor(text_buffer
, report
, -1);
440 else if (gui_side
->show_info
== FALSE
)
441 gtk_widget_destroy(GTK_WIDGET(gui_side
->abox
));
444 /* Scans src_dir, calling cb(item, dest_path) for each item */
445 static void for_dir_contents(ForDirCB
*cb
,
447 const char *dest_path
)
451 GList
*list
= NULL
, *next
;
453 d
= mc_opendir(src_dir
);
456 /* Message displayed is "ERROR reading 'path': message" */
457 printf_send("!%s '%s': %s\n", _("ERROR reading"),
458 src_dir
, g_strerror(errno
));
464 while ((ent
= mc_readdir(d
)))
466 if (ent
->d_name
[0] == '.' && (ent
->d_name
[1] == '\0'
467 || (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')))
469 list
= g_list_prepend(list
, g_strdup(make_path(src_dir
,
474 for (next
= list
; next
; next
= next
->next
)
476 cb((char *) next
->data
, dest_path
);
483 /* Read this many bytes into the buffer. TRUE on success. */
484 static gboolean
read_exact(int source
, char *buffer
, ssize_t len
)
489 got
= read(source
, buffer
, len
);
498 static void send_done(void)
500 printf_send(_("'\nDone\n"));
503 /* Notify the filer that this item has been updated */
504 static void send_check_path(const gchar
*path
)
506 printf_send("s%s", path
);
509 /* Notify the filer that this whole subtree has changed (eg, been unmounted) */
510 static void send_mount_path(const gchar
*path
)
512 printf_send("m%s", path
);
515 /* Send a message to the filer process. The first character indicates the
516 * type of the message.
518 static gboolean
printf_send(const char *msg
, ...)
524 tmp
= g_strdup_vprintf(msg
, args
);
527 g_string_assign(message
, tmp
);
533 /* Send 'message' to our parent process. TRUE on success. */
534 static gboolean
send_msg(void)
539 g_return_val_if_fail(message
->len
< 0xffff, FALSE
);
541 sprintf(len_buffer
, "%04" G_GSIZE_MODIFIER
"x", message
->len
);
542 fwrite(len_buffer
, 1, 4, to_parent
);
543 len
= fwrite(message
->str
, 1, message
->len
, to_parent
);
545 return len
== (ssize_t
) message
->len
;
548 /* Set the directory indicator at the top of the window */
549 static gboolean
send_dir(const char *dir
)
551 return printf_send("/%s", dir
);
554 static gboolean
send_error(void)
556 return printf_send("!%s: %s\n", _("ERROR"), g_strerror(errno
));
559 static void response(GtkDialog
*dialog
, gint response
, GUIside
*gui_side
)
563 if (!gui_side
->to_child
)
566 if (response
== GTK_RESPONSE_YES
)
568 else if (response
== GTK_RESPONSE_NO
)
573 fputc(code
, gui_side
->to_child
);
574 fflush(gui_side
->to_child
);
575 abox_show_compare(gui_side
->abox
, FALSE
);
578 static void flag_toggled(ABox
*abox
, gint flag
, GUIside
*gui_side
)
580 if (!gui_side
->to_child
)
583 fputc(flag
, gui_side
->to_child
);
584 fflush(gui_side
->to_child
);
587 static void read_new_entry_text(void)
593 new = g_string_new(NULL
);
597 len
= read(from_parent
, &c
, 1);
600 fprintf(stderr
, "read() error: %s\n",
602 _exit(1); /* Parent died? */
607 g_string_append_c(new, c
);
610 g_free(new_entry_string
);
611 new_entry_string
= new->str
;
612 g_string_free(new, FALSE
);
615 static void process_flag(char flag
)
626 o_recurse
= !o_recurse
;
635 read_new_entry_text();
638 printf_send("!ERROR: Bad message '%c'\n", flag
);
643 /* If the parent has sent any flag toggles, read them */
644 static void check_flags(void)
655 FD_SET(from_parent
, &set
);
658 got
= select(from_parent
+ 1, &set
, NULL
, NULL
, &tv
);
661 g_error("select() failed: %s\n", g_strerror(errno
));
665 got
= read(from_parent
, &retval
, 1);
667 g_error("read() error: %s\n", g_strerror(errno
));
669 process_flag(retval
);
673 /* Read until the user sends a reply. If ignore_quiet is TRUE then
674 * the user MUST click Yes or No, else treat quiet on as Yes.
675 * If the user needs prompting then does send_msg().
677 static gboolean
printf_reply(int fd
, gboolean ignore_quiet
,
678 const char *msg
, ...)
685 if (quiet
&& !ignore_quiet
)
689 tmp
= g_strdup_vprintf(msg
, args
);
692 g_string_assign(message
, tmp
);
699 len
= read(fd
, &retval
, 1);
702 fprintf(stderr
, "read() error: %s\n",
704 _exit(1); /* Parent died? */
710 printf_send("' %s\n", _("Yes"));
713 printf_send("' %s\n", _("No"));
716 process_flag(retval
);
722 static void abort_operation(GtkWidget
*widget
, gpointer data
)
724 GUIside
*gui_side
= (GUIside
*) data
;
728 if (gui_side
->abort_attempts
== 0)
730 abox_log(ABOX(widget
),
731 _("\nAsking child process to terminate...\n"),
733 kill(-gui_side
->child
, SIGTERM
);
737 abox_log(ABOX(widget
),
738 _("\nTrying to KILL run-away process...\n"),
740 kill(-gui_side
->child
, SIGKILL
);
741 kill(-gui_side
->child
, SIGCONT
);
743 gui_side
->abort_attempts
++;
746 gtk_widget_destroy(widget
);
749 static void destroy_action_window(GtkWidget
*widget
, gpointer data
)
751 GUIside
*gui_side
= (GUIside
*) data
;
755 kill(-gui_side
->child
, SIGTERM
);
756 fclose(gui_side
->to_child
);
757 close(gui_side
->from_child
);
758 g_source_remove(gui_side
->input_tag
);
766 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
767 * (NULL on failure). The child calls func().
769 static GUIside
*start_action(GtkWidget
*abox
, ActionChild
*func
, gpointer data
,
770 int force
, int brief
, int recurse
, int newer
)
773 int filedes
[4]; /* 0 and 2 are for reading */
776 struct sigaction act
;
780 report_error("pipe: %s", g_strerror(errno
));
781 gtk_widget_destroy(abox
);
785 if (pipe(filedes
+ 2))
789 report_error("pipe: %s", g_strerror(errno
));
790 gtk_widget_destroy(abox
);
794 autoq
= gtk_toggle_button_get_active(
795 GTK_TOGGLE_BUTTON(ABOX(abox
)->quiet
));
806 report_error("fork: %s", g_strerror(errno
));
807 gtk_widget_destroy(abox
);
810 /* We are the child */
812 /* Create a new process group */
817 dir_drop_all_dnotifies();
819 /* Reset the SIGCHLD handler */
820 act
.sa_handler
= SIG_DFL
;
821 sigemptyset(&act
.sa_mask
);
823 sigaction(SIGCHLD
, &act
, NULL
);
825 message
= g_string_new(NULL
);
828 to_parent
= fdopen(filedes
[1], "wb");
829 from_parent
= filedes
[2];
835 /* We are the parent */
838 gui_side
= g_new(GUIside
, 1);
839 gui_side
->from_child
= filedes
[0];
840 gui_side
->to_child
= fdopen(filedes
[3], "wb");
841 gui_side
->child
= child
;
842 gui_side
->errors
= 0;
843 gui_side
->show_info
= FALSE
;
844 gui_side
->default_string
= NULL
;
845 gui_side
->entry_string_func
= NULL
;
846 gui_side
->abort_attempts
= 0;
848 gui_side
->abox
= ABOX(abox
);
849 g_signal_connect(abox
, "destroy",
850 G_CALLBACK(destroy_action_window
), gui_side
);
852 g_signal_connect(abox
, "response", G_CALLBACK(response
), gui_side
);
853 g_signal_connect(abox
, "flag_toggled",
854 G_CALLBACK(flag_toggled
), gui_side
);
855 g_signal_connect(abox
, "abort_operation",
856 G_CALLBACK(abort_operation
), gui_side
);
858 gui_side
->input_tag
= gdk_input_add_full(gui_side
->from_child
,
866 /* ACTIONS ON ONE ITEM */
868 /* These may call themselves recursively, or ask questions, etc */
870 /* Updates the global size_tally, file_counter and dir_counter */
871 static void do_usage(const char *src_path
, const char *unused
)
877 if (mc_lstat(src_path
, &info
))
879 printf_send("'%s:\n", src_path
);
882 else if (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
885 size_tally
+= info
.st_size
;
887 else if (S_ISDIR(info
.st_mode
))
890 if (printf_reply(from_parent
, FALSE
,
891 _("?Count contents of %s?"), src_path
))
894 safe_path
= g_strdup(src_path
);
895 for_dir_contents(do_usage
, safe_path
, safe_path
);
903 /* dest_path is the dir containing src_path */
904 static void do_delete(const char *src_path
, const char *unused
)
912 if (mc_lstat(src_path
, &info
))
918 write_prot
= S_ISLNK(info
.st_mode
) ? FALSE
919 : access(src_path
, W_OK
) != 0;
920 if (write_prot
|| !quiet
)
924 printf_send("<%s", src_path
);
926 res
=printf_reply(from_parent
, write_prot
&& !o_force
,
927 _("?Delete %s'%s'?"),
928 write_prot
? _("WRITE-PROTECTED ") : "",
935 printf_send(_("'Deleting '%s'\n"), src_path
);
937 safe_path
= g_strdup(src_path
);
939 if (S_ISDIR(info
.st_mode
))
941 for_dir_contents(do_delete
, safe_path
, safe_path
);
942 if (rmdir(safe_path
))
948 printf_send(_("'Directory '%s' deleted\n"), safe_path
);
949 send_mount_path(safe_path
);
951 else if (unlink(src_path
))
955 send_check_path(safe_path
);
956 if (strcmp(g_basename(safe_path
), ".DirIcon") == 0)
959 dir
= g_path_get_dirname(safe_path
);
960 send_check_path(dir
);
968 static void do_eject(const char *path
)
970 const char *argv
[3] = {NULL
, NULL
, NULL
};
978 printf_send("<%s", path
);
980 res
=printf_reply(from_parent
, !o_force
,
988 printf_send(_("'Eject '%s'\n"), path
);
990 /* Need to close all sub-directories now, or we
991 * can't unmount if dnotify is used.
995 printf_send("X%s", path
);
996 /* Wait until it's safe... */
997 read(from_parent
, &c
, 1);
998 g_return_if_fail(c
== 'X');
1004 err
= fork_exec_wait(argv
);
1007 printf_send(_("!%s\neject failed\n"), err
);
1011 printf_send("M%s", path
);
1015 /* path is the item to check. If is is a directory then we may recurse
1016 * (unless prune is used).
1018 static void do_find(const char *path
, const char *unused
)
1026 if (!printf_reply(from_parent
, FALSE
, _("?Check '%s'?"), path
))
1032 if (new_entry_string
)
1034 find_condition_free(find_condition
);
1035 find_condition
= find_compile(new_entry_string
);
1036 null_g_free(&new_entry_string
);
1042 printf_send(_("!Invalid find condition - "
1043 "change it and try again\n"));
1044 if (!printf_reply(from_parent
, TRUE
,
1045 _("?Check '%s'?"), path
))
1049 if (mc_lstat(path
, &info
.stats
))
1052 printf_send(_("'(while checking '%s')\n"), path
);
1056 info
.fullpath
= path
;
1057 time(&info
.now
); /* XXX: Not for each check! */
1059 info
.leaf
= g_basename(path
);
1061 if (find_test_condition(find_condition
, &info
))
1062 printf_send("=%s", path
);
1064 if (S_ISDIR(info
.stats
.st_mode
) && !info
.prune
)
1067 safe_path
= g_strdup(path
);
1068 for_dir_contents(do_find
, safe_path
, safe_path
);
1073 /* Like mode_compile(), but ignores spaces and bracketed bits */
1074 static struct mode_change
*nice_mode_compile(const char *mode_string
,
1075 unsigned int masked_ops
)
1079 struct mode_change
*retval
= NULL
;
1081 new = g_string_new(NULL
);
1083 for (; *mode_string
; mode_string
++)
1085 if (*mode_string
== '(')
1087 if (*mode_string
== ')')
1095 if (brackets
== 0 && *mode_string
!= ' ')
1096 g_string_append_c(new, *mode_string
);
1100 retval
= mode_compile(new->str
, masked_ops
);
1101 g_string_free(new, TRUE
);
1105 static void do_chmod(const char *path
, const char *unused
)
1112 if (mc_lstat(path
, &info
))
1117 if (S_ISLNK(info
.st_mode
))
1123 printf_send("<%s", path
);
1125 res
=printf_reply(from_parent
, FALSE
,
1126 _("?Change permissions of '%s'?"), path
);
1132 printf_send(_("'Changing permissions of '%s'\n"), path
);
1136 if (new_entry_string
)
1139 mode_free(mode_change
);
1140 mode_change
= nice_mode_compile(new_entry_string
,
1142 null_g_free(&new_entry_string
);
1149 _("!Invalid mode command - change it and try again\n"));
1150 if (!printf_reply(from_parent
, TRUE
,
1151 _("?Change permissions of '%s'?"), path
))
1155 if (mc_lstat(path
, &info
))
1160 if (S_ISLNK(info
.st_mode
))
1163 new_mode
= mode_adjust(info
.st_mode
, mode_change
);
1164 if (chmod(path
, new_mode
))
1170 send_check_path(path
);
1172 if (S_ISDIR(info
.st_mode
))
1174 send_mount_path(path
);
1179 safe_path
= g_strdup(path
);
1180 for_dir_contents(do_chmod
, safe_path
, safe_path
);
1186 static void do_settype(const char *path
, const char *unused
)
1192 if (mc_lstat(path
, &info
))
1197 if (S_ISLNK(info
.st_mode
))
1203 printf_send("<%s", path
);
1205 res
=printf_reply(from_parent
, FALSE
,
1206 _("?Change type of '%s'?"), path
);
1214 if (new_entry_string
)
1216 type_change
= mime_type_lookup(new_entry_string
);
1217 null_g_free(&new_entry_string
);
1223 printf_send(_("!Invalid type - "
1224 "change it and try again\n"));
1225 if (!printf_reply(from_parent
, TRUE
,
1226 _("?Change type of '%s'?"), path
))
1230 if (mc_lstat(path
, &info
))
1235 if (S_ISLNK(info
.st_mode
))
1238 if (S_ISREG(info
.st_mode
))
1242 const char *comment
;
1244 comment
= mime_type_comment(type_change
);
1245 printf_send(_("'Changing type of '%s' to '%s'\n"), path
,
1249 if (xtype_set(path
, type_change
))
1255 send_check_path(path
);
1257 else if (S_ISDIR(info
.st_mode
))
1262 safe_path
= g_strdup(path
);
1263 for_dir_contents(do_settype
, safe_path
, unused
);
1269 /* We want to copy 'object' into directory 'dir'. If 'action_leaf'
1270 * is set then that is the new leafname, otherwise the leafname stays
1273 static const char *make_dest_path(const char *object
, const char *dir
)
1281 leaf
= strrchr(object
, '/');
1283 leaf
= object
; /* Error? */
1288 return make_path(dir
, leaf
);
1291 /* If action_leaf is not NULL it specifies the new leaf name */
1292 static void do_copy2(const char *path
, const char *dest
)
1294 const char *dest_path
;
1296 struct stat dest_info
;
1300 dest_path
= make_dest_path(path
, dest
);
1302 if (mc_lstat(path
, &info
))
1308 if (mc_lstat(dest_path
, &dest_info
) == 0)
1313 merge
= S_ISDIR(info
.st_mode
) && S_ISDIR(dest_info
.st_mode
);
1315 if (!merge
&& o_newer
&& info
.st_mtime
> dest_info
.st_mtime
)
1317 /* Newer; keep going */
1321 printf_send("<%s", path
);
1322 printf_send(">%s", dest_path
);
1323 if (!printf_reply(from_parent
, TRUE
,
1324 _("?'%s' already exists - %s?"),
1326 merge
? _("merge contents")
1333 if (S_ISDIR(dest_info
.st_mode
))
1334 err
= rmdir(dest_path
);
1336 err
= unlink(dest_path
);
1341 if (errno
!= ENOENT
)
1343 printf_send(_("'Trying copy anyway...\n"));
1349 printf_send("<%s", path
);
1351 if (!printf_reply(from_parent
, FALSE
,
1352 _("?Copy %s as %s?"), path
, dest_path
))
1355 else if (!o_brief
|| S_ISDIR(info
.st_mode
))
1356 printf_send(_("'Copying %s as %s\n"), path
, dest_path
);
1358 if (S_ISDIR(info
.st_mode
))
1360 mode_t mode
= info
.st_mode
;
1361 char *safe_path
, *safe_dest
;
1362 struct stat dest_info
;
1365 safe_path
= g_strdup(path
);
1366 safe_dest
= g_strdup(dest_path
);
1368 exists
= !mc_lstat(dest_path
, &dest_info
);
1370 if (exists
&& !S_ISDIR(dest_info
.st_mode
))
1371 printf_send(_("!ERROR: Destination already exists, "
1372 "but is not a directory\n"));
1373 else if (exists
== FALSE
&& mkdir(dest_path
, 0700 | mode
))
1378 /* (just been created then) */
1379 send_check_path(dest_path
);
1382 for_dir_contents(do_copy2
, safe_path
, safe_dest
);
1383 /* Note: dest_path now invalid... */
1389 /* We may have created the directory with
1390 * more permissions than the source so that
1391 * we could write to it... change it back now.
1393 if (chmod(safe_dest
, mode
))
1395 /* Some filesystems don't support
1396 * SetGID and SetUID bits. Ignore
1403 /* Also, try to preserve the timestamps */
1404 utb
.actime
= info
.st_atime
;
1405 utb
.modtime
= info
.st_mtime
;
1407 utime(safe_dest
, &utb
);
1414 else if (S_ISLNK(info
.st_mode
))
1418 /* Not all versions of cp(1) can make symlinks,
1419 * so we special-case it.
1422 target
= readlink_dup(path
);
1425 if (symlink(target
, dest_path
))
1428 send_check_path(dest_path
);
1439 error
= copy_file(path
, dest_path
);
1443 printf_send(_("!%s\nFailed to copy '%s'\n"),
1448 send_check_path(dest_path
);
1452 /* If action_leaf is not NULL it specifies the new leaf name */
1453 static void do_move2(const char *path
, const char *dest
)
1455 const char *dest_path
;
1456 const char *argv
[] = {"mv", "-f", NULL
, NULL
, NULL
};
1463 dest_path
= make_dest_path(path
, dest
);
1465 is_dir
= mc_lstat(path
, &info2
) == 0 && S_ISDIR(info2
.st_mode
);
1467 if (access(dest_path
, F_OK
) == 0)
1472 if (mc_lstat(dest_path
, &info
))
1478 if (!is_dir
&& o_newer
&& info2
.st_mtime
> info
.st_mtime
)
1480 /* Newer; keep going */
1484 printf_send("<%s", path
);
1485 printf_send(">%s", dest_path
);
1486 if (!printf_reply(from_parent
, TRUE
,
1487 _("?'%s' already exists - overwrite?"),
1492 if (S_ISDIR(info
.st_mode
))
1493 err
= rmdir(dest_path
);
1495 err
= unlink(dest_path
);
1500 if (errno
!= ENOENT
)
1502 printf_send(_("'Trying move anyway...\n"));
1507 printf_send("<%s", path
);
1509 if (!printf_reply(from_parent
, FALSE
,
1510 _("?Move %s as %s?"), path
, dest_path
))
1514 printf_send(_("'Moving %s as %s\n"), path
, dest_path
);
1517 argv
[3] = dest_path
;
1519 err
= fork_exec_wait(argv
);
1522 printf_send(_("!%s\nFailed to move %s as %s\n"),
1523 err
, path
, dest_path
);
1528 send_check_path(dest_path
);
1531 send_mount_path(path
);
1533 send_check_path(path
);
1537 /* Copy path to dest.
1538 * Check that path not copied into itself.
1540 static void do_copy(const char *path
, const char *dest
)
1542 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1543 printf_send(_("!ERROR: Can't copy object into itself\n"));
1546 do_copy2(path
, dest
);
1547 send_check_path(dest
);
1551 /* Move path to dest.
1552 * Check that path not moved into itself.
1554 static void do_move(const char *path
, const char *dest
)
1556 if (is_sub_dir(make_dest_path(path
, dest
), path
))
1558 _("!ERROR: Can't move/rename object into itself\n"));
1561 do_move2(path
, dest
);
1562 send_check_path(dest
);
1566 /* Common code for do_link_relative() and do_link_absolute(). */
1567 static void do_link(const char *path
, const char *dest_path
)
1570 printf_send(_("'Linking %s as %s\n"), path
, dest_path
);
1572 printf_send("<%s", path
);
1574 if (!printf_reply(from_parent
, FALSE
,
1575 _("?Link %s as %s?"), path
, dest_path
))
1579 if (symlink(path
, dest_path
))
1582 send_check_path(dest_path
);
1585 static void do_link_relative(const char *path
, const char *dest
)
1588 const char *dest_path
;
1590 dest_path
= make_dest_path(path
, dest
);
1594 rel_path
= get_relative_path(dest_path
, path
);
1595 do_link(rel_path
, dest_path
);
1599 static void do_link_absolute(const char *path
, const char *dest
)
1602 do_link(path
, make_dest_path(path
, dest
));
1605 /* Mount/umount this item (depending on 'mount') */
1606 static void do_mount(const guchar
*path
, gboolean mount
)
1608 const char *argv
[3] = {NULL
, NULL
, NULL
};
1613 argv
[0] = mount
? "mount" : "umount";
1617 printf_send(mount
? _("'Mounting %s\n")
1618 : _("'Unmounting %s\n"),
1620 else if (!printf_reply(from_parent
, FALSE
,
1621 mount
? _("?Mount %s?")
1622 : _("?Unmount %s?"),
1629 /* Need to close all sub-directories now, or we
1630 * can't unmount if dnotify is used.
1632 printf_send("X%s", path
);
1633 /* Wait until it's safe... */
1634 read(from_parent
, &c
, 1);
1635 g_return_if_fail(c
== 'X');
1638 err
= fork_exec_wait(argv
);
1642 _("!%s\nMount failed\n") :
1643 _("!%s\nUnmount failed\n"), err
);
1646 /* Mount may have worked even on error, eg if we try to mount
1647 * a read-only disk read/write, it gets mounted read-only
1650 if (mount
&& mount_is_mounted(path
, NULL
, NULL
))
1651 printf_send(_("'(seems to be mounted now anyway)\n"));
1656 printf_send("M%s", path
);
1657 if (mount
&& mount_open_dir
)
1658 printf_send("o%s", path
);
1661 /* CHILD MAIN LOOPS */
1663 /* After forking, the child calls one of these functions */
1665 /* We use a double for total size in order to count beyond 4Gb */
1666 static void usage_cb(gpointer data
)
1668 GList
*paths
= (GList
*) data
;
1669 double total_size
= 0;
1672 n
=g_list_length(paths
);
1673 dir_counter
= file_counter
= 0;
1675 for (i
=0; paths
; paths
= paths
->next
, i
++)
1677 guchar
*path
= (guchar
*) paths
->data
;
1686 printf_send("%%%d", per
);
1688 do_usage(path
, NULL
);
1690 printf_send("'%s: %s\n",
1692 format_double_size(size_tally
));
1693 total_size
+= size_tally
;
1695 printf_send("%%-1");
1697 g_string_printf(message
, _("'\nTotal: %s ("),
1698 format_double_size(total_size
));
1701 g_string_append_printf(message
,
1702 "%ld %s%s", file_counter
,
1703 file_counter
== 1 ? _("file") : _("files"),
1704 dir_counter
? ", " : ")\n");
1706 if (file_counter
== 0 && dir_counter
== 0)
1707 g_string_append(message
, _("no directories)\n"));
1708 else if (dir_counter
)
1709 g_string_append_printf(message
,
1710 "%ld %s)\n", dir_counter
,
1711 dir_counter
== 1 ? _("directory")
1712 : _("directories"));
1717 #ifdef DO_MOUNT_POINTS
1718 static void mount_cb(gpointer data
)
1720 GList
*paths
= (GList
*) data
;
1721 gboolean mount_points
= FALSE
;
1724 n
=g_list_length(paths
);
1725 for (i
=0; paths
; paths
= paths
->next
, i
++)
1727 guchar
*path
= (guchar
*) paths
->data
;
1730 target
= pathdup(path
);
1737 printf_send("%%%d", per
);
1739 if (mount_is_mounted(target
, NULL
, NULL
))
1741 mount_points
= TRUE
;
1742 do_mount(target
, FALSE
); /* Unmount */
1744 else if (g_hash_table_lookup(fstab_mounts
, target
))
1746 mount_points
= TRUE
;
1747 do_mount(target
, TRUE
); /* Mount */
1757 printf_send(_("!No mount points selected!\n"));
1761 /* (use g_dirname() instead?) */
1762 static guchar
*dirname(guchar
*path
)
1766 slash
= strrchr(path
, '/');
1767 g_return_val_if_fail(slash
!= NULL
, g_strdup(path
));
1770 return g_strndup(path
, slash
- path
);
1771 return g_strdup("/");
1774 static void delete_cb(gpointer data
)
1776 GList
*paths
= (GList
*) data
;
1779 n
=g_list_length(paths
);
1780 for (i
=0; paths
; paths
= paths
->next
, i
++)
1782 guchar
*path
= (guchar
*) paths
->data
;
1785 dir
= dirname(path
);
1791 printf_send("%%%d", per
);
1793 do_delete(path
, dir
);
1801 static void eject_cb(gpointer data
)
1803 GList
*paths
= (GList
*) data
;
1806 n
=g_list_length(paths
);
1808 for (i
=0; paths
; paths
= paths
->next
, i
++)
1810 guchar
*path
= (guchar
*) paths
->data
;
1815 printf_send("%%%d", per
);
1825 static void find_cb(gpointer data
)
1827 GList
*all_paths
= (GList
*) data
;
1832 for (paths
= all_paths
; paths
; paths
= paths
->next
)
1834 guchar
*path
= (guchar
*) paths
->data
;
1838 do_find(path
, NULL
);
1841 if (!printf_reply(from_parent
, TRUE
,
1842 _("?Another search?")))
1850 static void chmod_cb(gpointer data
)
1852 GList
*paths
= (GList
*) data
;
1855 n
=g_list_length(paths
);
1857 for (i
=0; paths
; paths
= paths
->next
, i
++)
1859 guchar
*path
= (guchar
*) paths
->data
;
1865 printf_send("%%%d", per
);
1869 if (mc_stat(path
, &info
) != 0)
1871 else if (S_ISLNK(info
.st_mode
))
1872 printf_send(_("!'%s' is a symbolic link\n"),
1875 do_chmod(path
, NULL
);
1881 static void settype_cb(gpointer data
)
1883 GList
*paths
= (GList
*) data
;
1886 n
=g_list_length(paths
);
1888 for (i
=0; paths
; paths
= paths
->next
, i
++)
1890 guchar
*path
= (guchar
*) paths
->data
;
1896 printf_send("%%%d", per
);
1900 if (mc_stat(path
, &info
) != 0)
1902 else if (S_ISLNK(info
.st_mode
))
1903 printf_send(_("!'%s' is a symbolic link\n"),
1906 do_settype(path
, NULL
);
1912 static void list_cb(gpointer data
)
1914 GList
*paths
= (GList
*) data
;
1917 n
=g_list_length(paths
);
1919 for (i
=0; paths
; paths
= paths
->next
, i
++)
1924 printf_send("%%%d", per
);
1926 send_dir((char *) paths
->data
);
1928 action_do_func((char *) paths
->data
, action_dest
);
1934 /* EXTERNAL INTERFACE */
1936 void action_find(GList
*paths
)
1943 report_error(_("You need to select some items "
1944 "to search through"));
1948 if (!last_find_string
)
1949 last_find_string
= g_strdup("'core'");
1951 new_entry_string
= last_find_string
;
1953 abox
= abox_new(_("Find"), FALSE
);
1954 gui_side
= start_action(abox
, find_cb
, paths
,
1955 o_action_force
.int_value
,
1956 o_action_brief
.int_value
,
1957 o_action_recurse
.int_value
,
1958 o_action_newer
.int_value
);
1962 abox_add_results(ABOX(abox
));
1964 gui_side
->default_string
= &last_find_string
;
1965 abox_add_entry(ABOX(abox
), last_find_string
,
1966 new_help_button(show_condition_help
, NULL
));
1967 g_signal_connect(ABOX(abox
)->entry
, "changed",
1968 G_CALLBACK(entry_changed
), gui_side
);
1969 set_find_string_colour(ABOX(abox
)->entry
, last_find_string
);
1971 gui_side
->show_info
= TRUE
;
1972 gui_side
->entry_string_func
= set_find_string_colour
;
1974 number_of_windows
++;
1975 gtk_widget_show(abox
);
1978 /* Count disk space used by selected items */
1979 void action_usage(GList
*paths
)
1986 report_error(_("You need to select some items to count"));
1990 abox
= abox_new(_("Disk Usage"), TRUE
);
1992 gui_side
= start_action(abox
, usage_cb
, paths
,
1993 o_action_force
.int_value
,
1994 o_action_brief
.int_value
,
1995 o_action_recurse
.int_value
,
1996 o_action_newer
.int_value
);
2000 gui_side
->show_info
= TRUE
;
2002 number_of_windows
++;
2004 gtk_widget_show(abox
);
2007 /* Mount/unmount listed items (paths).
2008 * Free the list after this function returns.
2009 * If open_dir is TRUE and the dir is successfully mounted, open it.
2010 * quiet can be -1 for default.
2012 void action_mount(GList
*paths
, gboolean open_dir
, int quiet
)
2014 #ifdef DO_MOUNT_POINTS
2019 quiet
= o_action_mount
.int_value
;
2021 mount_open_dir
= open_dir
;
2023 abox
= abox_new(_("Mount / Unmount"), quiet
);
2024 gui_side
= start_action(abox
, mount_cb
, paths
,
2025 o_action_force
.int_value
,
2026 o_action_brief
.int_value
,
2027 o_action_recurse
.int_value
,
2028 o_action_newer
.int_value
);
2032 number_of_windows
++;
2033 gtk_widget_show(abox
);
2036 _("ROX-Filer does not yet support mount points on your "
2038 #endif /* DO_MOUNT_POINTS */
2041 /* Delete these paths */
2042 void action_delete(GList
*paths
)
2047 if (!remove_pinned_ok(paths
))
2050 abox
= abox_new(_("Delete"), o_action_delete
.int_value
);
2051 gui_side
= start_action(abox
, delete_cb
, paths
,
2052 o_action_force
.int_value
,
2053 o_action_brief
.int_value
,
2054 o_action_recurse
.int_value
,
2055 o_action_newer
.int_value
);
2059 abox_add_flag(ABOX(abox
),
2060 _("Force"), _("Don't confirm deletion of non-writeable items"),
2061 'F', o_action_force
.int_value
);
2062 abox_add_flag(ABOX(abox
),
2063 _("Brief"), _("Only log directories being deleted"),
2064 'B', o_action_brief
.int_value
);
2066 number_of_windows
++;
2067 gtk_widget_show(abox
);
2070 /* Change the permissions of the selected items */
2071 void action_chmod(GList
*paths
, gboolean force_recurse
, const char *action
)
2075 static GList
*presets
= NULL
;
2076 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2080 report_error(_("You need to select the items "
2081 "whose permissions you want to change"));
2087 presets
= g_list_append(presets
, (gchar
*)
2088 _("a+x (Make executable/searchable)"));
2089 presets
= g_list_append(presets
, (gchar
*)
2090 _("a-x (Make non-executable/non-searchable)"));
2091 presets
= g_list_append(presets
, (gchar
*)
2092 _("u+rw (Give owner read+write)"));
2093 presets
= g_list_append(presets
, (gchar
*)
2094 _("go-rwx (Private - owner access only)"));
2095 presets
= g_list_append(presets
, (gchar
*)
2096 _("go=u-w (Public access, not write)"));
2099 if (!last_chmod_string
)
2100 last_chmod_string
= g_strdup((guchar
*) presets
->data
);
2103 new_entry_string
= g_strdup(action
);
2105 new_entry_string
= g_strdup(last_chmod_string
);
2107 abox
= abox_new(_("Permissions"), FALSE
);
2108 gui_side
= start_action(abox
, chmod_cb
, paths
,
2109 o_action_force
.int_value
,
2110 o_action_brief
.int_value
,
2112 o_action_newer
.int_value
);
2117 abox_add_flag(ABOX(abox
),
2118 _("Brief"), _("Don't list processed files"),
2119 'B', o_action_brief
.int_value
);
2120 abox_add_flag(ABOX(abox
),
2121 _("Recurse"), _("Also change contents of subdirectories"),
2124 gui_side
->default_string
= &last_chmod_string
;
2125 abox_add_combo(ABOX(abox
), _("Command:"), presets
, new_entry_string
,
2126 new_help_button(show_chmod_help
, NULL
));
2128 g_signal_connect(ABOX(abox
)->entry
, "changed",
2129 G_CALLBACK(entry_changed
), gui_side
);
2131 g_signal_connect_swapped(gui_side
->entry
, "activate",
2132 G_CALLBACK(gtk_button_clicked
),
2136 number_of_windows
++;
2137 gtk_widget_show(abox
);
2140 null_g_free(&new_entry_string
);
2143 /* Set the MIME type of the selected items */
2144 void action_settype(GList
*paths
, gboolean force_recurse
, const char *oldtype
)
2148 GList
*presets
= NULL
;
2149 gboolean recurse
= force_recurse
|| o_action_recurse
.int_value
;
2153 report_error(_("You need to select the items "
2154 "whose type you want to change"));
2158 if (!last_settype_string
)
2159 last_settype_string
= g_strdup("text/plain");
2162 new_entry_string
= g_strdup(oldtype
);
2164 new_entry_string
= g_strdup(last_settype_string
);
2166 abox
= abox_new(_("Set type"), FALSE
);
2167 gui_side
= start_action(abox
, settype_cb
, paths
,
2168 o_action_force
.int_value
,
2169 o_action_brief
.int_value
,
2171 o_action_newer
.int_value
);
2176 abox_add_flag(ABOX(abox
),
2177 _("Brief"), _("Don't list processed files"),
2178 'B', o_action_brief
.int_value
);
2179 abox_add_flag(ABOX(abox
),
2180 _("Recurse"), _("Change contents of subdirectories"),
2183 gui_side
->default_string
= &last_settype_string
;
2185 /* Note: get the list again each time -- it can change */
2186 presets
= mime_type_name_list();
2187 abox_add_combo(ABOX(abox
), _("Type:"), presets
, new_entry_string
,
2188 new_help_button(show_settype_help
, NULL
));
2189 g_list_free(presets
);
2191 g_signal_connect(ABOX(abox
)->entry
, "changed",
2192 G_CALLBACK(entry_changed
), gui_side
);
2194 number_of_windows
++;
2195 gtk_widget_show(abox
);
2198 null_g_free(&new_entry_string
);
2201 /* If leaf is NULL then the copy has the same name as the original.
2202 * quiet can be -1 for default.
2204 void action_copy(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2210 quiet
= o_action_copy
.int_value
;
2214 action_do_func
= do_copy
;
2216 abox
= abox_new(_("Copy"), quiet
);
2217 gui_side
= start_action(abox
, list_cb
, paths
,
2218 o_action_force
.int_value
,
2219 o_action_brief
.int_value
,
2220 o_action_recurse
.int_value
,
2221 o_action_newer
.int_value
);
2225 abox_add_flag(ABOX(abox
),
2227 _("Only over-write if source is newer than destination."),
2228 'W', o_action_newer
.int_value
);
2229 abox_add_flag(ABOX(abox
),
2230 _("Brief"), _("Only log directories as they are copied"),
2231 'B', o_action_brief
.int_value
);
2233 number_of_windows
++;
2234 gtk_widget_show(abox
);
2237 /* If leaf is NULL then the file is not renamed.
2238 * quiet can be -1 for default.
2240 void action_move(GList
*paths
, const char *dest
, const char *leaf
, int quiet
)
2246 quiet
= o_action_move
.int_value
;
2250 action_do_func
= do_move
;
2252 abox
= abox_new(_("Move"), quiet
);
2253 gui_side
= start_action(abox
, list_cb
, paths
,
2254 o_action_force
.int_value
,
2255 o_action_brief
.int_value
,
2256 o_action_recurse
.int_value
,
2257 o_action_newer
.int_value
);
2261 abox_add_flag(ABOX(abox
),
2263 _("Only over-write if source is newer than destination."),
2264 'W', o_action_newer
.int_value
);
2265 abox_add_flag(ABOX(abox
),
2266 _("Brief"), _("Don't log each file as it is moved"),
2267 'B', o_action_brief
.int_value
);
2268 number_of_windows
++;
2269 gtk_widget_show(abox
);
2272 /* If leaf is NULL then the link will have the same name */
2273 void action_link(GList
*paths
, const char *dest
, const char *leaf
,
2282 action_do_func
= do_link_relative
;
2284 action_do_func
= do_link_absolute
;
2286 abox
= abox_new(_("Link"), o_action_link
.int_value
);
2287 gui_side
= start_action(abox
, list_cb
, paths
,
2288 o_action_force
.int_value
,
2289 o_action_brief
.int_value
,
2290 o_action_recurse
.int_value
,
2291 o_action_newer
.int_value
);
2295 number_of_windows
++;
2296 gtk_widget_show(abox
);
2299 /* Eject these paths */
2300 void action_eject(GList
*paths
)
2305 abox
= abox_new(_("Eject"), TRUE
);
2306 gui_side
= start_action(abox
, eject_cb
, paths
,
2307 o_action_force
.int_value
,
2308 o_action_brief
.int_value
,
2309 o_action_recurse
.int_value
,
2310 o_action_newer
.int_value
);
2314 number_of_windows
++;
2315 gtk_widget_show(abox
);
2318 void action_init(void)
2320 option_add_int(&o_action_copy
, "action_copy", 1);
2321 option_add_int(&o_action_move
, "action_move", 1);
2322 option_add_int(&o_action_link
, "action_link", 1);
2323 option_add_int(&o_action_delete
, "action_delete", 0);
2324 option_add_int(&o_action_mount
, "action_mount", 1);
2325 option_add_int(&o_action_force
, "action_force", FALSE
);
2326 option_add_int(&o_action_brief
, "action_brief", FALSE
);
2327 option_add_int(&o_action_recurse
, "action_recurse", FALSE
);
2328 option_add_int(&o_action_newer
, "action_newer", FALSE
);
2333 /* Check to see if any of the selected items (or their children) are
2334 * on the pinboard or panel. If so, ask for confirmation.
2336 * TRUE if it's OK to lose them.
2338 static gboolean
remove_pinned_ok(GList
*paths
)
2340 GList
*ask
= NULL
, *next
;
2345 for (; paths
; paths
= paths
->next
)
2347 guchar
*path
= (guchar
*) paths
->data
;
2349 if (icons_require(path
))
2351 if (++ask_n
> MAX_ASK
)
2353 ask
= g_list_append(ask
, path
);
2360 if (ask_n
> MAX_ASK
)
2362 message
= g_string_new(_("Deleting items such as "));
2365 else if (ask_n
== 1)
2366 message
= g_string_new(_("Deleting the item "));
2368 message
= g_string_new(_("Deleting the items "));
2371 for (next
= ask
; next
; next
= next
->next
)
2373 guchar
*path
= (guchar
*) next
->data
;
2376 leaf
= strrchr(path
, '/');
2382 g_string_append_c(message
, '`');
2383 g_string_append(message
, leaf
);
2384 g_string_append_c(message
, '\'');
2386 if (i
== ask_n
- 1 && i
> 0)
2387 g_string_append(message
, _(" and "));
2389 g_string_append(message
, ", ");
2395 message
= g_string_append(message
,
2396 _(" will affect some items on the pinboard "
2397 "or panel - really delete it?"));
2400 if (ask_n
> MAX_ASK
)
2401 message
= g_string_append_c(message
, ',');
2402 message
= g_string_append(message
,
2403 _(" will affect some items on the pinboard "
2404 "or panel - really delete them?"));
2407 retval
= confirm(message
->str
, GTK_STOCK_DELETE
, NULL
);
2409 g_string_free(message
, TRUE
);
2414 void set_find_string_colour(GtkWidget
*widget
, const guchar
*string
)
2416 FindCondition
*cond
;
2418 cond
= find_compile(string
);
2419 entry_set_error(widget
, !cond
);
2421 find_condition_free(cond
);