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(STAT_STATVFS) \
59 && (defined(HAVE_STRUCT_STATVFS_F_BASETYPE) \
60 || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME))
61 #include <sys/statvfs.h>
62 #define STRUCT_STATFS struct statvfs
63 #define STATFS statvfs
64 #elif defined(HAVE_STATFS) && !defined(STAT_STATFS4)
67 #elif defined(HAVE_SYS_MOUNT_H) && defined(HAVE_SYS_PARAM_H)
68 #include <sys/param.h>
69 #include <sys/mount.h>
70 #elif defined(HAVE_SYS_STATFS_H)
71 #include <sys/statfs.h>
73 #define STRUCT_STATFS struct statfs
79 #include "lib/global.h"
81 #include "lib/tty/key.h" /* tty_get_event */
82 #include "lib/mcconfig.h"
83 #include "lib/search.h"
84 #include "lib/vfs/mc-vfs/vfs.h"
85 #include "lib/strescape.h"
86 #include "lib/strutil.h"
87 #include "lib/timefmt.h" /* file_date() */
89 #include "lib/widget.h"
91 #include "src/setup.h" /* verbose */
94 #include "fileopctx.h" /* FILE_CONT */
100 /*** global variables ****************************************************************************/
102 int classic_progressbar
= 1;
104 /*** file scope macro definitions ****************************************************************/
106 /* Hack: the vfs code should not rely on this */
107 #define WITH_FULL_PATHS 1
109 /* File operate window sizes */
112 #define FCOPY_LABEL_X 3
114 #define truncFileString(ui, s) str_trunc (s, 52)
115 #define truncFileStringSecure(ui, s) path_trunc (s, 52)
117 /*** file scope type declarations ****************************************************************/
121 MSDOS_SUPER_MAGIC
= 0x4d44,
122 NTFS_SB_MAGIC
= 0x5346544e,
123 NTFS_3G_MAGIC
= 0x65735546,
124 PROC_SUPER_MAGIC
= 0x9fa0,
125 SMB_SUPER_MAGIC
= 0x517B,
126 NCP_SUPER_MAGIC
= 0x564c,
127 USBDEVICE_SUPER_MAGIC
= 0x9fa2
128 } filegui_nonattrs_fs_t
;
131 /* Used for button result values */
134 REPLACE_YES
= B_USER
,
145 /* This structure describes the UI and internal data required by a file
151 gboolean showing_eta
;
152 gboolean showing_bps
;
154 /* Dialog and widgets for the operation progress window */
156 WLabel
*file_string
[2];
157 WLabel
*file_label
[2];
158 WGauge
*progress_file_gauge
;
159 WLabel
*progress_file_label
;
161 WGauge
*progress_total_gauge
;
163 WLabel
*total_files_processed_label
;
165 WLabel
*total_bytes_label
;
167 /* Query replace dialog */
168 Dlg_head
*replace_dlg
;
169 const char *replace_filename
;
170 replace_action_t replace_result
;
172 struct stat
*s_stat
, *d_stat
;
175 /*** file scope variables ************************************************************************/
177 /* Used to save the hint line */
178 static int last_hint_line
;
180 /*** file scope functions ************************************************************************/
181 /* --------------------------------------------------------------------------------------------- */
184 filegui__check_attrs_on_fs (const char *fs_path
)
189 if (!setup_copymove_persistent_attr
)
192 if (STATFS (fs_path
, &stfs
) != 0)
196 switch ((filegui_nonattrs_fs_t
) stfs
.f_type
)
198 case MSDOS_SUPER_MAGIC
:
201 case PROC_SUPER_MAGIC
:
202 case SMB_SUPER_MAGIC
:
203 case NCP_SUPER_MAGIC
:
204 case USBDEVICE_SUPER_MAGIC
:
207 #elif defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) \
208 || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)
209 if (!strcmp (stfs
.f_fstypename
, "msdos")
210 || !strcmp (stfs
.f_fstypename
, "msdosfs")
211 || !strcmp (stfs
.f_fstypename
, "ntfs")
212 || !strcmp (stfs
.f_fstypename
, "procfs")
213 || !strcmp (stfs
.f_fstypename
, "smbfs") || strstr (stfs
.f_fstypename
, "fusefs"))
215 #elif defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
216 if (!strcmp (stfs
.f_basetype
, "pcfs")
217 || !strcmp (stfs
.f_basetype
, "ntfs")
218 || !strcmp (stfs
.f_basetype
, "proc")
219 || !strcmp (stfs
.f_basetype
, "smbfs") || !strcmp (stfs
.f_basetype
, "fuse"))
227 /* --------------------------------------------------------------------------------------------- */
230 file_frmt_time (char *buffer
, double eta_secs
)
232 int eta_hours
, eta_mins
, eta_s
;
233 eta_hours
= eta_secs
/ (60 * 60);
234 eta_mins
= (eta_secs
- (eta_hours
* 60 * 60)) / 60;
235 eta_s
= eta_secs
- (eta_hours
* 60 * 60 + eta_mins
* 60);
236 g_snprintf (buffer
, BUF_TINY
, _("%d:%02d.%02d"), eta_hours
, eta_mins
, eta_s
);
239 /* --------------------------------------------------------------------------------------------- */
242 file_eta_prepare_for_show (char *buffer
, double eta_secs
, gboolean always_show
)
244 char _fmt_buff
[BUF_TINY
];
245 if (eta_secs
<= 0.5 && !always_show
)
252 file_frmt_time (_fmt_buff
, eta_secs
);
253 g_snprintf (buffer
, BUF_TINY
, _("ETA %s"), _fmt_buff
);
256 /* --------------------------------------------------------------------------------------------- */
259 file_bps_prepare_for_show (char *buffer
, long bps
)
261 if (bps
> 1024 * 1024)
263 g_snprintf (buffer
, BUF_TINY
, _("%.2f MB/s"), bps
/ (1024 * 1024.0));
267 g_snprintf (buffer
, BUF_TINY
, _("%.2f KB/s"), bps
/ 1024.0);
271 g_snprintf (buffer
, BUF_TINY
, _("%ld B/s"), bps
);
277 /* --------------------------------------------------------------------------------------------- */
279 * FIXME: probably it is better to replace this with quick dialog machinery,
280 * but actually I'm not familiar with it and have not much time :(
283 static replace_action_t
284 overwrite_query_dialog (FileOpContext
* ctx
, enum OperationMode mode
)
286 #define ADD_RD_BUTTON(i) \
287 add_widget (ui->replace_dlg, \
288 button_new (rd_widgets [i].ypos, rd_widgets [i].xpos, rd_widgets [i].value, \
289 NORMAL_BUTTON, rd_widgets [i].text, 0))
291 #define ADD_RD_LABEL(i, p1, p2) \
292 g_snprintf (buffer, sizeof (buffer), rd_widgets [i].text, p1, p2); \
293 add_widget (ui->replace_dlg, label_new (rd_widgets [i].ypos, rd_widgets [i].xpos, buffer))
296 const int rd_ylen
= 17;
303 int value
; /* 0 for labels */
308 { N_("Target file already exists!"), 3, 4, 0 },
311 /* 2 */ /* cannot use PRIuMAX here; %llu is used instead */
312 { N_("Source date: %s, size %llu"), 6, 4, 0 },
313 /* 3 */ /* cannot use PRIuMAX here; %llu is used instead */
314 { N_("Target date: %s, size %llu"), 7, 4, 0 },
316 { N_("&Abort"), 14, 25, REPLACE_ABORT
},
318 { N_("If &size differs"), 12, 28, REPLACE_SIZE
},
320 { N_("Non&e"), 11, 47, REPLACE_NEVER
},
322 { N_("&Update"), 11, 36, REPLACE_UPDATE
},
324 { N_("A&ll"), 11, 28, REPLACE_ALWAYS
},
326 { N_("Overwrite all targets?"), 11, 4, 0 },
328 { N_("&Reget"), 10, 28, REPLACE_REGET
},
330 { N_("A&ppend"), 9, 45, REPLACE_APPEND
},
332 { N_("&No"), 9, 37, REPLACE_NO
},
334 { N_("&Yes"), 9, 28, REPLACE_YES
},
336 { N_("Overwrite this target?"), 9, 4, 0 }
340 const int num
= sizeof (rd_widgets
) / sizeof (rd_widgets
[0]);
343 FileOpContextUI
*ui
= ctx
->ui
;
345 char buffer
[BUF_SMALL
];
347 const char *stripped_name
= strip_home_and_password (ui
->replace_filename
);
348 int stripped_name_len
;
352 widgets_len
= g_new0 (int, num
);
354 if (mode
== Foreground
)
355 title
= _("File exists");
357 title
= _("Background process: File exists");
359 stripped_name_len
= str_term_width1 (stripped_name
);
362 int i
, l1
, l2
, l
, row
;
364 for (i
= 0; i
< num
; i
++)
367 if (i
!= 1) /* skip filename */
368 rd_widgets
[i
].text
= _(rd_widgets
[i
].text
);
369 #endif /* ENABLE_NLS */
370 widgets_len
[i
] = str_term_width1 (rd_widgets
[i
].text
);
374 * longest of "Overwrite..." labels
375 * (assume "Target date..." are short enough)
377 l1
= max (widgets_len
[9], widgets_len
[14]);
379 /* longest of button rows */
381 for (row
= l
= l2
= 0; i
--;)
382 if (rd_widgets
[i
].value
!= 0)
384 if (row
!= rd_widgets
[i
].ypos
)
386 row
= rd_widgets
[i
].ypos
;
390 l
+= widgets_len
[i
] + 4;
393 l2
= max (l2
, l
); /* last row */
394 rd_xlen
= max (rd_xlen
, l1
+ l2
+ 8);
395 rd_xlen
= max (rd_xlen
, str_term_width1 (title
) + 2);
396 rd_xlen
= max (rd_xlen
, min (COLS
, stripped_name_len
+ 8));
398 /* Now place widgets */
399 l1
+= 5; /* start of first button in the row */
401 for (l
= l1
, row
= 0; --i
> 1;)
402 if (rd_widgets
[i
].value
!= 0)
404 if (row
!= rd_widgets
[i
].ypos
)
406 row
= rd_widgets
[i
].ypos
;
409 rd_widgets
[i
].xpos
= l
;
410 l
+= widgets_len
[i
] + 4;
413 /* Abort button is centered */
414 rd_widgets
[4].xpos
= (rd_xlen
- widgets_len
[4] - 3) / 2;
417 /* FIXME - missing help node */
419 create_dlg (TRUE
, 0, 0, rd_ylen
, rd_xlen
, alarm_colors
, NULL
, "[Replace]",
420 title
, DLG_CENTER
| DLG_REVERSE
);
422 /* prompt -- centered */
423 add_widget (ui
->replace_dlg
,
424 label_new (rd_widgets
[0].ypos
, (rd_xlen
- widgets_len
[0]) / 2, rd_widgets
[0].text
));
425 /* file name -- centered */
426 stripped_name
= str_trunc (stripped_name
, rd_xlen
- 8);
427 stripped_name_len
= str_term_width1 (stripped_name
);
428 add_widget (ui
->replace_dlg
,
429 label_new (rd_widgets
[1].ypos
, (rd_xlen
- stripped_name_len
) / 2, stripped_name
));
431 /* source date and size */
432 ADD_RD_LABEL (2, file_date (ui
->s_stat
->st_mtime
), (unsigned long long) ui
->s_stat
->st_size
);
433 /* destination date and size */
434 ADD_RD_LABEL (3, file_date (ui
->d_stat
->st_mtime
), (unsigned long long) ui
->d_stat
->st_size
);
436 ADD_RD_BUTTON (4); /* Abort */
437 ADD_RD_BUTTON (5); /* If size differs */
438 ADD_RD_BUTTON (6); /* None */
439 ADD_RD_BUTTON (7); /* Update */
440 ADD_RD_BUTTON (8); /* All" */
441 ADD_RD_LABEL (9, 0, 0); /* Overwrite all targets? */
443 /* "this target..." widgets */
444 if (!S_ISDIR (ui
->d_stat
->st_mode
))
446 if ((ctx
->operation
== OP_COPY
) && (ui
->d_stat
->st_size
!= 0)
447 && (ui
->s_stat
->st_size
> ui
->d_stat
->st_size
))
448 ADD_RD_BUTTON (10); /* Reget */
450 ADD_RD_BUTTON (11); /* Append */
452 ADD_RD_BUTTON (12); /* No */
453 ADD_RD_BUTTON (13); /* Yes */
454 ADD_RD_LABEL (14, 0, 0); /* Overwrite this target? */
456 result
= run_dlg (ui
->replace_dlg
);
457 destroy_dlg (ui
->replace_dlg
);
459 g_free (widgets_len
);
461 return (result
== B_CANCEL
) ? REPLACE_ABORT
: (replace_action_t
) result
;
466 /* --------------------------------------------------------------------------------------------- */
469 is_wildcarded (char *p
)
475 if (*p
== '\\' && p
[1] >= '1' && p
[1] <= '9')
481 /* --------------------------------------------------------------------------------------------- */
482 /*** public functions ****************************************************************************/
483 /* --------------------------------------------------------------------------------------------- */
486 check_progress_buttons (FileOpContext
* ctx
)
492 g_return_val_if_fail (ctx
->ui
!= NULL
, FILE_CONT
);
496 event
.x
= -1; /* Don't show the GPM cursor */
497 c
= tty_get_event (&event
, FALSE
, FALSE
);
501 /* Reinitialize to avoid old values after events other than
502 selecting a button */
503 ui
->op_dlg
->ret_value
= FILE_CONT
;
505 dlg_process_event (ui
->op_dlg
, c
, &event
);
506 switch (ui
->op_dlg
->ret_value
)
519 /* --------------------------------------------------------------------------------------------- */
520 /* {{{ File progress display routines */
523 file_op_context_create_ui_without_init (FileOpContext
* ctx
, gboolean with_eta
,
524 filegui_dialog_type_t dialog_type
)
527 int minus
= 0, total_reserve
= 0;
528 const char *abort_button_label
= N_("&Abort");
529 const char *skip_button_label
= N_("&Skip");
530 int abort_button_width
, skip_button_width
, buttons_width
;
533 g_return_if_fail (ctx
!= NULL
);
534 g_return_if_fail (ctx
->ui
== NULL
);
537 abort_button_label
= _(abort_button_label
);
538 skip_button_label
= _(skip_button_label
);
541 abort_button_width
= str_term_width1 (abort_button_label
) + 3;
542 skip_button_width
= str_term_width1 (skip_button_label
) + 3;
543 buttons_width
= abort_button_width
+ skip_button_width
+ 2;
545 dlg_width
= max (WX
, buttons_width
+ 6);
547 ui
= g_new0 (FileOpContextUI
, 1);
550 ctx
->dialog_type
= dialog_type
;
554 case FILEGUI_DIALOG_ONE_ITEM
:
556 minus
= verbose
? 0 : 2;
558 case FILEGUI_DIALOG_MULTI_ITEM
:
560 minus
= verbose
? 0 : 7;
562 case FILEGUI_DIALOG_DELETE_ITEM
:
568 ctx
->recursive_result
= RECURSIVE_YES
;
570 ui
->replace_result
= REPLACE_YES
;
571 ui
->showing_eta
= with_eta
;
572 ui
->showing_bps
= with_eta
;
575 create_dlg (TRUE
, 0, 0, WY
- minus
+ 1 + total_reserve
, dlg_width
,
576 dialog_colors
, NULL
, NULL
, op_names
[ctx
->operation
], DLG_CENTER
| DLG_REVERSE
);
578 last_hint_line
= the_hint
->widget
.y
;
579 if ((ui
->op_dlg
->y
+ ui
->op_dlg
->lines
) > last_hint_line
)
580 the_hint
->widget
.y
= ui
->op_dlg
->y
+ ui
->op_dlg
->lines
+ 1;
582 add_widget (ui
->op_dlg
,
583 button_new (WY
- minus
- 2 + total_reserve
,
584 dlg_width
/ 2 + 1, FILE_ABORT
,
585 NORMAL_BUTTON
, abort_button_label
, NULL
));
586 add_widget (ui
->op_dlg
,
587 button_new (WY
- minus
- 2 + total_reserve
,
588 dlg_width
/ 2 - 1 - skip_button_width
, FILE_SKIP
,
589 NORMAL_BUTTON
, skip_button_label
, NULL
));
592 if (verbose
&& dialog_type
== FILEGUI_DIALOG_MULTI_ITEM
)
594 add_widget (ui
->op_dlg
, hline_new (8, 1, dlg_width
- 2));
596 add_widget (ui
->op_dlg
, ui
->total_bytes_label
= label_new (8, FCOPY_LABEL_X
+ 15, ""));
598 add_widget (ui
->op_dlg
, ui
->progress_total_gauge
=
599 gauge_new (9, FCOPY_LABEL_X
+ 3, 0, 100, 0));
601 add_widget (ui
->op_dlg
, ui
->total_files_processed_label
=
602 label_new (11, FCOPY_LABEL_X
, ""));
604 add_widget (ui
->op_dlg
, ui
->time_label
= label_new (12, FCOPY_LABEL_X
, ""));
607 add_widget (ui
->op_dlg
, ui
->progress_file_label
= label_new (7, FCOPY_LABEL_X
, ""));
609 add_widget (ui
->op_dlg
, ui
->progress_file_gauge
= gauge_new (6, FCOPY_LABEL_X
+ 3, 0, 100, 0));
611 add_widget (ui
->op_dlg
, ui
->file_string
[1] = label_new (5, FCOPY_LABEL_X
, ""));
613 add_widget (ui
->op_dlg
, ui
->file_label
[1] = label_new (4, FCOPY_LABEL_X
, ""));
614 add_widget (ui
->op_dlg
, ui
->file_string
[0] = label_new (3, FCOPY_LABEL_X
, ""));
615 add_widget (ui
->op_dlg
, ui
->file_label
[0] = label_new (2, FCOPY_LABEL_X
, ""));
617 if ((right_panel
== current_panel
) && !classic_progressbar
)
619 ui
->progress_file_gauge
->from_left_to_right
= FALSE
;
620 if (verbose
&& dialog_type
== FILEGUI_DIALOG_MULTI_ITEM
)
621 ui
->progress_total_gauge
->from_left_to_right
= FALSE
;
625 /* --------------------------------------------------------------------------------------------- */
628 file_op_context_create_ui (FileOpContext
* ctx
, gboolean with_eta
,
629 filegui_dialog_type_t dialog_type
)
633 g_return_if_fail (ctx
!= NULL
);
634 g_return_if_fail (ctx
->ui
== NULL
);
636 file_op_context_create_ui_without_init (ctx
, with_eta
, dialog_type
);
639 /* We will manage the dialog without any help, that's why
640 we have to call init_dlg */
641 init_dlg (ui
->op_dlg
);
644 /* --------------------------------------------------------------------------------------------- */
647 file_op_context_destroy_ui (FileOpContext
* ctx
)
649 g_return_if_fail (ctx
!= NULL
);
653 FileOpContextUI
*ui
= (FileOpContextUI
*) ctx
->ui
;
655 dlg_run_done (ui
->op_dlg
);
656 destroy_dlg (ui
->op_dlg
);
661 the_hint
->widget
.y
= last_hint_line
;
664 /* --------------------------------------------------------------------------------------------- */
666 show progressbar for file
670 file_progress_show (FileOpContext
* ctx
, off_t done
, off_t total
,
671 const char *stalled_msg
, gboolean force_update
)
674 char buffer
[BUF_TINY
];
675 char buffer2
[BUF_TINY
];
676 char buffer3
[BUF_TINY
];
681 g_return_if_fail (ctx
!= NULL
);
682 g_return_if_fail (ctx
->ui
!= NULL
);
688 gauge_show (ui
->progress_file_gauge
, 0);
692 gauge_set_value (ui
->progress_file_gauge
, 1024, (int) (1024 * done
/ total
));
693 gauge_show (ui
->progress_file_gauge
, 1);
698 if (ui
->showing_eta
&& ctx
->eta_secs
> 0.5)
700 file_eta_prepare_for_show (buffer2
, ctx
->eta_secs
, FALSE
);
701 file_bps_prepare_for_show (buffer3
, ctx
->bps
);
702 g_snprintf (buffer
, BUF_TINY
, "%s (%s) %s", buffer2
, buffer3
, stalled_msg
);
706 g_snprintf (buffer
, BUF_TINY
, "%s", stalled_msg
);
709 label_set_text (ui
->progress_file_label
, buffer
);
712 /* --------------------------------------------------------------------------------------------- */
715 file_progress_show_count (FileOpContext
* ctx
, size_t done
, size_t total
)
717 char buffer
[BUF_TINY
];
720 g_return_if_fail (ctx
!= NULL
);
721 g_return_if_fail (ctx
->ui
!= NULL
);
724 g_snprintf (buffer
, BUF_TINY
, _("Files processed: %zu of %zu"), done
, total
);
725 label_set_text (ui
->total_files_processed_label
, buffer
);
728 /* --------------------------------------------------------------------------------------------- */
731 file_progress_show_total (FileOpTotalContext
* tctx
, FileOpContext
* ctx
, uintmax_t copyed_bytes
,
732 gboolean show_summary
)
734 char buffer
[BUF_TINY
];
735 char buffer2
[BUF_TINY
];
736 char buffer3
[BUF_TINY
];
737 char buffer4
[BUF_TINY
];
738 struct timeval tv_current
;
741 g_return_if_fail (ctx
!= NULL
);
742 g_return_if_fail (ctx
->ui
!= NULL
);
746 if (ctx
->progress_bytes
!= 0)
748 gauge_set_value (ui
->progress_total_gauge
, 1024,
749 (int) (1024 * copyed_bytes
/ ctx
->progress_bytes
));
750 gauge_show (ui
->progress_total_gauge
, 1);
753 gauge_show (ui
->progress_total_gauge
, 0);
755 if (!show_summary
&& tctx
->bps
== 0)
758 gettimeofday (&tv_current
, NULL
);
759 file_frmt_time (buffer2
, tv_current
.tv_sec
- tctx
->transfer_start
.tv_sec
);
760 file_eta_prepare_for_show (buffer3
, tctx
->eta_secs
, TRUE
);
761 file_bps_prepare_for_show (buffer4
, (long) tctx
->bps
);
763 g_snprintf (buffer
, BUF_TINY
, _("Time: %s %s (%s)"), buffer2
, buffer3
, buffer4
);
764 label_set_text (ui
->time_label
, buffer
);
766 size_trunc_len (buffer2
, 5, tctx
->copyed_bytes
, 0, panels_options
.kilobyte_si
);
767 size_trunc_len (buffer3
, 5, ctx
->progress_bytes
, 0, panels_options
.kilobyte_si
);
769 g_snprintf (buffer
, BUF_TINY
, _("Total: %s of %s"), buffer2
, buffer3
);
771 label_set_text (ui
->total_bytes_label
, buffer
);
776 /* --------------------------------------------------------------------------------------------- */
779 file_progress_show_source (FileOpContext
* ctx
, const char *s
)
783 g_return_if_fail (ctx
!= NULL
);
784 g_return_if_fail (ctx
->ui
!= NULL
);
790 #ifdef WITH_FULL_PATHS
793 i
= strlen (current_panel
->cwd
);
795 /* We remove the full path we have added before */
796 if (strncmp (s
, current_panel
->cwd
, i
) == 0)
797 if (s
[i
] == PATH_SEP
)
799 #endif /* WITH_FULL_PATHS */
801 label_set_text (ui
->file_label
[0], _("Source"));
802 label_set_text (ui
->file_string
[0], truncFileString (ui
, s
));
806 label_set_text (ui
->file_label
[0], "");
807 label_set_text (ui
->file_string
[0], "");
811 /* --------------------------------------------------------------------------------------------- */
814 file_progress_show_target (FileOpContext
* ctx
, const char *s
)
818 g_return_if_fail (ctx
!= NULL
);
819 g_return_if_fail (ctx
->ui
!= NULL
);
825 label_set_text (ui
->file_label
[1], _("Target"));
826 label_set_text (ui
->file_string
[1], truncFileStringSecure (ui
, s
));
830 label_set_text (ui
->file_label
[1], "");
831 label_set_text (ui
->file_string
[1], "");
835 /* --------------------------------------------------------------------------------------------- */
838 file_progress_show_deleting (FileOpContext
* ctx
, const char *s
)
842 g_return_if_fail (ctx
!= NULL
);
843 g_return_if_fail (ctx
->ui
!= NULL
);
846 label_set_text (ui
->file_label
[0], _("Deleting"));
847 label_set_text (ui
->file_label
[0], truncFileStringSecure (ui
, s
));
850 /* --------------------------------------------------------------------------------------------- */
853 file_progress_real_query_replace (FileOpContext
* ctx
,
854 enum OperationMode mode
, const char *destname
,
855 struct stat
* _s_stat
, struct stat
* _d_stat
)
859 g_return_val_if_fail (ctx
!= NULL
, FILE_CONT
);
860 g_return_val_if_fail (ctx
->ui
!= NULL
, FILE_CONT
);
864 if (ui
->replace_result
< REPLACE_ALWAYS
)
866 ui
->replace_filename
= destname
;
867 ui
->s_stat
= _s_stat
;
868 ui
->d_stat
= _d_stat
;
869 ui
->replace_result
= overwrite_query_dialog (ctx
, mode
);
872 switch (ui
->replace_result
)
876 if (_s_stat
->st_mtime
> _d_stat
->st_mtime
)
883 if (_s_stat
->st_size
== _d_stat
->st_size
)
889 /* Careful: we fall through and set do_append */
890 ctx
->do_reget
= _d_stat
->st_size
;
893 ctx
->do_append
= TRUE
;
909 /* --------------------------------------------------------------------------------------------- */
912 file_mask_dialog (FileOpContext
* ctx
, FileOperation operation
,
914 const char *format
, const void *text
,
915 const char *def_text
, gboolean
* do_bg
)
917 const size_t FMDY
= 13;
918 const size_t FMDX
= 68;
922 const size_t gap
= 1;
923 size_t b0_len
, b2_len
;
926 int source_easy_patterns
= easy_patterns
;
928 char fmd_buf
[BUF_MEDIUM
];
929 char *source_mask
, *orig_mask
, *dest_dir
, *tmp
;
930 char *def_text_secure
;
933 QuickWidget fmd_widgets
[] = {
934 /* 0 */ QUICK_BUTTON (42, 64, 10, FMDY
, N_("&Cancel"), B_CANCEL
, NULL
),
935 #ifdef WITH_BACKGROUND
936 /* 1 */ QUICK_BUTTON (25, 64, 10, FMDY
, N_("&Background"), B_USER
, NULL
),
940 #endif /* WITH_BACKGROUND */
942 QUICK_BUTTON (14, FMDX
, 10, FMDY
, N_("&OK"), B_ENTER
, NULL
),
944 QUICK_CHECKBOX (42, FMDX
, 8, FMDY
, N_("&Stable Symlinks"), &ctx
->stable_symlinks
),
946 QUICK_CHECKBOX (31, FMDX
, 7, FMDY
, N_("Di&ve into subdir if exists"),
947 &ctx
->dive_into_subdirs
),
949 QUICK_CHECKBOX (3, FMDX
, 8, FMDY
, N_("Preserve &attributes"), &ctx
->op_preserve
),
951 QUICK_CHECKBOX (3, FMDX
, 7, FMDY
, N_("Follow &links"), &ctx
->follow_links
),
953 QUICK_INPUT (3, FMDX
, 6, FMDY
, "", 58, 0, "input2", &dest_dir
),
955 QUICK_LABEL (3, FMDX
, 5, FMDY
, N_("to:")),
957 QUICK_CHECKBOX (37, FMDX
, 4, FMDY
, N_("&Using shell patterns"), &source_easy_patterns
),
959 QUICK_INPUT (3, FMDX
, 3, FMDY
, easy_patterns
? "*" : "^(.*)$", 58, 0, "input-def",
962 QUICK_LABEL (3, FMDX
, 2, FMDY
, fmd_buf
),
966 g_return_val_if_fail (ctx
!= NULL
, NULL
);
970 for (i
= 0; i
<= 2 - OFFSET
; i
++)
971 fmd_widgets
[i
].u
.button
.text
= _(fmd_widgets
[i
].u
.button
.text
);
974 for (i
= 3 - OFFSET
; i
<= 9 - OFFSET
; i
++)
976 fmd_widgets
[i
].u
.checkbox
.text
= _(fmd_widgets
[i
].u
.checkbox
.text
);
977 #endif /* !ENABLE_NLS */
979 fmd_xlen
= max (FMDX
, (size_t) COLS
* 2 / 3);
981 len
= str_term_width1 (fmd_widgets
[6 - OFFSET
].u
.checkbox
.text
)
982 + str_term_width1 (fmd_widgets
[4 - OFFSET
].u
.checkbox
.text
) + 15;
983 fmd_xlen
= max (fmd_xlen
, len
);
985 len
= str_term_width1 (fmd_widgets
[5 - OFFSET
].u
.checkbox
.text
)
986 + str_term_width1 (fmd_widgets
[3 - OFFSET
].u
.checkbox
.text
) + 15;
987 fmd_xlen
= max (fmd_xlen
, len
);
990 b2_len
= str_term_width1 (fmd_widgets
[2 - OFFSET
].u
.button
.text
) + 6 + gap
; /* OK */
991 #ifdef WITH_BACKGROUND
992 b1_len
= str_term_width1 (fmd_widgets
[1].u
.button
.text
) + 4 + gap
; /* Background */
994 b0_len
= str_term_width1 (fmd_widgets
[0].u
.button
.text
) + 4; /* Cancel */
995 len
= b0_len
+ b1_len
+ b2_len
;
996 fmd_xlen
= min (max (fmd_xlen
, len
+ 6), (size_t) COLS
);
1002 flen
= str_term_width1 (format
);
1003 i
= fmd_xlen
- flen
- 4; /* FIXME */
1004 g_snprintf (fmd_buf
, sizeof (fmd_buf
), format
, str_trunc ((const char *) text
, i
));
1008 g_snprintf (fmd_buf
, sizeof (fmd_buf
), format
, *(const int *) text
);
1009 fmd_xlen
= max (fmd_xlen
, (size_t) str_term_width1 (fmd_buf
) + 6);
1012 for (i
= sizeof (fmd_widgets
) / sizeof (fmd_widgets
[0]); i
> 0;)
1013 fmd_widgets
[--i
].x_divisions
= fmd_xlen
;
1015 i
= (fmd_xlen
- len
) / 2;
1017 fmd_widgets
[2 - OFFSET
].relative_x
= i
;
1019 #ifdef WITH_BACKGROUND
1020 /* Background button */
1021 fmd_widgets
[1].relative_x
= i
;
1025 fmd_widgets
[0].relative_x
= i
;
1027 #define chkbox_xpos(i) \
1028 fmd_widgets [i].relative_x = fmd_xlen - str_term_width1 (fmd_widgets [i].u.checkbox.text) - 6
1029 chkbox_xpos (3 - OFFSET
);
1030 chkbox_xpos (4 - OFFSET
);
1031 chkbox_xpos (9 - OFFSET
);
1035 fmd_widgets
[7 - OFFSET
].u
.input
.len
= fmd_widgets
[10 - OFFSET
].u
.input
.len
= fmd_xlen
- 6;
1037 /* unselect checkbox if target filesystem don't support attributes */
1038 ctx
->op_preserve
= filegui__check_attrs_on_fs (def_text
);
1040 /* filter out a possible password from def_text */
1041 tmp
= strip_password (g_strdup (def_text
), 1);
1042 if (source_easy_patterns
)
1043 def_text_secure
= strutils_glob_escape (tmp
);
1045 def_text_secure
= strutils_regex_escape (tmp
);
1049 fmd_widgets
[7 - OFFSET
].u
.input
.text
= def_text_secure
;
1051 ctx
->stable_symlinks
= FALSE
;
1057 QuickDialog Quick_input
= {
1058 fmd_xlen
, FMDY
, -1, -1, op_names
[operation
],
1059 "[Mask Copy/Rename]", fmd_widgets
, NULL
, TRUE
1063 val
= quick_dialog_skip (&Quick_input
, 4);
1065 if (val
== B_CANCEL
)
1067 g_free (def_text_secure
);
1071 if (ctx
->follow_links
)
1072 ctx
->stat_func
= mc_stat
;
1074 ctx
->stat_func
= mc_lstat
;
1076 if (ctx
->op_preserve
)
1078 ctx
->preserve
= TRUE
;
1079 ctx
->umask_kill
= 0777777;
1080 ctx
->preserve_uidgid
= (geteuid () == 0);
1085 ctx
->preserve
= ctx
->preserve_uidgid
= FALSE
;
1088 ctx
->umask_kill
= i2
^ 0777777;
1091 if ((dest_dir
== NULL
) || (*dest_dir
== '\0'))
1093 g_free (def_text_secure
);
1094 g_free (source_mask
);
1098 ctx
->search_handle
= mc_search_new (source_mask
, -1);
1100 if (ctx
->search_handle
== NULL
)
1102 message (D_ERROR
, MSG_ERROR
, _("Invalid source pattern `%s'"), source_mask
);
1104 g_free (source_mask
);
1108 g_free (def_text_secure
);
1109 g_free (source_mask
);
1111 ctx
->search_handle
->is_case_sensitive
= TRUE
;
1112 if (source_easy_patterns
)
1113 ctx
->search_handle
->search_type
= MC_SEARCH_T_GLOB
;
1115 ctx
->search_handle
->search_type
= MC_SEARCH_T_REGEX
;
1118 dest_dir
= tilde_expand (tmp
);
1121 ctx
->dest_mask
= strrchr (dest_dir
, PATH_SEP
);
1122 if (ctx
->dest_mask
== NULL
)
1123 ctx
->dest_mask
= dest_dir
;
1126 orig_mask
= ctx
->dest_mask
;
1127 if (!*ctx
->dest_mask
1128 || (!ctx
->dive_into_subdirs
&& !is_wildcarded (ctx
->dest_mask
)
1130 || (!mc_stat (dest_dir
, &buf
) && S_ISDIR (buf
.st_mode
))))
1131 || (ctx
->dive_into_subdirs
1132 && ((!only_one
&& !is_wildcarded (ctx
->dest_mask
))
1133 || (only_one
&& !mc_stat (dest_dir
, &buf
) && S_ISDIR (buf
.st_mode
)))))
1134 ctx
->dest_mask
= g_strdup ("\\0");
1137 ctx
->dest_mask
= g_strdup (ctx
->dest_mask
);
1143 dest_dir
= g_strdup ("./");
1152 /* --------------------------------------------------------------------------------------------- */