r2932: Eject, Format and Free added to menu for mount points, only Eject implemented
[rox-filer.git] / ROX-Filer / src / action.c
blob0b62882f6c0bd75e3b8fa2e5c6b1e45710b9d93e
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, 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)
10 * any later version.
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
15 * more details.
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.
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <sys/param.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <sys/time.h>
35 #include <utime.h>
36 #include <stdarg.h>
38 #include "global.h"
40 #include "action.h"
41 #include "abox.h"
42 #include "string.h"
43 #include "support.h"
44 #include "gui_support.h"
45 #include "filer.h"
46 #include "display.h"
47 #include "main.h"
48 #include "options.h"
49 #include "modechange.h"
50 #include "find.h"
51 #include "dir.h"
52 #include "icon.h"
53 #include "mount.h"
55 /* Parent->Child messages are one character each:
57 * Y/N Yes/No button clicked
58 * F Force deletion of non-writeable items
59 * Q Quiet toggled
60 * E Entry text changed
61 * W neWer toggled
64 typedef struct _GUIside GUIside;
65 typedef void ActionChild(gpointer data);
66 typedef void ForDirCB(const char *path, const char *dest_path);
68 struct _GUIside
70 ABox *abox; /* The action window widget */
72 int from_child; /* File descriptor */
73 FILE *to_child;
74 int input_tag; /* gdk_input_add() */
75 pid_t child; /* Process ID */
76 int errors; /* Number of errors so far */
77 gboolean show_info; /* For Disk Usage */
79 guchar **default_string; /* Changed when the entry changes */
80 void (*entry_string_func)(GtkWidget *widget,
81 const guchar *string);
83 int abort_attempts;
86 /* These don't need to be in a structure because we fork() before
87 * using them again.
89 static gboolean mount_open_dir = FALSE;
90 static int from_parent = 0;
91 static FILE *to_parent = NULL;
92 static gboolean quiet = FALSE;
93 static GString *message = NULL;
94 static const char *action_dest = NULL;
95 static const char *action_leaf = NULL;
96 static void (*action_do_func)(const char *source, const char *dest);
97 static double size_tally; /* For Disk Usage */
98 static unsigned long dir_counter; /* For Disk Usage */
99 static unsigned long file_counter; /* For Disk Usage */
101 static struct mode_change *mode_change = NULL; /* For Permissions */
102 static FindCondition *find_condition = NULL; /* For Find */
104 /* Only used by child */
105 static gboolean o_force = FALSE;
106 static gboolean o_brief = FALSE;
107 static gboolean o_recurse = FALSE;
108 static gboolean o_newer = FALSE;
110 static Option o_action_copy, o_action_move, o_action_link;
111 static Option o_action_delete, o_action_mount;
112 static Option o_action_force, o_action_brief, o_action_recurse;
113 static Option o_action_newer;
115 /* Whenever the text in these boxes is changed we store a copy of the new
116 * string to be used as the default next time.
118 static guchar *last_chmod_string = NULL;
119 static guchar *last_find_string = NULL;
121 /* Set to one of the above before forking. This may change over a call to
122 * reply(). It is reset to NULL once the text is parsed.
124 static guchar *new_entry_string = NULL;
126 /* Static prototypes */
127 static void send_done(void);
128 static void send_check_path(const gchar *path);
129 static void send_mount_path(const gchar *path);
130 static gboolean printf_send(const char *msg, ...);
131 static gboolean send(void);
132 static gboolean send_error(void);
133 static gboolean send_dir(const char *dir);
134 static gboolean read_exact(int source, char *buffer, ssize_t len);
135 static void do_mount(const guchar *path, gboolean mount);
136 static gboolean printf_reply(int fd, gboolean ignore_quiet,
137 const char *msg, ...);
138 static gboolean remove_pinned_ok(GList *paths);
140 /* SUPPORT */
143 /* This is called whenever the user edits the entry box (if any) - send the
144 * new string.
146 static void entry_changed(GtkEditable *entry, GUIside *gui_side)
148 guchar *text;
150 g_return_if_fail(gui_side->default_string != NULL);
152 text = gtk_editable_get_chars(entry, 0, -1);
154 if (gui_side->entry_string_func)
155 gui_side->entry_string_func(GTK_WIDGET(entry), text);
157 g_free(*(gui_side->default_string));
158 *(gui_side->default_string) = text; /* Gets text's ref */
160 if (!gui_side->to_child)
161 return;
163 fputc('E', gui_side->to_child);
164 fputs(text, gui_side->to_child);
165 fputc('\n', gui_side->to_child);
166 fflush(gui_side->to_child);
169 void show_condition_help(gpointer data)
171 GtkWidget *help;
172 GtkWidget *text;
174 help = gtk_dialog_new_with_buttons(
175 _("Find expression reference"),
176 NULL, 0,
177 GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
178 NULL);
179 gtk_dialog_set_default_response(GTK_DIALOG(help), GTK_RESPONSE_CANCEL);
181 text = gtk_label_new(NULL);
182 gtk_misc_set_padding(GTK_MISC(text), 2, 2);
183 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help)->vbox), text);
184 gtk_label_set_selectable(GTK_LABEL(text), TRUE);
185 gtk_label_set_markup(GTK_LABEL(text), _(
186 "<u>Quick Start</u>\n"
187 "Just put the name of the file you're looking for in single quotes:\n"
188 "<b>'index.html'</b> (to find a file called 'index.html')\n"
189 "\n"
190 "<u>Examples</u>\n"
191 "<b>'*.htm', '*.html'</b> (finds HTML files)\n"
192 "<b>IsDir 'lib'</b> (finds directories called 'lib')\n"
193 "<b>IsReg 'core'</b> (finds a regular file called 'core')\n"
194 "<b>! (IsDir, IsReg)</b> (is neither a directory nor a regular file)\n"
195 "<b>mtime after 1 day ago and size > 1Mb</b> (big, and recently modified)\n"
196 "<b>'CVS' prune, isreg</b> (a regular file not in CVS)\n"
197 "<b>IsReg system(grep -q fred \"%\")</b> (contains the word 'fred')\n"
198 "\n"
199 "<u>Simple Tests</u>\n"
200 "<b>IsReg, IsLink, IsDir, IsChar, IsBlock, IsDev, IsPipe, IsSocket, IsDoor</b> "
201 "(types)\n"
202 "<b>IsSUID, IsSGID, IsSticky, IsReadable, IsWriteable, IsExecutable</b> "
203 "(permissions)\n"
204 "<b>IsEmpty, IsMine</b>\n"
205 "A pattern in single quotes is a shell-style wildcard pattern to match. If it\n"
206 "contains a slash then the match is against the full path; otherwise it is\n"
207 "against the leafname only.\n"
208 "\n"
209 "<u>Comparisons</u>\n"
210 "<b>&lt;, &lt;=, =, !=, &gt;, &gt;=, After, Before</b> (compare two values)\n"
211 "<b>5 bytes, 1Kb, 2Mb, 3Gb</b> (file sizes)\n"
212 "<b>2 secs|mins|hours|days|weeks|years ago|hence</b> (times)\n"
213 "<b>atime, ctime, mtime, now, size, inode, nlinks, uid, gid, blocks</b> "
214 "(values)\n"
215 "\n"
216 "<u>Specials</u>\n"
217 "<b>system(command)</b> (true if 'command' returns with a zero exit status;\n"
218 "a % in 'command' is replaced with the path of the current file)\n"
219 "<b>prune</b> (false, and prevents searching the contents of a directory)."));
221 g_signal_connect(help, "response",
222 G_CALLBACK(gtk_widget_destroy), NULL);
224 gtk_widget_show_all(help);
227 static void show_chmod_help(gpointer data)
229 GtkWidget *help;
230 GtkWidget *text;
232 help = gtk_dialog_new_with_buttons(
233 _("Find expression reference"),
234 NULL, 0,
235 GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
236 NULL);
237 gtk_dialog_set_default_response(GTK_DIALOG(help), GTK_RESPONSE_CANCEL);
239 text = gtk_label_new(NULL);
240 gtk_misc_set_padding(GTK_MISC(text), 2, 2);
241 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(help)->vbox), text);
242 gtk_label_set_selectable(GTK_LABEL(text), TRUE);
243 gtk_label_set_markup(GTK_LABEL(text), _(
244 "Normally, you can just select a command from the menu (click \n"
245 "on the arrow beside the command box). Sometimes, you need more...\n"
246 "\n"
247 "The format of a command is: <b>CHANGE, CHANGE, ...</b>\n"
248 "Each <b>CHANGE</b> is: <b>WHO HOW PERMISSIONS</b>\n"
249 "<b>WHO</b> is some combination of <b>u</b>, <b>g</b> and <b>o</b> which "
250 "determines whether to\n"
251 "change the permissions for the User (owner), Group or Others.\n"
252 "<b>HOW</b> is <b>+</b>, <b>-</b> or <b>=</b> to add, remove or set "
253 "exactly the permissions.\n"
254 "<b>PERMISSIONS</b> is some combination of the letters <b>rwxXstugo</b>\n"
255 "\n"
256 "Bracketed text and spaces are ignored.\n"
257 "\n"
258 "<u>Examples</u>\n"
259 "<b>u+rw</b>: the file owner gains read and write permission\n"
260 "<b>g=u</b>: the group permissions are set to be the same as the user's\n"
261 "<b>o=u-w</b>: others get the same permissions as the owner, but without "
262 "write permission\n"
263 "<b>a+x</b>: <b>a</b>ll get execute/access permission - same as <b>ugo+x</b>\n"
264 "<b>a+X</b>: directories become accessable by everyone; files which were\n"
265 "executable by anyone become executable by everyone\n"
266 "<b>u+rw, go+r</b>: two commands at once!\n"
267 "<b>u+s</b>: set the SetUID bit - often has no effect on script files\n"
268 "<b>755</b>: set the permissions directly\n"
269 "\n"
270 "See the chmod(1) man page for full details."));
272 g_signal_connect(help, "response",
273 G_CALLBACK(gtk_widget_destroy), NULL);
275 gtk_widget_show_all(help);
278 static void process_message(GUIside *gui_side, const gchar *buffer)
280 ABox *abox = gui_side->abox;
282 if (*buffer == '?')
283 abox_ask(abox, buffer + 1);
284 else if (*buffer == 's')
285 dir_check_this(buffer + 1); /* Update this item */
286 else if (*buffer == '=')
287 abox_add_filename(abox, buffer + 1);
288 else if (*buffer == '#')
289 abox_clear_results(abox);
290 else if (*buffer == 'X')
292 filer_close_recursive(buffer + 1);
293 /* Let child know it's safe to continue... */
294 fputc('X', gui_side->to_child);
295 fflush(gui_side->to_child);
297 else if (*buffer == 'm' || *buffer == 'M')
299 /* Mount / major changes to this path */
300 if (*buffer == 'M')
302 mount_update(TRUE);
303 mount_user_mount(buffer + 1);
305 filer_check_mounted(buffer + 1);
307 else if (*buffer == '/')
308 abox_set_current_object(abox, buffer + 1);
309 else if (*buffer == 'o')
310 filer_opendir(buffer + 1, NULL, NULL);
311 else if (*buffer == '!')
313 gui_side->errors++;
314 abox_log(abox, buffer + 1, "error");
316 else if (*buffer == '<')
317 abox_set_file(abox, 0, buffer+1);
318 else if (*buffer == '>')
320 abox_set_file(abox, 1, buffer+1);
321 abox_show_compare(abox, TRUE);
323 else
324 abox_log(abox, buffer + 1, NULL);
327 /* Called when the child sends us a message */
328 static void message_from_child(gpointer data,
329 gint source,
330 GdkInputCondition condition)
332 char buf[5];
333 GUIside *gui_side = (GUIside *) data;
334 ABox *abox = gui_side->abox;
335 GtkTextBuffer *text_buffer;
337 text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox->log));
339 if (read_exact(source, buf, 4))
341 ssize_t message_len;
342 char *buffer;
344 buf[4] = '\0';
345 message_len = strtol(buf, NULL, 16);
346 buffer = g_malloc(message_len + 1);
347 if (message_len > 0 && read_exact(source, buffer, message_len))
349 buffer[message_len] = '\0';
350 process_message(gui_side, buffer);
351 g_free(buffer);
352 return;
354 g_printerr("Child died in the middle of a message.\n");
357 if (gui_side->abort_attempts)
358 abox_log(abox, _("\nProcess terminated.\n"), "error");
360 /* The child is dead */
361 gui_side->child = 0;
363 fclose(gui_side->to_child);
364 gui_side->to_child = NULL;
365 close(gui_side->from_child);
366 g_source_remove(gui_side->input_tag);
367 abox_cancel_ask(gui_side->abox);
369 if (gui_side->errors)
371 guchar *report;
373 if (gui_side->errors == 1)
374 report = g_strdup(_("There was one error.\n"));
375 else
376 report = g_strdup_printf(_("There were %d errors.\n"),
377 gui_side->errors);
379 gtk_text_buffer_insert_at_cursor(text_buffer, report, -1);
381 g_free(report);
383 else if (gui_side->show_info == FALSE)
384 gtk_widget_destroy(GTK_WIDGET(gui_side->abox));
387 /* Scans src_dir, calling cb(item, dest_path) for each item */
388 static void for_dir_contents(ForDirCB *cb,
389 const char *src_dir,
390 const char *dest_path)
392 DIR *d;
393 struct dirent *ent;
394 GList *list = NULL, *next;
396 d = mc_opendir(src_dir);
397 if (!d)
399 /* Message displayed is "ERROR reading 'path': message" */
400 printf_send("!%s '%s': %s\n", _("ERROR reading"),
401 src_dir, g_strerror(errno));
402 return;
405 send_dir(src_dir);
407 while ((ent = mc_readdir(d)))
409 if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0'
410 || (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
411 continue;
412 list = g_list_prepend(list, g_strdup(make_path(src_dir,
413 ent->d_name)));
415 mc_closedir(d);
417 for (next = list; next; next = next->next)
419 cb((char *) next->data, dest_path);
421 g_free(next->data);
423 g_list_free(list);
426 /* Read this many bytes into the buffer. TRUE on success. */
427 static gboolean read_exact(int source, char *buffer, ssize_t len)
429 while (len > 0)
431 ssize_t got;
432 got = read(source, buffer, len);
433 if (got < 1)
434 return FALSE;
435 len -= got;
436 buffer += got;
438 return TRUE;
441 static void send_done(void)
443 printf_send(_("'\nDone\n"));
446 /* Notify the filer that this item has been updated */
447 static void send_check_path(const gchar *path)
449 printf_send("s%s", path);
452 /* Notify the filer that this whole subtree has changed (eg, been unmounted) */
453 static void send_mount_path(const gchar *path)
455 printf_send("m%s", path);
458 /* Send a message to the filer process. The first character indicates the
459 * type of the message.
461 static gboolean printf_send(const char *msg, ...)
463 va_list args;
464 gchar *tmp;
466 va_start(args, msg);
467 tmp = g_strdup_vprintf(msg, args);
468 va_end(args);
470 g_string_assign(message, tmp);
471 g_free(tmp);
473 return send();
476 /* Send 'message' to our parent process. TRUE on success. */
477 static gboolean send(void)
479 char len_buffer[5];
480 ssize_t len;
482 g_return_val_if_fail(message->len < 0xffff, FALSE);
484 sprintf(len_buffer, "%04x", message->len);
485 fwrite(len_buffer, 1, 4, to_parent);
486 len = fwrite(message->str, 1, message->len, to_parent);
487 fflush(to_parent);
488 return len == (ssize_t) message->len;
491 /* Set the directory indicator at the top of the window */
492 static gboolean send_dir(const char *dir)
494 return printf_send("/%s", dir);
497 static gboolean send_error(void)
499 return printf_send("!%s: %s\n", _("ERROR"), g_strerror(errno));
502 static void response(GtkDialog *dialog, gint response, GUIside *gui_side)
504 gchar code;
506 if (!gui_side->to_child)
507 return;
509 if (response == GTK_RESPONSE_YES)
510 code = 'Y';
511 else if (response == GTK_RESPONSE_NO)
512 code = 'N';
513 else
514 return;
516 fputc(code, gui_side->to_child);
517 fflush(gui_side->to_child);
518 abox_show_compare(gui_side->abox, FALSE);
521 static void flag_toggled(ABox *abox, gint flag, GUIside *gui_side)
523 if (!gui_side->to_child)
524 return;
526 fputc(flag, gui_side->to_child);
527 fflush(gui_side->to_child);
530 static void read_new_entry_text(void)
532 int len;
533 char c;
534 GString *new;
536 new = g_string_new(NULL);
538 for (;;)
540 len = read(from_parent, &c, 1);
541 if (len != 1)
543 fprintf(stderr, "read() error: %s\n",
544 g_strerror(errno));
545 _exit(1); /* Parent died? */
548 if (c == '\n')
549 break;
550 g_string_append_c(new, c);
553 g_free(new_entry_string);
554 new_entry_string = new->str;
555 g_string_free(new, FALSE);
558 static void process_flag(char flag)
560 switch (flag)
562 case 'Q':
563 quiet = !quiet;
564 break;
565 case 'F':
566 o_force = !o_force;
567 break;
568 case 'R':
569 o_recurse = !o_recurse;
570 break;
571 case 'B':
572 o_brief = !o_brief;
573 break;
574 case 'W':
575 o_newer = !o_newer;
576 break;
577 case 'E':
578 read_new_entry_text();
579 break;
580 default:
581 printf_send("!ERROR: Bad message '%c'\n", flag);
582 break;
586 /* If the parent has sent any flag toggles, read them */
587 static void check_flags(void)
589 fd_set set;
590 int got;
591 char retval;
592 struct timeval tv;
594 FD_ZERO(&set);
596 while (1)
598 FD_SET(from_parent, &set);
599 tv.tv_sec = 0;
600 tv.tv_usec = 0;
601 got = select(from_parent + 1, &set, NULL, NULL, &tv);
603 if (got == -1)
604 g_error("select() failed: %s\n", g_strerror(errno));
605 else if (!got)
606 return;
608 got = read(from_parent, &retval, 1);
609 if (got != 1)
610 g_error("read() error: %s\n", g_strerror(errno));
612 process_flag(retval);
616 /* Read until the user sends a reply. If ignore_quiet is TRUE then
617 * the user MUST click Yes or No, else treat quiet on as Yes.
618 * If the user needs prompting then does send().
620 static gboolean printf_reply(int fd, gboolean ignore_quiet,
621 const char *msg, ...)
623 ssize_t len;
624 char retval;
625 va_list args;
626 gchar *tmp;
628 if (quiet && !ignore_quiet)
629 return TRUE;
631 va_start(args, msg);
632 tmp = g_strdup_vprintf(msg, args);
633 va_end(args);
635 g_string_assign(message, tmp);
636 g_free(tmp);
638 send();
640 while (1)
642 len = read(fd, &retval, 1);
643 if (len != 1)
645 fprintf(stderr, "read() error: %s\n",
646 g_strerror(errno));
647 _exit(1); /* Parent died? */
650 switch (retval)
652 case 'Y':
653 printf_send("' %s\n", _("Yes"));
654 return TRUE;
655 case 'N':
656 printf_send("' %s\n", _("No"));
657 return FALSE;
658 default:
659 process_flag(retval);
660 break;
665 static void abort_operation(GtkWidget *widget, gpointer data)
667 GUIside *gui_side = (GUIside *) data;
669 if (gui_side->child)
671 if (gui_side->abort_attempts == 0)
673 abox_log(ABOX(widget),
674 _("\nAsking child process to terminate...\n"),
675 "error");
676 kill(-gui_side->child, SIGTERM);
678 else
680 abox_log(ABOX(widget),
681 _("\nTrying to KILL run-away process...\n"),
682 "error");
683 kill(-gui_side->child, SIGKILL);
684 kill(-gui_side->child, SIGCONT);
686 gui_side->abort_attempts++;
688 else
689 gtk_widget_destroy(widget);
692 static void destroy_action_window(GtkWidget *widget, gpointer data)
694 GUIside *gui_side = (GUIside *) data;
696 if (gui_side->child)
698 kill(-gui_side->child, SIGTERM);
699 fclose(gui_side->to_child);
700 close(gui_side->from_child);
701 g_source_remove(gui_side->input_tag);
704 g_free(gui_side);
706 one_less_window();
709 /* Create two pipes, fork() a child and return a pointer to a GUIside struct
710 * (NULL on failure). The child calls func().
712 static GUIside *start_action(GtkWidget *abox, ActionChild *func, gpointer data,
713 int force, int brief, int recurse, int newer)
715 gboolean autoq;
716 int filedes[4]; /* 0 and 2 are for reading */
717 GUIside *gui_side;
718 pid_t child;
719 struct sigaction act;
721 if (pipe(filedes))
723 report_error("pipe: %s", g_strerror(errno));
724 gtk_widget_destroy(abox);
725 return NULL;
728 if (pipe(filedes + 2))
730 close(filedes[0]);
731 close(filedes[1]);
732 report_error("pipe: %s", g_strerror(errno));
733 gtk_widget_destroy(abox);
734 return NULL;
737 autoq = gtk_toggle_button_get_active(
738 GTK_TOGGLE_BUTTON(ABOX(abox)->quiet));
740 o_force = force;
741 o_brief = brief;
742 o_recurse = recurse;
743 o_newer = newer;
745 child = fork();
746 switch (child)
748 case -1:
749 report_error("fork: %s", g_strerror(errno));
750 gtk_widget_destroy(abox);
751 return NULL;
752 case 0:
753 /* We are the child */
755 /* Create a new process group */
756 setpgid(0, 0);
758 quiet = autoq;
760 dir_drop_all_dnotifies();
762 /* Reset the SIGCHLD handler */
763 act.sa_handler = SIG_DFL;
764 sigemptyset(&act.sa_mask);
765 act.sa_flags = 0;
766 sigaction(SIGCHLD, &act, NULL);
768 message = g_string_new(NULL);
769 close(filedes[0]);
770 close(filedes[3]);
771 to_parent = fdopen(filedes[1], "wb");
772 from_parent = filedes[2];
773 func(data);
774 send_dir("");
775 _exit(0);
778 /* We are the parent */
779 close(filedes[1]);
780 close(filedes[2]);
781 gui_side = g_new(GUIside, 1);
782 gui_side->from_child = filedes[0];
783 gui_side->to_child = fdopen(filedes[3], "wb");
784 gui_side->child = child;
785 gui_side->errors = 0;
786 gui_side->show_info = FALSE;
787 gui_side->default_string = NULL;
788 gui_side->entry_string_func = NULL;
789 gui_side->abort_attempts = 0;
791 gui_side->abox = ABOX(abox);
792 g_signal_connect(abox, "destroy",
793 G_CALLBACK(destroy_action_window), gui_side);
795 g_signal_connect(abox, "response", G_CALLBACK(response), gui_side);
796 g_signal_connect(abox, "flag_toggled",
797 G_CALLBACK(flag_toggled), gui_side);
798 g_signal_connect(abox, "abort_operation",
799 G_CALLBACK(abort_operation), gui_side);
801 gui_side->input_tag = gtk_input_add_full(gui_side->from_child,
802 GDK_INPUT_READ,
803 message_from_child,
804 NULL, gui_side, NULL);
806 return gui_side;
809 /* ACTIONS ON ONE ITEM */
811 /* These may call themselves recursively, or ask questions, etc */
813 /* Updates the global size_tally, file_counter and dir_counter */
814 static void do_usage(const char *src_path, const char *unused)
816 struct stat info;
818 check_flags();
820 if (mc_lstat(src_path, &info))
822 printf_send("'%s:\n", src_path);
823 send_error();
825 else if (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))
827 file_counter++;
828 size_tally += info.st_size;
830 else if (S_ISDIR(info.st_mode))
832 dir_counter++;
833 if (printf_reply(from_parent, FALSE,
834 _("?Count contents of %s?"), src_path))
836 char *safe_path;
837 safe_path = g_strdup(src_path);
838 for_dir_contents(do_usage, safe_path, safe_path);
839 g_free(safe_path);
842 else
843 file_counter++;
846 /* dest_path is the dir containing src_path */
847 static void do_delete(const char *src_path, const char *unused)
849 struct stat info;
850 gboolean write_prot;
851 char *safe_path;
853 check_flags();
855 if (mc_lstat(src_path, &info))
857 send_error();
858 return;
861 write_prot = S_ISLNK(info.st_mode) ? FALSE
862 : access(src_path, W_OK) != 0;
863 if (write_prot || !quiet)
865 printf_send("<%s", src_path);
866 printf_send(">");
867 if (!printf_reply(from_parent, write_prot && !o_force,
868 _("?Delete %s'%s'?"),
869 write_prot ? _("WRITE-PROTECTED ") : "",
870 src_path))
871 return;
873 else if (!o_brief)
874 printf_send(_("'Deleting '%s'\n"), src_path);
876 safe_path = g_strdup(src_path);
878 if (S_ISDIR(info.st_mode))
880 for_dir_contents(do_delete, safe_path, safe_path);
881 if (rmdir(safe_path))
883 g_free(safe_path);
884 send_error();
885 return;
887 printf_send(_("'Directory '%s' deleted\n"), safe_path);
888 send_mount_path(safe_path);
890 else if (unlink(src_path))
891 send_error();
892 else
894 send_check_path(safe_path);
895 if (strcmp(g_basename(safe_path), ".DirIcon") == 0)
897 gchar *dir;
898 dir = g_path_get_dirname(safe_path);
899 send_check_path(dir);
900 g_free(dir);
904 g_free(safe_path);
907 static void do_eject(const char *path)
909 const char *argv[3] = {NULL, NULL, NULL};
910 char *err;
912 check_flags();
914 if (!quiet)
916 printf_send("<%s", path);
917 printf_send(">");
918 if (!printf_reply(from_parent, !o_force,
919 _("?Eject '%s'?"),
920 path))
921 return;
923 else if (!o_brief)
924 printf_send(_("'Eject '%s'\n"), path);
926 argv[0]="eject";
927 argv[1]=path;
928 argv[2]=NULL;
929 err=fork_exec_wait(argv);
930 if (err)
932 printf_send(_("!%s\neject failed\n"), err);
933 g_free(err);
938 /* path is the item to check. If is is a directory then we may recurse
939 * (unless prune is used).
941 static void do_find(const char *path, const char *unused)
943 FindInfo info;
945 check_flags();
947 if (!quiet)
949 if (!printf_reply(from_parent, FALSE, _("?Check '%s'?"), path))
950 return;
953 for (;;)
955 if (new_entry_string)
957 find_condition_free(find_condition);
958 find_condition = find_compile(new_entry_string);
959 null_g_free(&new_entry_string);
962 if (find_condition)
963 break;
965 printf_send(_("!Invalid find condition - "
966 "change it and try again\n"));
967 if (!printf_reply(from_parent, TRUE,
968 _("?Check '%s'?"), path))
969 return;
972 if (mc_lstat(path, &info.stats))
974 send_error();
975 printf_send(_("'(while checking '%s')\n"), path);
976 return;
979 info.fullpath = path;
980 time(&info.now); /* XXX: Not for each check! */
982 info.leaf = g_basename(path);
983 info.prune = FALSE;
984 if (find_test_condition(find_condition, &info))
985 printf_send("=%s", path);
987 if (S_ISDIR(info.stats.st_mode) && !info.prune)
989 char *safe_path;
990 safe_path = g_strdup(path);
991 for_dir_contents(do_find, safe_path, safe_path);
992 g_free(safe_path);
996 /* Like mode_compile(), but ignores spaces and bracketed bits */
997 static struct mode_change *nice_mode_compile(const char *mode_string,
998 unsigned int masked_ops)
1000 GString *new;
1001 int brackets = 0;
1002 struct mode_change *retval = NULL;
1004 new = g_string_new(NULL);
1006 for (; *mode_string; mode_string++)
1008 if (*mode_string == '(')
1009 brackets++;
1010 if (*mode_string == ')')
1012 brackets--;
1013 if (brackets < 0)
1014 break;
1015 continue;
1018 if (brackets == 0 && *mode_string != ' ')
1019 g_string_append_c(new, *mode_string);
1022 if (brackets == 0)
1023 retval = mode_compile(new->str, masked_ops);
1024 g_string_free(new, TRUE);
1025 return retval;
1028 static void do_chmod(const char *path, const char *unused)
1030 struct stat info;
1031 mode_t new_mode;
1033 check_flags();
1035 if (mc_lstat(path, &info))
1037 send_error();
1038 return;
1040 if (S_ISLNK(info.st_mode))
1041 return;
1043 if (!quiet)
1045 printf_send("<%s", path);
1046 printf_send(">");
1047 if (!printf_reply(from_parent, FALSE,
1048 _("?Change permissions of '%s'?"), path))
1049 return;
1051 else if (!o_brief)
1052 printf_send(_("'Changing permissions of '%s'\n"), path);
1054 for (;;)
1056 if (new_entry_string)
1058 if (mode_change)
1059 mode_free(mode_change);
1060 mode_change = nice_mode_compile(new_entry_string,
1061 MODE_MASK_ALL);
1062 null_g_free(&new_entry_string);
1065 if (mode_change)
1066 break;
1068 printf_send(
1069 _("!Invalid mode command - change it and try again\n"));
1070 if (!printf_reply(from_parent, TRUE,
1071 _("?Change permissions of '%s'?"), path))
1072 return;
1075 if (mc_lstat(path, &info))
1077 send_error();
1078 return;
1080 if (S_ISLNK(info.st_mode))
1081 return;
1083 new_mode = mode_adjust(info.st_mode, mode_change);
1084 if (chmod(path, new_mode))
1086 send_error();
1087 return;
1090 send_check_path(path);
1092 if (S_ISDIR(info.st_mode))
1094 send_mount_path(path);
1096 if (o_recurse)
1098 guchar *safe_path;
1099 safe_path = g_strdup(path);
1100 for_dir_contents(do_chmod, safe_path, safe_path);
1101 g_free(safe_path);
1106 /* We want to copy 'object' into directory 'dir'. If 'action_leaf'
1107 * is set then that is the new leafname, otherwise the leafname stays
1108 * the same.
1110 static const char *make_dest_path(const char *object, const char *dir)
1112 const char *leaf;
1114 if (action_leaf)
1115 leaf = action_leaf;
1116 else
1118 leaf = strrchr(object, '/');
1119 if (!leaf)
1120 leaf = object; /* Error? */
1121 else
1122 leaf++;
1125 return make_path(dir, leaf);
1128 /* If action_leaf is not NULL it specifies the new leaf name */
1129 static void do_copy2(const char *path, const char *dest)
1131 const char *dest_path;
1132 struct stat info;
1133 struct stat dest_info;
1135 check_flags();
1137 dest_path = make_dest_path(path, dest);
1139 if (mc_lstat(path, &info))
1141 send_error();
1142 return;
1145 if (mc_lstat(dest_path, &dest_info) == 0)
1147 int err;
1148 gboolean merge;
1150 merge = S_ISDIR(info.st_mode) && S_ISDIR(dest_info.st_mode);
1152 if (!merge && o_newer && info.st_mtime > dest_info.st_mtime)
1154 /* Newer; keep going */
1156 else
1158 printf_send("<%s", path);
1159 printf_send(">%s", dest_path);
1160 if (!printf_reply(from_parent, TRUE,
1161 _("?'%s' already exists - %s?"),
1162 dest_path,
1163 merge ? _("merge contents")
1164 : _("overwrite")))
1165 return;
1168 if (!merge)
1170 if (S_ISDIR(dest_info.st_mode))
1171 err = rmdir(dest_path);
1172 else
1173 err = unlink(dest_path);
1175 if (err)
1177 send_error();
1178 if (errno != ENOENT)
1179 return;
1180 printf_send(_("'Trying copy anyway...\n"));
1184 else if (!quiet)
1186 printf_send("<%s", path);
1187 printf_send(">");
1188 if (!printf_reply(from_parent, FALSE,
1189 _("?Copy %s as %s?"), path, dest_path))
1190 return;
1192 else
1193 printf_send(_("'Copying %s as %s\n"), path, dest_path);
1195 if (S_ISDIR(info.st_mode))
1197 mode_t mode = info.st_mode;
1198 char *safe_path, *safe_dest;
1199 struct stat dest_info;
1200 gboolean exists;
1202 safe_path = g_strdup(path);
1203 safe_dest = g_strdup(dest_path);
1205 exists = !mc_lstat(dest_path, &dest_info);
1207 if (exists && !S_ISDIR(dest_info.st_mode))
1208 printf_send(_("!ERROR: Destination already exists, "
1209 "but is not a directory\n"));
1210 else if (exists == FALSE && mkdir(dest_path, 0700 | mode))
1211 send_error();
1212 else
1214 if (!exists)
1215 /* (just been created then) */
1216 send_check_path(dest_path);
1218 action_leaf = NULL;
1219 for_dir_contents(do_copy2, safe_path, safe_dest);
1220 /* Note: dest_path now invalid... */
1222 if (!exists)
1224 struct utimbuf utb;
1226 /* We may have created the directory with
1227 * more permissions than the source so that
1228 * we could write to it... change it back now.
1230 if (chmod(safe_dest, mode))
1232 /* Some filesystems don't support
1233 * SetGID and SetUID bits. Ignore
1234 * these errors.
1236 if (errno != EPERM)
1237 send_error();
1240 /* Also, try to preserve the timestamps */
1241 utb.actime = info.st_atime;
1242 utb.modtime = info.st_mtime;
1244 utime(safe_dest, &utb);
1248 g_free(safe_path);
1249 g_free(safe_dest);
1251 else if (S_ISLNK(info.st_mode))
1253 char *target;
1255 /* Not all versions of cp(1) can make symlinks,
1256 * so we special-case it.
1259 target = readlink_dup(path);
1260 if (target)
1262 if (symlink(target, dest_path))
1263 send_error();
1264 else
1265 send_check_path(dest_path);
1267 g_free(target);
1269 else
1270 send_error();
1272 else
1274 guchar *error;
1276 error = copy_file(path, dest_path);
1278 if (error)
1280 printf_send(_("!%s\nFailed to copy '%s'\n"),
1281 error, path);
1282 g_free(error);
1284 else
1285 send_check_path(dest_path);
1289 /* If action_leaf is not NULL it specifies the new leaf name */
1290 static void do_move2(const char *path, const char *dest)
1292 const char *dest_path;
1293 const char *argv[] = {"mv", "-f", NULL, NULL, NULL};
1294 struct stat info2;
1295 gboolean is_dir;
1296 char *err;
1298 check_flags();
1300 dest_path = make_dest_path(path, dest);
1302 is_dir = mc_lstat(path, &info2) == 0 && S_ISDIR(info2.st_mode);
1304 if (access(dest_path, F_OK) == 0)
1306 struct stat info;
1307 int err;
1309 if (mc_lstat(dest_path, &info))
1311 send_error();
1312 return;
1315 if (!is_dir && o_newer && info2.st_mtime > info.st_mtime)
1317 /* Newer; keep going */
1319 else {
1320 printf_send("<%s", path);
1321 printf_send(">%s", dest_path);
1322 if (!printf_reply(from_parent, TRUE,
1323 _("?'%s' already exists - overwrite?"),
1324 dest_path))
1325 return;
1328 if (S_ISDIR(info.st_mode))
1329 err = rmdir(dest_path);
1330 else
1331 err = unlink(dest_path);
1333 if (err)
1335 send_error();
1336 if (errno != ENOENT)
1337 return;
1338 printf_send(_("'Trying move anyway...\n"));
1341 else if (!quiet)
1343 printf_send("<%s", path);
1344 printf_send(">");
1345 if (!printf_reply(from_parent, FALSE,
1346 _("?Move %s as %s?"), path, dest_path))
1347 return;
1349 else
1350 printf_send(_("'Moving %s as %s\n"), path, dest_path);
1352 argv[2] = path;
1353 argv[3] = dest_path;
1355 err = fork_exec_wait(argv);
1356 if (err)
1358 printf_send(_("!%s\nFailed to move %s as %s\n"),
1359 err, path, dest_path);
1360 g_free(err);
1362 else
1364 send_check_path(dest_path);
1366 if (is_dir)
1367 send_mount_path(path);
1368 else
1369 send_check_path(path);
1373 /* Copy path to dest.
1374 * Check that path not copied into itself.
1376 static void do_copy(const char *path, const char *dest)
1378 if (is_sub_dir(make_dest_path(path, dest), path))
1379 printf_send(_("!ERROR: Can't copy object into itself\n"));
1380 else
1382 do_copy2(path, dest);
1383 send_check_path(dest);
1387 /* Move path to dest.
1388 * Check that path not moved into itself.
1390 static void do_move(const char *path, const char *dest)
1392 if (is_sub_dir(make_dest_path(path, dest), path))
1393 printf_send(
1394 _("!ERROR: Can't move/rename object into itself\n"));
1395 else
1397 do_move2(path, dest);
1398 send_check_path(dest);
1402 static void do_link(const char *path, const char *dest)
1404 const char *dest_path;
1406 check_flags();
1408 dest_path = make_dest_path(path, dest);
1410 if (quiet)
1411 printf_send(_("'Linking %s as %s\n"), path, dest_path);
1412 else {
1413 printf_send("<%s", path);
1414 printf_send(">");
1415 if (!printf_reply(from_parent, FALSE,
1416 _("?Link %s as %s?"), path, dest_path))
1417 return;
1420 if (symlink(path, dest_path))
1421 send_error();
1422 else
1423 send_check_path(dest_path);
1426 /* Mount/umount this item (depending on 'mount') */
1427 static void do_mount(const guchar *path, gboolean mount)
1429 const char *argv[3] = {NULL, NULL, NULL};
1430 char *err;
1432 check_flags();
1434 argv[0] = mount ? "mount" : "umount";
1435 argv[1] = path;
1437 if (quiet)
1438 printf_send(mount ? _("'Mounting %s\n")
1439 : _("'Unmounting %s\n"),
1440 path);
1441 else if (!printf_reply(from_parent, FALSE,
1442 mount ? _("?Mount %s?")
1443 : _("?Unmount %s?"),
1444 path))
1445 return;
1447 if (!mount)
1449 char c = '?';
1450 /* Need to close all sub-directories now, or we
1451 * can't unmount if dnotify is used.
1453 printf_send("X%s", path);
1454 /* Wait until it's safe... */
1455 read(from_parent, &c, 1);
1456 g_return_if_fail(c == 'X');
1459 err = fork_exec_wait(argv);
1460 if (err)
1462 printf_send(mount ?
1463 _("!%s\nMount failed\n") :
1464 _("!%s\nUnmount failed\n"), err);
1465 g_free(err);
1467 /* Mount may have worked even on error, eg if we try to mount
1468 * a read-only disk read/write, it gets mounted read-only
1469 * with an error.
1471 if (mount && mount_is_mounted(path, NULL, NULL))
1472 printf_send(_("'(seems to be mounted now anyway)\n"));
1473 else
1474 return;
1477 printf_send("M%s", path);
1478 if (mount && mount_open_dir)
1479 printf_send("o%s", path);
1482 /* CHILD MAIN LOOPS */
1484 /* After forking, the child calls one of these functions */
1486 /* We use a double for total size in order to count beyond 4Gb */
1487 static void usage_cb(gpointer data)
1489 GList *paths = (GList *) data;
1490 double total_size = 0;
1492 dir_counter = file_counter = 0;
1494 for (; paths; paths = paths->next)
1496 guchar *path = (guchar *) paths->data;
1498 send_dir(path);
1500 size_tally = 0;
1502 do_usage(path, NULL);
1504 printf_send("'%s: %s\n",
1505 g_basename(path),
1506 format_double_size(size_tally));
1507 total_size += size_tally;
1510 g_string_printf(message, _("'\nTotal: %s ("),
1511 format_double_size(total_size));
1513 if (file_counter)
1514 g_string_append_printf(message,
1515 "%ld %s%s", file_counter,
1516 file_counter == 1 ? _("file") : _("files"),
1517 dir_counter ? ", " : ")\n");
1519 if (file_counter == 0 && dir_counter == 0)
1520 g_string_append(message, _("no directories)\n"));
1521 else if (dir_counter)
1522 g_string_append_printf(message,
1523 "%ld %s)\n", dir_counter,
1524 dir_counter == 1 ? _("directory")
1525 : _("directories"));
1527 send();
1530 #ifdef DO_MOUNT_POINTS
1531 static void mount_cb(gpointer data)
1533 GList *paths = (GList *) data;
1534 gboolean mount_points = FALSE;
1536 for (; paths; paths = paths->next)
1538 guchar *path = (guchar *) paths->data;
1539 guchar *target;
1541 target = readlink_dup(path);
1542 if (!target)
1543 target = path;
1545 if (mount_is_mounted(target, NULL, NULL))
1547 mount_points = TRUE;
1548 do_mount(target, FALSE); /* Unmount */
1550 else if (g_hash_table_lookup(fstab_mounts, target))
1552 mount_points = TRUE;
1553 do_mount(target, TRUE); /* Mount */
1556 if (target != path)
1557 g_free(target);
1560 if (mount_points)
1561 send_done();
1562 else
1563 printf_send(_("!No mount points selected!\n"));
1565 #endif
1567 /* (use g_dirname() instead?) */
1568 static guchar *dirname(guchar *path)
1570 guchar *slash;
1572 slash = strrchr(path, '/');
1573 g_return_val_if_fail(slash != NULL, g_strdup(path));
1575 if (slash != path)
1576 return g_strndup(path, slash - path);
1577 return g_strdup("/");
1580 static void delete_cb(gpointer data)
1582 GList *paths = (GList *) data;
1584 for (; paths; paths = paths->next)
1586 guchar *path = (guchar *) paths->data;
1587 guchar *dir;
1589 dir = dirname(path);
1590 send_dir(dir);
1592 do_delete(path, dir);
1594 g_free(dir);
1597 send_done();
1600 static void eject_cb(gpointer data)
1602 GList *paths = (GList *) data;
1604 for (; paths; paths = paths->next)
1606 guchar *path = (guchar *) paths->data;
1608 send_dir(path);
1610 do_eject(path);
1613 send_done();
1616 static void find_cb(gpointer data)
1618 GList *all_paths = (GList *) data;
1619 GList *paths;
1621 while (1)
1623 for (paths = all_paths; paths; paths = paths->next)
1625 guchar *path = (guchar *) paths->data;
1627 send_dir(path);
1629 do_find(path, NULL);
1632 if (!printf_reply(from_parent, TRUE,
1633 _("?Another search?")))
1634 break;
1635 printf_send("#");
1638 send_done();
1641 static void chmod_cb(gpointer data)
1643 GList *paths = (GList *) data;
1645 for (; paths; paths = paths->next)
1647 guchar *path = (guchar *) paths->data;
1648 struct stat info;
1650 send_dir(path);
1652 if (mc_stat(path, &info) != 0)
1653 send_error();
1654 else if (S_ISLNK(info.st_mode))
1655 printf_send(_("!'%s' is a symbolic link\n"),
1656 g_basename(path));
1657 else
1658 do_chmod(path, NULL);
1661 send_done();
1664 static void list_cb(gpointer data)
1666 GList *paths = (GList *) data;
1668 for (; paths; paths = paths->next)
1670 send_dir((char *) paths->data);
1672 action_do_func((char *) paths->data, action_dest);
1675 send_done();
1678 /* EXTERNAL INTERFACE */
1680 void action_find(GList *paths)
1682 GUIside *gui_side;
1683 GtkWidget *abox;
1685 if (!paths)
1687 report_error(_("You need to select some items "
1688 "to search through"));
1689 return;
1692 if (!last_find_string)
1693 last_find_string = g_strdup("'core'");
1695 new_entry_string = last_find_string;
1697 abox = abox_new(_("Find"), FALSE);
1698 gui_side = start_action(abox, find_cb, paths,
1699 o_action_force.int_value,
1700 o_action_brief.int_value,
1701 o_action_recurse.int_value,
1702 o_action_newer.int_value);
1703 if (!gui_side)
1704 return;
1706 abox_add_results(ABOX(abox));
1708 gui_side->default_string = &last_find_string;
1709 abox_add_entry(ABOX(abox), last_find_string,
1710 new_help_button(show_condition_help, NULL));
1711 g_signal_connect(ABOX(abox)->entry, "changed",
1712 G_CALLBACK(entry_changed), gui_side);
1713 set_find_string_colour(ABOX(abox)->entry, last_find_string);
1715 gui_side->show_info = TRUE;
1716 gui_side->entry_string_func = set_find_string_colour;
1718 number_of_windows++;
1719 gtk_widget_show_all(abox);
1722 /* Count disk space used by selected items */
1723 void action_usage(GList *paths)
1725 GUIside *gui_side;
1726 GtkWidget *abox;
1728 if (!paths)
1730 report_error(_("You need to select some items to count"));
1731 return;
1734 abox = abox_new(_("Disk Usage"), TRUE);
1736 gui_side = start_action(abox, usage_cb, paths,
1737 o_action_force.int_value,
1738 o_action_brief.int_value,
1739 o_action_recurse.int_value,
1740 o_action_newer.int_value);
1741 if (!gui_side)
1742 return;
1744 gui_side->show_info = TRUE;
1746 number_of_windows++;
1748 gtk_widget_show(abox);
1751 /* Mount/unmount listed items (paths).
1752 * Free the list after this function returns.
1753 * If open_dir is TRUE and the dir is successfully mounted, open it.
1754 * quiet can be -1 for default.
1756 void action_mount(GList *paths, gboolean open_dir, int quiet)
1758 #ifdef DO_MOUNT_POINTS
1759 GUIside *gui_side;
1760 GtkWidget *abox;
1762 if (quiet == -1)
1763 quiet = o_action_mount.int_value;
1765 mount_open_dir = open_dir;
1767 abox = abox_new(_("Mount / Unmount"), quiet);
1768 gui_side = start_action(abox, mount_cb, paths,
1769 o_action_force.int_value,
1770 o_action_brief.int_value,
1771 o_action_recurse.int_value,
1772 o_action_newer.int_value);
1773 if (!gui_side)
1774 return;
1776 number_of_windows++;
1777 gtk_widget_show(abox);
1778 #else
1779 report_error(
1780 _("ROX-Filer does not yet support mount points on your "
1781 "system. Sorry."));
1782 #endif /* DO_MOUNT_POINTS */
1785 /* Delete these paths */
1786 void action_delete(GList *paths)
1788 GUIside *gui_side;
1789 GtkWidget *abox;
1791 if (!remove_pinned_ok(paths))
1792 return;
1794 abox = abox_new(_("Delete"), o_action_delete.int_value);
1795 gui_side = start_action(abox, delete_cb, paths,
1796 o_action_force.int_value,
1797 o_action_brief.int_value,
1798 o_action_recurse.int_value,
1799 o_action_newer.int_value);
1800 if (!gui_side)
1801 return;
1803 abox_add_flag(ABOX(abox),
1804 _("Force"), _("Don't confirm deletion of non-writeable items"),
1805 'F', o_action_force.int_value);
1806 abox_add_flag(ABOX(abox),
1807 _("Brief"), _("Only log directories being deleted"),
1808 'B', o_action_brief.int_value);
1810 number_of_windows++;
1811 gtk_widget_show(abox);
1814 /* Change the permissions of the selected items */
1815 void action_chmod(GList *paths, gboolean force_recurse, const char *action)
1817 GtkWidget *abox;
1818 GUIside *gui_side;
1819 static GList *presets = NULL;
1820 gboolean recurse = force_recurse || o_action_recurse.int_value;
1822 if (!paths)
1824 report_error(_("You need to select the items "
1825 "whose permissions you want to change"));
1826 return;
1829 if (!presets)
1831 presets = g_list_append(presets, (gchar *)
1832 _("a+x (Make executable/searchable)"));
1833 presets = g_list_append(presets, (gchar *)
1834 _("a-x (Make non-executable/non-searchable)"));
1835 presets = g_list_append(presets, (gchar *)
1836 _("u+rw (Give owner read+write)"));
1837 presets = g_list_append(presets, (gchar *)
1838 _("go-rwx (Private - owner access only)"));
1839 presets = g_list_append(presets, (gchar *)
1840 _("go=u-w (Public access, not write)"));
1843 if (!last_chmod_string)
1844 last_chmod_string = g_strdup((guchar *) presets->data);
1846 if (action)
1847 new_entry_string = g_strdup(action);
1848 else
1849 new_entry_string = g_strdup(last_chmod_string);
1851 abox = abox_new(_("Permissions"), FALSE);
1852 gui_side = start_action(abox, chmod_cb, paths,
1853 o_action_force.int_value,
1854 o_action_brief.int_value,
1855 recurse,
1856 o_action_newer.int_value);
1858 if (!gui_side)
1859 goto out;
1861 abox_add_flag(ABOX(abox),
1862 _("Brief"), _("Don't list processed files"),
1863 'B', o_action_brief.int_value);
1864 abox_add_flag(ABOX(abox),
1865 _("Recurse"), _("Also change contents of subdirectories"),
1866 'R', recurse);
1868 gui_side->default_string = &last_chmod_string;
1869 abox_add_combo(ABOX(abox), presets, new_entry_string,
1870 new_help_button(show_chmod_help, NULL));
1872 g_signal_connect(ABOX(abox)->entry, "changed",
1873 G_CALLBACK(entry_changed), gui_side);
1874 #if 0
1875 g_signal_connect_swapped(gui_side->entry, "activate",
1876 G_CALLBACK(gtk_button_clicked),
1877 gui_side->yes);
1878 #endif
1880 number_of_windows++;
1881 gtk_widget_show(abox);
1883 out:
1884 null_g_free(&new_entry_string);
1887 /* If leaf is NULL then the copy has the same name as the original.
1888 * quiet can be -1 for default.
1890 void action_copy(GList *paths, const char *dest, const char *leaf, int quiet)
1892 GUIside *gui_side;
1893 GtkWidget *abox;
1895 if (quiet == -1)
1896 quiet = o_action_copy.int_value;
1898 action_dest = dest;
1899 action_leaf = leaf;
1900 action_do_func = do_copy;
1902 abox = abox_new(_("Copy"), quiet);
1903 gui_side = start_action(abox, list_cb, paths,
1904 o_action_force.int_value,
1905 o_action_brief.int_value,
1906 o_action_recurse.int_value,
1907 o_action_newer.int_value);
1908 if (!gui_side)
1909 return;
1911 abox_add_flag(ABOX(abox),
1912 _("Newer"),
1913 _("Only over-write if source is newer than destination."),
1914 'W', o_action_newer.int_value);
1916 number_of_windows++;
1917 gtk_widget_show(abox);
1920 /* If leaf is NULL then the file is not renamed.
1921 * quiet can be -1 for default.
1923 void action_move(GList *paths, const char *dest, const char *leaf, int quiet)
1925 GUIside *gui_side;
1926 GtkWidget *abox;
1928 if (quiet == -1)
1929 quiet = o_action_move.int_value;
1931 action_dest = dest;
1932 action_leaf = leaf;
1933 action_do_func = do_move;
1935 abox = abox_new(_("Move"), quiet);
1936 gui_side = start_action(abox, list_cb, paths,
1937 o_action_force.int_value,
1938 o_action_brief.int_value,
1939 o_action_recurse.int_value,
1940 o_action_newer.int_value);
1941 if (!gui_side)
1942 return;
1944 abox_add_flag(ABOX(abox),
1945 _("Newer"),
1946 _("Only over-write if source is newer than destination."),
1947 'W', o_action_newer.int_value);
1948 number_of_windows++;
1949 gtk_widget_show(abox);
1952 /* If leaf is NULL then the link will have the same name */
1953 /* XXX: No quiet option here? */
1954 void action_link(GList *paths, const char *dest, const char *leaf)
1956 GtkWidget *abox;
1957 GUIside *gui_side;
1959 action_dest = dest;
1960 action_leaf = leaf;
1961 action_do_func = do_link;
1963 abox = abox_new(_("Link"), o_action_link.int_value);
1964 gui_side = start_action(abox, list_cb, paths,
1965 o_action_force.int_value,
1966 o_action_brief.int_value,
1967 o_action_recurse.int_value,
1968 o_action_newer.int_value);
1969 if (!gui_side)
1970 return;
1972 number_of_windows++;
1973 gtk_widget_show(abox);
1976 /* Eject these paths */
1977 void action_eject(GList *paths)
1979 GUIside *gui_side;
1980 GtkWidget *abox;
1982 abox = abox_new(_("Eject"), 0);
1983 gui_side = start_action(abox, eject_cb, paths,
1984 o_action_force.int_value,
1985 o_action_brief.int_value,
1986 o_action_recurse.int_value,
1987 o_action_newer.int_value);
1988 if (!gui_side)
1989 return;
1991 number_of_windows++;
1992 gtk_widget_show(abox);
1995 void action_init(void)
1997 option_add_int(&o_action_copy, "action_copy", 1);
1998 option_add_int(&o_action_move, "action_move", 1);
1999 option_add_int(&o_action_link, "action_link", 1);
2000 option_add_int(&o_action_delete, "action_delete", 0);
2001 option_add_int(&o_action_mount, "action_mount", 1);
2002 option_add_int(&o_action_force, "action_force", FALSE);
2003 option_add_int(&o_action_brief, "action_brief", FALSE);
2004 option_add_int(&o_action_recurse, "action_recurse", FALSE);
2005 option_add_int(&o_action_newer, "action_newer", FALSE);
2008 #define MAX_ASK 4
2010 /* Check to see if any of the selected items (or their children) are
2011 * on the pinboard or panel. If so, ask for confirmation.
2013 * TRUE if it's OK to lose them.
2015 static gboolean remove_pinned_ok(GList *paths)
2017 GList *ask = NULL, *next;
2018 GString *message;
2019 int i, ask_n = 0;
2020 gboolean retval;
2022 for (; paths; paths = paths->next)
2024 guchar *path = (guchar *) paths->data;
2026 if (icons_require(path))
2028 if (++ask_n > MAX_ASK)
2029 break;
2030 ask = g_list_append(ask, path);
2034 if (!ask)
2035 return TRUE;
2037 if (ask_n > MAX_ASK)
2039 message = g_string_new(_("Deleting items such as "));
2040 ask_n--;
2042 else if (ask_n == 1)
2043 message = g_string_new(_("Deleting the item "));
2044 else
2045 message = g_string_new(_("Deleting the items "));
2047 i = 0;
2048 for (next = ask; next; next = next->next)
2050 guchar *path = (guchar *) next->data;
2051 guchar *leaf;
2053 leaf = strrchr(path, '/');
2054 if (leaf)
2055 leaf++;
2056 else
2057 leaf = path;
2059 g_string_append_c(message, '`');
2060 g_string_append(message, leaf);
2061 g_string_append_c(message, '\'');
2062 i++;
2063 if (i == ask_n - 1 && i > 0)
2064 g_string_append(message, _(" and "));
2065 else if (i < ask_n)
2066 g_string_append(message, ", ");
2069 g_list_free(ask);
2071 if (ask_n == 1)
2072 message = g_string_append(message,
2073 _(" will affect some items on the pinboard "
2074 "or panel - really delete it?"));
2075 else
2077 if (ask_n > MAX_ASK)
2078 message = g_string_append_c(message, ',');
2079 message = g_string_append(message,
2080 _(" will affect some items on the pinboard "
2081 "or panel - really delete them?"));
2084 retval = confirm(message->str, GTK_STOCK_DELETE, NULL);
2086 g_string_free(message, TRUE);
2088 return retval;
2091 void set_find_string_colour(GtkWidget *widget, const guchar *string)
2093 FindCondition *cond;
2095 cond = find_compile(string);
2096 entry_set_error(widget, !cond);
2098 find_condition_free(cond);