1 /* File management GUI for the text mode edition
3 * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
4 * 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
6 * Written by: 1994, 1995 Janne Kukonlehto
7 * 1994, 1995 Fred Leeflang
8 * 1994, 1995, 1996 Miguel de Icaza
9 * 1995, 1996 Jakub Jelinek
10 * 1997 Norbert Warmuth
14 * The copy code was based in GNU's cp, and was written by:
15 * Torbjorn Granlund, David MacKenzie, and Jim Meyering.
17 * The move code was based in GNU's mv, and was written by:
18 * Mike Parker and David MacKenzie.
20 * Janne Kukonlehto added much error recovery to them for being used
21 * in an interactive program.
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
39 * Please note that all dialogs used here must be safe for background
44 * \brief Source: file management GUI for the text mode edition
47 /* {{{ Include files */
55 #include <sys/types.h>
58 #if defined (__FreeBSD__)
59 # include <sys/param.h>
61 #if defined(__APPLE__) || defined (__FreeBSD__)
62 # include <sys/mount.h>
63 #elif defined (__NetBSD__)
64 # include <sys/param.h>
69 # include <sys/statfs.h>
77 #include "../src/tty/key.h" /* tty_get_event */
79 #include "../src/search/search.h"
81 #include "setup.h" /* verbose */
82 #include "dialog.h" /* do_refresh() */
83 #include "widget.h" /* WLabel */
84 #include "main-widgets.h"
85 #include "main.h" /* the_hint */
86 #include "wtools.h" /* QuickDialog */
87 #include "panel.h" /* current_panel */
88 #include "fileopctx.h" /* FILE_CONT */
90 #include "util.h" /* strip_password() */
92 #include "../src/strescape.h"
96 MSDOS_SUPER_MAGIC
= 0x4d44,
97 NTFS_SB_MAGIC
= 0x5346544e,
98 NTFS_3G_MAGIC
= 0x65735546,
99 PROC_SUPER_MAGIC
= 0x9fa0,
100 SMB_SUPER_MAGIC
= 0x517B,
101 NCP_SUPER_MAGIC
= 0x564c,
102 USBDEVICE_SUPER_MAGIC
= 0x9fa2
103 } filegui_nonattrs_fs_t
;
105 /* Hack: the vfs code should not rely on this */
106 #define WITH_FULL_PATHS 1
108 /* This structure describes the UI and internal data required by a file
118 /* Dialog and widgets for the operation progress window */
122 WLabel
*file_label
[2];
123 WLabel
*file_string
[2];
124 WLabel
*progress_label
[3];
125 WGauge
*progress_gauge
[3];
128 WLabel
*stalled_label
;
130 /* Query replace dialog */
132 Dlg_head
*replace_dlg
;
133 const char *replace_filename
;
135 struct stat
*s_stat
, *d_stat
;
139 /* Used to save the hint line */
140 static int last_hint_line
;
142 /* File operate window sizes */
146 #define WX_ETA_EXTRA 12
148 #define FCOPY_GAUGE_X 14
149 #define FCOPY_LABEL_X 5
151 /* Used for button result values */
153 REPLACE_YES
= B_USER
,
165 filegui__check_attrs_on_fs(const char *fs_path
)
169 if (statfs(fs_path
, &stfs
)!=0)
172 switch ((filegui_nonattrs_fs_t
) stfs
.f_type
)
174 case MSDOS_SUPER_MAGIC
:
177 case PROC_SUPER_MAGIC
:
178 case SMB_SUPER_MAGIC
:
179 case NCP_SUPER_MAGIC
:
180 case USBDEVICE_SUPER_MAGIC
:
187 static FileProgressStatus
188 check_progress_buttons (FileOpContext
*ctx
)
199 event
.x
= -1; /* Don't show the GPM cursor */
200 c
= tty_get_event (&event
, FALSE
, FALSE
);
204 /* Reinitialize to avoid old values after events other than
205 selecting a button */
206 ui
->op_dlg
->ret_value
= FILE_CONT
;
208 dlg_process_event (ui
->op_dlg
, c
, &event
);
209 switch (ui
->op_dlg
->ret_value
) {
222 /* {{{ File progress display routines */
225 file_op_context_create_ui (FileOpContext
*ctx
, int with_eta
)
234 g_return_if_fail (ctx
!= NULL
);
235 g_return_if_fail (ctx
->ui
== NULL
);
237 ui
= g_new0 (FileOpContextUI
, 1);
240 minus
= verbose
? 0 : 3;
241 eta_offset
= with_eta
? (WX_ETA_EXTRA
) / 2 : 0;
246 ctx
->recursive_result
= 0;
248 ui
->replace_result
= 0;
249 ui
->showing_eta
= with_eta
;
250 ui
->showing_bps
= with_eta
;
251 ui
->eta_extra
= with_eta
? WX_ETA_EXTRA
: 0;
252 x_size
= (WX
+ 4) + ui
->eta_extra
;
255 create_dlg (0, 0, WY
- minus
+ 4, x_size
, dialog_colors
, NULL
,
256 NULL
, op_names
[ctx
->operation
],
257 DLG_CENTER
| DLG_REVERSE
);
259 last_hint_line
= the_hint
->widget
.y
;
260 if ((ui
->op_dlg
->y
+ ui
->op_dlg
->lines
) > last_hint_line
)
261 the_hint
->widget
.y
= ui
->op_dlg
->y
+ ui
->op_dlg
->lines
+ 1;
263 add_widget (ui
->op_dlg
,
264 button_new (BY
- minus
, WX
- 19 + eta_offset
, FILE_ABORT
,
265 NORMAL_BUTTON
, _("&Abort"), 0));
266 add_widget (ui
->op_dlg
,
267 button_new (BY
- minus
, 14 + eta_offset
, FILE_SKIP
,
268 NORMAL_BUTTON
, _("&Skip"), 0));
270 add_widget (ui
->op_dlg
, ui
->progress_gauge
[2] =
271 gauge_new (7, FCOPY_GAUGE_X
, 0, 100, 0));
272 add_widget (ui
->op_dlg
, ui
->progress_label
[2] =
273 label_new (7, FCOPY_LABEL_X
, fifteen
));
274 add_widget (ui
->op_dlg
, ui
->bps_label
= label_new (7, WX
, ""));
276 add_widget (ui
->op_dlg
, ui
->progress_gauge
[1] =
277 gauge_new (8, FCOPY_GAUGE_X
, 0, 100, 0));
278 add_widget (ui
->op_dlg
, ui
->progress_label
[1] =
279 label_new (8, FCOPY_LABEL_X
, fifteen
));
280 add_widget (ui
->op_dlg
, ui
->stalled_label
= label_new (8, WX
, ""));
282 add_widget (ui
->op_dlg
, ui
->progress_gauge
[0] =
283 gauge_new (6, FCOPY_GAUGE_X
, 0, 100, 0));
284 add_widget (ui
->op_dlg
, ui
->progress_label
[0] =
285 label_new (6, FCOPY_LABEL_X
, fifteen
));
286 add_widget (ui
->op_dlg
, ui
->eta_label
= label_new (6, WX
, ""));
288 add_widget (ui
->op_dlg
, ui
->file_string
[1] =
289 label_new (4, FCOPY_GAUGE_X
, sixty
));
290 add_widget (ui
->op_dlg
, ui
->file_label
[1] =
291 label_new (4, FCOPY_LABEL_X
, fifteen
));
292 add_widget (ui
->op_dlg
, ui
->file_string
[0] =
293 label_new (3, FCOPY_GAUGE_X
, sixty
));
294 add_widget (ui
->op_dlg
, ui
->file_label
[0] =
295 label_new (3, FCOPY_LABEL_X
, fifteen
));
297 /* We will manage the dialog without any help, that's why
298 we have to call init_dlg */
299 init_dlg (ui
->op_dlg
);
300 ui
->op_dlg
->running
= 1;
304 file_op_context_destroy_ui (FileOpContext
*ctx
)
308 g_return_if_fail (ctx
!= NULL
);
313 dlg_run_done (ui
->op_dlg
);
314 destroy_dlg (ui
->op_dlg
);
318 the_hint
->widget
.y
= last_hint_line
;
323 static FileProgressStatus
324 show_no_bar (FileOpContext
*ctx
, int n
)
334 label_set_text (ui
->progress_label
[n
], "");
335 gauge_show (ui
->progress_gauge
[n
], 0);
337 return check_progress_buttons (ctx
);
340 static FileProgressStatus
341 show_bar (FileOpContext
*ctx
, int n
, double done
, double total
)
351 * Gauge needs integers, so give it with integers between 0 and 1023.
352 * This precision should be quite reasonable.
354 gauge_set_value (ui
->progress_gauge
[n
], 1024,
355 (int) (1024 * done
/ total
));
356 gauge_show (ui
->progress_gauge
[n
], 1);
357 return check_progress_buttons (ctx
);
361 file_eta_show (FileOpContext
*ctx
)
363 int eta_hours
, eta_mins
, eta_s
;
364 char eta_buffer
[BUF_TINY
];
372 if (!ui
->showing_eta
)
375 if (ctx
->eta_secs
> 0.5) {
376 eta_hours
= ctx
->eta_secs
/ (60 * 60);
377 eta_mins
= (ctx
->eta_secs
- (eta_hours
* 60 * 60)) / 60;
378 eta_s
= ctx
->eta_secs
- (eta_hours
* 60 * 60 + eta_mins
* 60);
379 g_snprintf (eta_buffer
, sizeof (eta_buffer
), _("ETA %d:%02d.%02d"),
380 eta_hours
, eta_mins
, eta_s
);
384 label_set_text (ui
->eta_label
, eta_buffer
);
388 file_bps_show (FileOpContext
*ctx
)
390 char bps_buffer
[BUF_TINY
];
398 if (!ui
->showing_bps
)
401 if (ctx
->bps
> 1024 * 1024) {
402 g_snprintf (bps_buffer
, sizeof (bps_buffer
), _("%.2f MB/s"),
403 ctx
->bps
/ (1024 * 1024.0));
404 } else if (ctx
->bps
> 1024) {
405 g_snprintf (bps_buffer
, sizeof (bps_buffer
), _("%.2f KB/s"),
407 } else if (ctx
->bps
> 1) {
408 g_snprintf (bps_buffer
, sizeof (bps_buffer
), _("%ld B/s"),
413 label_set_text (ui
->bps_label
, bps_buffer
);
417 file_progress_show (FileOpContext
*ctx
, off_t done
, off_t total
)
421 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
429 return check_progress_buttons (ctx
);
431 label_set_text (ui
->progress_label
[0], _("File"));
434 return show_bar (ctx
, 0, done
, total
);
436 return show_no_bar (ctx
, 0);
440 file_progress_show_count (FileOpContext
*ctx
, off_t done
, off_t total
)
444 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
452 return check_progress_buttons (ctx
);
454 label_set_text (ui
->progress_label
[1], _("Count"));
455 return show_bar (ctx
, 1, done
, total
);
457 return show_no_bar (ctx
, 1);
461 file_progress_show_bytes (FileOpContext
*ctx
, double done
, double total
)
465 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
473 return check_progress_buttons (ctx
);
475 label_set_text (ui
->progress_label
[2], _("Bytes"));
476 return show_bar (ctx
, 2, done
, total
);
478 return show_no_bar (ctx
, 2);
483 #define truncFileString(ui, s) str_trunc (s, ui->eta_extra + 47)
484 #define truncFileStringSecure(ui, s) path_trunc (s, ui->eta_extra + 47)
487 file_progress_show_source (FileOpContext
*ctx
, const char *s
)
491 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
499 #ifdef WITH_FULL_PATHS
500 int i
= strlen (current_panel
->cwd
);
502 /* We remove the full path we have added before */
503 if (!strncmp (s
, current_panel
->cwd
, i
)) {
504 if (s
[i
] == PATH_SEP
)
507 #endif /* WITH_FULL_PATHS */
509 label_set_text (ui
->file_label
[0], _("Source"));
510 label_set_text (ui
->file_string
[0], truncFileString (ui
, s
));
511 return check_progress_buttons (ctx
);
513 label_set_text (ui
->file_label
[0], "");
514 label_set_text (ui
->file_string
[0], "");
515 return check_progress_buttons (ctx
);
520 file_progress_show_target (FileOpContext
*ctx
, const char *s
)
524 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
532 label_set_text (ui
->file_label
[1], _("Target"));
533 label_set_text (ui
->file_string
[1], truncFileStringSecure (ui
, s
));
534 return check_progress_buttons (ctx
);
536 label_set_text (ui
->file_label
[1], "");
537 label_set_text (ui
->file_string
[1], "");
538 return check_progress_buttons (ctx
);
543 file_progress_show_deleting (FileOpContext
*ctx
, const char *s
)
547 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
554 label_set_text (ui
->file_label
[0], _("Deleting"));
555 label_set_text (ui
->file_label
[0], truncFileStringSecure (ui
, s
));
556 return check_progress_buttons (ctx
);
562 * FIXME: probably it is better to replace this with quick dialog machinery,
563 * but actually I'm not familiar with it and have not much time :(
569 int value
; /* 0 for labels */
572 N_("Target file \"%s\" already exists!"), 3, 4, 0}, {
573 N_("&Abort"), BY
+ 3, 25, REPLACE_ABORT
}, {
574 N_("If &size differs"), BY
+ 1, 28, REPLACE_SIZE
}, {
575 N_("Non&e"), BY
, 47, REPLACE_NEVER
}, {
576 N_("&Update"), BY
, 36, REPLACE_UPDATE
}, {
577 N_("A&ll"), BY
, 28, REPLACE_ALWAYS
}, {
578 N_("Overwrite all targets?"), BY
, 4, 0}, {
579 N_("&Reget"), BY
- 1, 28, REPLACE_REGET
}, {
580 N_("A&ppend"), BY
- 2, 45, REPLACE_APPEND
}, {
581 N_("&No"), BY
- 2, 37, REPLACE_NO
}, {
582 N_("&Yes"), BY
- 2, 28, REPLACE_YES
}, {
583 N_("Overwrite this target?"), BY
- 2, 4, 0}, {
584 #if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || (defined _LARGE_FILES && _LARGE_FILES)
585 N_("Target date: %s, size %llu"), 6, 4, 0}, {
586 N_("Source date: %s, size %llu"), 5, 4, 0}
588 N_("Target date: %s, size %u"), 6, 4, 0}, {
589 N_("Source date: %s, size %u"), 5, 4, 0}
593 #define ADD_RD_BUTTON(i)\
594 add_widget (ui->replace_dlg,\
595 button_new (rd_widgets [i].ypos, rd_widgets [i].xpos, rd_widgets [i].value,\
596 NORMAL_BUTTON, rd_widgets [i].text, 0))
598 #define ADD_RD_LABEL(ui,i,p1,p2)\
599 g_snprintf (buffer, sizeof (buffer), rd_widgets [i].text, p1, p2);\
600 add_widget (ui->replace_dlg,\
601 label_new (rd_widgets [i].ypos, rd_widgets [i].xpos, buffer))
604 init_replace (FileOpContext
*ctx
, enum OperationMode mode
)
607 char buffer
[BUF_SMALL
];
609 static int rd_xlen
= 60, rd_trunc
= X_TRUNC
;
612 static int i18n_flag
;
615 register int i
= sizeof (rd_widgets
) / sizeof (rd_widgets
[0]);
617 rd_widgets
[i
].text
= _(rd_widgets
[i
].text
);
620 * longest of "Overwrite..." labels
621 * (assume "Target date..." are short enough)
623 l1
= max (str_term_width1 (rd_widgets
[6].text
),
624 str_term_width1 (rd_widgets
[11].text
));
626 /* longest of button rows */
627 i
= sizeof (rd_widgets
) / sizeof (rd_widgets
[0]);
628 for (row
= l
= l2
= 0; i
--;) {
629 if (rd_widgets
[i
].value
!= 0) {
630 if (row
!= rd_widgets
[i
].ypos
) {
631 row
= rd_widgets
[i
].ypos
;
635 l
+= str_term_width1 (rd_widgets
[i
].text
) + 4;
638 l2
= max (l2
, l
); /* last row */
639 rd_xlen
= max (rd_xlen
, l1
+ l2
+ 8);
640 rd_trunc
= rd_xlen
- 6;
642 /* Now place buttons */
643 l1
+= 5; /* start of first button in the row */
644 i
= sizeof (rd_widgets
) / sizeof (rd_widgets
[0]);
646 for (l
= l1
, row
= 0; --i
> 1;) {
647 if (rd_widgets
[i
].value
!= 0) {
648 if (row
!= rd_widgets
[i
].ypos
) {
649 row
= rd_widgets
[i
].ypos
;
652 rd_widgets
[i
].xpos
= l
;
653 l
+= str_term_width1 (rd_widgets
[i
].text
) + 4;
656 /* Abort button is centered */
658 (rd_xlen
- str_term_width1 (rd_widgets
[1].text
) - 3) / 2;
660 #endif /* ENABLE_NLS */
664 if (mode
== Foreground
)
665 title
= _(" File exists ");
667 title
= _(" Background process: File exists ");
669 /* FIXME - missing help node */
671 create_dlg (0, 0, 16, rd_xlen
, alarm_colors
, NULL
, "[Replace]",
672 title
, DLG_CENTER
| DLG_REVERSE
);
676 str_trunc (ui
->replace_filename
,
677 rd_trunc
- str_term_width1 (rd_widgets
[0].text
)), 0);
684 ADD_RD_LABEL (ui
, 6, 0, 0);
686 /* "this target..." widgets */
687 if (!S_ISDIR (ui
->d_stat
->st_mode
)) {
688 if ((ctx
->operation
== OP_COPY
) && (ui
->d_stat
->st_size
!= 0)
689 && (ui
->s_stat
->st_size
> ui
->d_stat
->st_size
))
690 ADD_RD_BUTTON (7); /* reget */
692 ADD_RD_BUTTON (8); /* Overwrite all targets? */
696 ADD_RD_LABEL (ui
, 11, 0, 0);
698 ADD_RD_LABEL (ui
, 12, file_date (ui
->d_stat
->st_mtime
),
699 (off_t
) ui
->d_stat
->st_size
);
700 ADD_RD_LABEL (ui
, 13, file_date (ui
->s_stat
->st_mtime
),
701 (off_t
) ui
->s_stat
->st_size
);
705 file_progress_set_stalled_label (FileOpContext
*ctx
, const char *stalled_msg
)
709 g_return_if_fail (ctx
!= NULL
);
716 label_set_text (ui
->stalled_label
, stalled_msg
);
720 file_progress_real_query_replace (FileOpContext
*ctx
,
721 enum OperationMode mode
, const char *destname
,
722 struct stat
*_s_stat
,
723 struct stat
*_d_stat
)
727 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
728 g_return_val_if_fail (ctx
->ui
!= NULL
, FILE_CONT
);
732 if (ui
->replace_result
< REPLACE_ALWAYS
) {
733 ui
->replace_filename
= destname
;
734 ui
->s_stat
= _s_stat
;
735 ui
->d_stat
= _d_stat
;
736 init_replace (ctx
, mode
);
737 run_dlg (ui
->replace_dlg
);
738 ui
->replace_result
= ui
->replace_dlg
->ret_value
;
739 if (ui
->replace_result
== B_CANCEL
)
740 ui
->replace_result
= REPLACE_ABORT
;
741 destroy_dlg (ui
->replace_dlg
);
744 switch (ui
->replace_result
) {
747 if (_s_stat
->st_mtime
> _d_stat
->st_mtime
)
754 if (_s_stat
->st_size
== _d_stat
->st_size
)
760 /* Careful: we fall through and set do_append */
761 ctx
->do_reget
= _d_stat
->st_size
;
783 static QuickWidget fmd_widgets
[] = {
788 /* follow symlinks and preserve Attributes must be the first */
789 {quick_checkbox
, 3, 64, 8, FMDY
, N_("preserve &Attributes"), 9, 0,
790 0 /* &op_preserve */ , 0, NULL
, NULL
, NULL
},
791 {quick_checkbox
, 3, 64, 7, FMDY
, N_("follow &Links"), 7, 0,
792 0 /* &file_mask_op_follow_links */ , 0, NULL
, NULL
, NULL
},
793 {quick_label
, 3, 64, 5, FMDY
, N_("to:"), 0, 0, 0, 0, NULL
, NULL
, NULL
},
794 {quick_checkbox
, 37, 64, 4, FMDY
, N_("&Using shell patterns"), 0, 0,
795 0 /* &source_easy_patterns */ , 0, NULL
, NULL
, NULL
},
796 {quick_input
, 3, 64, 3, FMDY
, "", 58,
797 0, 0, 0, "input-def", NULL
, NULL
},
801 {quick_input
, 3, 64, 6, FMDY
, "", 58, 0,
802 0, 0, "input2", NULL
, NULL
},
804 {quick_label
, 3, 64, 2, FMDY
, "", 0, 0, 0, 0, NULL
, NULL
, NULL
},
806 {quick_button
, 42, 64, 9, FMDY
, N_("&Cancel"), 0, B_CANCEL
, 0, 0,
809 #ifdef WITH_BACKGROUND
815 {quick_button
, 25, 64, 9, FMDY
, N_("&Background"), 0, B_USER
, 0, 0,
817 #else /* WITH_BACKGROUND */
824 {quick_button
, 14, 64, 9, FMDY
, N_("&OK"), 0, B_ENTER
, 0, 0, NULL
, NULL
, NULL
},
825 {quick_checkbox
, 42, 64, 8, FMDY
, N_("&Stable Symlinks"), 0, 0,
826 0 /* &file_mask_stable_symlinks */ , 0, NULL
, NULL
, NULL
},
827 {quick_checkbox
, 31, 64, 7, FMDY
, N_("&Dive into subdir if exists"), 0,
828 0, 0 /* &dive_into_subdirs */ , 0, NULL
, NULL
, NULL
},
833 is_wildcarded (char *p
)
838 else if (*p
== '\\' && p
[1] >= '1' && p
[1] <= '9')
845 fmd_init_i18n (int force
)
848 static int initialized
= FALSE
;
852 if (initialized
&& !force
)
855 for (i
= sizeof (op_names
) / sizeof (op_names
[0]); i
--;)
856 op_names
[i
] = _(op_names
[i
]);
858 i
= sizeof (fmd_widgets
) / sizeof (fmd_widgets
[0]) - 1;
860 if (fmd_widgets
[i
].text
[0] != '\0')
861 fmd_widgets
[i
].text
= _(fmd_widgets
[i
].text
);
863 len
= str_term_width1 (fmd_widgets
[FMCB11
].text
)
864 + str_term_width1 (fmd_widgets
[FMCB21
].text
) + 15;
865 fmd_xlen
= max (fmd_xlen
, len
);
867 len
= str_term_width1 (fmd_widgets
[FMCB12
].text
)
868 + str_term_width1 (fmd_widgets
[FMCB22
].text
) + 15;
869 fmd_xlen
= max (fmd_xlen
, len
);
871 len
= str_term_width1 (fmd_widgets
[FMBRGT
].text
)
872 + str_term_width1 (fmd_widgets
[FMBLFT
].text
) + 11;
875 len
+= str_term_width1 (fmd_widgets
[FMBMID
].text
) + 6;
878 fmd_xlen
= max (fmd_xlen
, len
+ 4);
880 len
= (fmd_xlen
- (len
+ 6)) / 2;
881 i
= fmd_widgets
[FMBLFT
].relative_x
= len
+ 3;
882 i
+= str_term_width1 (fmd_widgets
[FMBLFT
].text
) + 8;
885 fmd_widgets
[FMBMID
].relative_x
= i
;
886 i
+= str_term_width1 (fmd_widgets
[FMBMID
].text
) + 6;
889 fmd_widgets
[FMBRGT
].relative_x
= i
;
891 #define chkbox_xpos(i) \
892 fmd_widgets [i].relative_x = fmd_xlen - str_term_width1 (fmd_widgets [i].text) - 6
895 chkbox_xpos (FMCB21
);
896 chkbox_xpos (FMCB22
);
898 if (fmd_xlen
!= FMD_XLEN
) {
899 i
= sizeof (fmd_widgets
) / sizeof (fmd_widgets
[0]) - 1;
901 fmd_widgets
[i
].x_divisions
= fmd_xlen
;
903 fmd_widgets
[FMDI1
].hotkey_pos
=
904 fmd_widgets
[FMDI2
].hotkey_pos
= fmd_xlen
- 6;
909 #endif /* !ENABLE_NLS */
913 file_mask_dialog (FileOpContext
*ctx
, FileOperation operation
, const char *text
,
914 const char *def_text
, int only_one
, int *do_background
)
916 int source_easy_patterns
= easy_patterns
;
917 char *source_mask
, *orig_mask
, *dest_dir
, *tmp
;
918 char *def_text_secure
;
921 QuickDialog Quick_input
;
923 g_return_val_if_fail (ctx
!= NULL
, NULL
);
925 fmd_init_i18n (FALSE
);
927 /* unselect checkbox if target filesystem don't support attributes */
928 ctx
->op_preserve
= filegui__check_attrs_on_fs(def_text
);
930 /* Set up the result pointers */
932 fmd_widgets
[FMCB12
].result
= &ctx
->op_preserve
;
933 fmd_widgets
[FMCB11
].result
= &ctx
->follow_links
;
934 fmd_widgets
[FMCB22
].result
= &ctx
->stable_symlinks
;
935 fmd_widgets
[FMCB21
].result
= &ctx
->dive_into_subdirs
;
937 /* filter out a possible password from def_text */
938 tmp
= strip_password (g_strdup (def_text
), 1);
939 if (source_easy_patterns
)
940 def_text_secure
= strutils_glob_escape (tmp
);
942 def_text_secure
= strutils_regex_escape (tmp
);
945 /* Create the dialog */
947 ctx
->stable_symlinks
= 0;
948 fmd_widgets
[FMDC
].result
= &source_easy_patterns
;
949 fmd_widgets
[FMDI1
].text
= easy_patterns
? "*" : "^\\(.*\\)$";
950 Quick_input
.xlen
= fmd_xlen
;
951 Quick_input
.xpos
= -1;
952 Quick_input
.title
= op_names
[operation
];
953 Quick_input
.help
= "[Mask Copy/Rename]";
954 Quick_input
.ylen
= FMDY
;
955 Quick_input
.i18n
= 1;
956 Quick_input
.widgets
= fmd_widgets
;
957 fmd_widgets
[FMDI0
].text
= text
;
958 fmd_widgets
[FMDI2
].text
= def_text_secure
;
959 fmd_widgets
[FMDI2
].str_result
= &dest_dir
;
960 fmd_widgets
[FMDI1
].str_result
= &source_mask
;
965 val
= quick_dialog_skip (&Quick_input
, SKIP
);
967 if (val
== B_CANCEL
) {
968 g_free (def_text_secure
);
972 if (ctx
->follow_links
)
973 ctx
->stat_func
= mc_stat
;
975 ctx
->stat_func
= mc_lstat
;
977 if (ctx
->op_preserve
) {
979 ctx
->umask_kill
= 0777777;
980 ctx
->preserve_uidgid
= (geteuid () == 0) ? 1 : 0;
983 ctx
->preserve
= ctx
->preserve_uidgid
= 0;
986 ctx
->umask_kill
= i
^ 0777777;
989 if (!dest_dir
|| !*dest_dir
) {
990 g_free (def_text_secure
);
991 g_free (source_mask
);
995 ctx
->search_handle
= mc_search_new(source_mask
,-1);
997 if (ctx
->search_handle
== NULL
) {
998 message (D_ERROR
, MSG_ERROR
, _("Invalid source pattern `%s'"),
1001 g_free (source_mask
);
1005 g_free (def_text_secure
);
1006 g_free (source_mask
);
1008 ctx
->search_handle
->is_case_sentitive
= TRUE
;
1009 if (source_easy_patterns
)
1010 ctx
->search_handle
->search_type
= MC_SEARCH_T_GLOB
;
1012 ctx
->search_handle
->search_type
= MC_SEARCH_T_REGEX
;
1015 dest_dir
= tilde_expand (tmp
);
1018 ctx
->dest_mask
= strrchr (dest_dir
, PATH_SEP
);
1019 if (ctx
->dest_mask
== NULL
)
1020 ctx
->dest_mask
= dest_dir
;
1023 orig_mask
= ctx
->dest_mask
;
1024 if (!*ctx
->dest_mask
1025 || (!ctx
->dive_into_subdirs
&& !is_wildcarded (ctx
->dest_mask
)
1027 || (!mc_stat (dest_dir
, &buf
) && S_ISDIR (buf
.st_mode
))))
1028 || (ctx
->dive_into_subdirs
1029 && ((!only_one
&& !is_wildcarded (ctx
->dest_mask
))
1030 || (only_one
&& !mc_stat (dest_dir
, &buf
)
1031 && S_ISDIR (buf
.st_mode
)))))
1032 ctx
->dest_mask
= g_strdup ("\\0");
1034 ctx
->dest_mask
= g_strdup (ctx
->dest_mask
);
1039 dest_dir
= g_strdup ("./");