941 lines
27 KiB
C
941 lines
27 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $TOG: main_dtcopy.c /main/10 1998/10/26 12:42:41 mgreess $ */
|
|
/************************************<+>*************************************
|
|
****************************************************************************
|
|
*
|
|
* FILE: main_dtcopy.c
|
|
*
|
|
* COMPONENT_NAME: dtcopy - Handles move/copy/link operations for 'dtfile'
|
|
*
|
|
* DESCRIPTION: Main program for dtfile_copy.
|
|
*
|
|
*
|
|
* FUNCTIONS: AppendErrorMsg
|
|
* CheckForMap
|
|
* ConfirmHandler
|
|
* ErrorHandler
|
|
* EventCheck
|
|
* InitNlsMessage
|
|
* TimeoutHandler
|
|
* UpdateErrorCount
|
|
* UpdateStatus
|
|
* UpdateSummary
|
|
* get_command_line
|
|
* main
|
|
* moveDeleteCallback
|
|
* moveErrorCallback
|
|
*
|
|
* (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
|
|
* (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
|
|
* (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
|
|
* (c) Copyright 1993, 1994, 1995 Novell, Inc.
|
|
*
|
|
****************************************************************************
|
|
************************************<+>*************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <locale.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <Xm/Xm.h>
|
|
|
|
/* #Include <X11/Xmu/Editres.h> */ /* for editres debugging tool */
|
|
|
|
#include <Dt/Connect.h>
|
|
#include <Dt/DtNlUtils.h>
|
|
#include <Dt/EnvControlP.h>
|
|
|
|
#include "fsrtns.h"
|
|
#include "dosync.h"
|
|
#include "dtcopy.h"
|
|
#include "sharedFuncs.h"
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* Global Variables
|
|
*------------------------------------------------------------------*/
|
|
|
|
extern Widget G_toplevel;
|
|
Widget G_summary_text;
|
|
Widget G_status_text;
|
|
/* Widget G_status_text2; */
|
|
Widget G_error_count;
|
|
Widget G_error_msgs;
|
|
Widget G_copy_dialog;
|
|
Widget G_error_dialog = NULL;
|
|
Widget G_over_dialog = NULL;
|
|
Widget G_over_confirm;
|
|
Widget G_copy_action_area_pbuttons[4];
|
|
Widget G_help_dialog;
|
|
Widget G_overwrite_radio;
|
|
Widget G_rename_text;
|
|
Widget G_toggle_main;
|
|
Widget G_toggle_error;
|
|
|
|
int G_overwrite_selection = G_OVERWRITE_EXISTING;
|
|
int G_move = FALSE;
|
|
int G_do_copy = TRUE;
|
|
int G_pause_copy = FALSE;
|
|
int G_user_pause_copy = FALSE;
|
|
int G_wait_on_error = TRUE;
|
|
int G_error_status = 0;
|
|
int G_ignore_errors = FALSE;
|
|
int G_overwrite_confirm = TRUE;
|
|
int G_wait_on_input = TRUE;
|
|
extern int G_dialog_closed;
|
|
|
|
char G_rename_oldname[MAX_PATH];
|
|
char G_source_dir[MAX_PATH];
|
|
|
|
/* debugging flag */
|
|
#ifdef DEBUG
|
|
int debug = 0;
|
|
#endif
|
|
|
|
static XtAppContext app_context;
|
|
static Display *display;
|
|
static Boolean is_mapped = False;
|
|
static int nfiles = 0;
|
|
static int ndirs = 0;
|
|
static int nerr = 0;
|
|
static char last_dir[MAX_PATH];
|
|
|
|
#define FILEOPNUM 14
|
|
static char *LongFileOpNames[FILEOPNUM];
|
|
static char *DefaultLongFileOpNames[] = {
|
|
"processing",
|
|
"opening",
|
|
"opening",
|
|
"opening",
|
|
"reading link",
|
|
"deleting",
|
|
"copying",
|
|
"creating directory",
|
|
"copying link",
|
|
"creating link",
|
|
"working",
|
|
"is a copy",
|
|
"is a link",
|
|
"renaming"
|
|
};
|
|
|
|
/*--------------------------------------------------------------------
|
|
* application resource definitions
|
|
*------------------------------------------------------------------*/
|
|
|
|
typedef struct
|
|
{
|
|
char *source_name;
|
|
char *target_name;
|
|
SyncParams sync;
|
|
Boolean move;
|
|
Boolean confirmreplace;
|
|
Boolean confirmerrors;
|
|
Boolean popdown;
|
|
int delay;
|
|
Boolean use_toggle_buttons;
|
|
Boolean slow;
|
|
Boolean checkPerms;
|
|
} AppArgs, *AppArgsPtr;
|
|
|
|
static AppArgs app_args;
|
|
|
|
static XtResource resources[] =
|
|
{
|
|
/* source and target directories */
|
|
|
|
{ "source", "Source", XmRString, sizeof (char *),
|
|
XtOffset (AppArgsPtr, source_name), XmRImmediate, (XtPointer) NULL, },
|
|
|
|
{ "target", "Target", XmRString, sizeof (char *),
|
|
XtOffset (AppArgsPtr, target_name), XmRImmediate, (XtPointer) NULL, },
|
|
|
|
/* SyncParams */
|
|
|
|
{ "verbose", "Verbose", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.verbose), XmRImmediate, (XtPointer) True, },
|
|
|
|
{ "quiet", "Quiet", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.quiet), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "dontDoIt", "DontDoIt", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.dontdoit), XmRImmediate, (XtPointer) False, },
|
|
|
|
|
|
{ "keepNew", "KeepNew", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.keepnew), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "keepOld", "KeepOld", XmRString, sizeof (char *),
|
|
XtOffset (AppArgsPtr, sync.keepold), XmRImmediate, (XtPointer) NULL, },
|
|
|
|
{ "dontDelete", "DontDelete", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.dontdelete), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "dontAdd", "DontAdd", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.dontadd), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "dontReplace", "DontReplace", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.dontreplace),
|
|
XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "dontRecur", "DontRecur", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.dontrecur), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "keepLinks", "KeepLinks", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.keeplinks), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "keepCopies", "KeepCopies", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.keepcopies), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "forceCopies", "ForceCopies", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.forcecopies), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "listLinks", "ListLinks", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.listlinks), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "listCopies", "ListCopies", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.listcopies), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "linkFolders", "LinkFolders", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.linkdirs), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "linkFiles", "LinkFiles", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.linkfiles), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "copyFolders", "CopyFolders", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.copydirs), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "copyFiles", "CopyFiles", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.copyfiles), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "copyTop", "CopyTop", XmRBool, sizeof (int),
|
|
XtOffset (AppArgsPtr, sync.copytop), XmRImmediate, (XtPointer) False, },
|
|
|
|
/* other options */
|
|
|
|
{ "move", "Move", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, move), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "confirmReplace", "ConfirmReplace", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, confirmreplace), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "confirmErrors", "ConfirmErrors", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, confirmerrors), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "popDown", "PopDown", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, popdown), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "delay", "Delay", XmRInt, sizeof (int),
|
|
XtOffset (AppArgsPtr, delay), XmRImmediate, (XtPointer) 5000, }, /* in milliseconds */
|
|
|
|
{ "toggle", "Toggle", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, use_toggle_buttons), XmRImmediate, (XtPointer) True, },
|
|
{ "slow", "Slow", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, slow), XmRImmediate, (XtPointer) False, },
|
|
|
|
{ "checkPermissions", "CheckPermissions", XmRBoolean, sizeof (Boolean),
|
|
XtOffset (AppArgsPtr, checkPerms), XmRImmediate, (XtPointer) False, },
|
|
};
|
|
|
|
|
|
static XrmOptionDescRec option_list[] =
|
|
{
|
|
{ "-from", "source", XrmoptionSepArg, NULL },
|
|
{ "-to", "target", XrmoptionSepArg, NULL },
|
|
|
|
{ "-verbose", "verbose", XrmoptionNoArg, "True" },
|
|
{ "-v", "verbose", XrmoptionNoArg, "True" },
|
|
{ "-quiet", "quiet", XrmoptionNoArg, "True" },
|
|
{ "-q", "quiet", XrmoptionNoArg, "True" },
|
|
{ "-dontDoIt", "dontDoIt", XrmoptionNoArg, "True" },
|
|
{ "-n", "dontDoIt", XrmoptionNoArg, "True" },
|
|
|
|
{ "-keepNew", "keepNew", XrmoptionNoArg, "True" },
|
|
{ "-kn", "keepNew", XrmoptionNoArg, "True" },
|
|
{ "-keepOld", "keepOld", XrmoptionSepArg, NULL },
|
|
{ "-ko", "keepOld", XrmoptionSepArg, NULL },
|
|
{ "-dontDelete", "dontDelete", XrmoptionNoArg, "True" },
|
|
{ "-nd", "dontDelete", XrmoptionNoArg, "True" },
|
|
{ "-dontAdd", "dontAdd", XrmoptionNoArg, "True" },
|
|
{ "-na", "dontAdd", XrmoptionNoArg, "True" },
|
|
{ "-dontReplace", "dontReplace", XrmoptionNoArg, "True" },
|
|
{ "-nr", "dontReplace", XrmoptionNoArg, "True" },
|
|
{ "-dontRecur", "dontRecur", XrmoptionNoArg, "True" },
|
|
{ "-nR", "dontRecur", XrmoptionNoArg, "True" },
|
|
|
|
{ "-keepLinks", "keepLinks", XrmoptionNoArg, "True" },
|
|
{ "-kl", "keepLinks", XrmoptionNoArg, "True" },
|
|
{ "-keepCopies", "keepCopies", XrmoptionNoArg, "True" },
|
|
{ "-kc", "keepCopies", XrmoptionNoArg, "True" },
|
|
{ "-forceCopies", "forceCopies", XrmoptionNoArg, "True" },
|
|
{ "-fc", "forceCopies", XrmoptionNoArg, "True" },
|
|
{ "-listLinks", "listLinks", XrmoptionNoArg, "True" },
|
|
{ "-ll", "listLinks", XrmoptionNoArg, "True" },
|
|
{ "-listCopies", "listCopies", XrmoptionNoArg, "True" },
|
|
{ "-lc", "listCopies", XrmoptionNoArg, "True" },
|
|
{ "-linkFolders", "linkFolders", XrmoptionNoArg, "True" },
|
|
{ "-ld", "linkFolders", XrmoptionNoArg, "True" },
|
|
{ "-linkFiles", "linkFiles", XrmoptionNoArg, "True" },
|
|
{ "-lf", "linkFiles", XrmoptionNoArg, "True" },
|
|
{ "-copyFolders", "copyFolders", XrmoptionNoArg, "True" },
|
|
{ "-cd", "copyFolders", XrmoptionNoArg, "True" },
|
|
{ "-copyFiles", "copyFiles", XrmoptionNoArg, "True" },
|
|
{ "-cf", "copyFiles", XrmoptionNoArg, "True" },
|
|
{ "-copyTop", "copyTop", XrmoptionNoArg, "True" },
|
|
{ "-ct", "copyTop", XrmoptionNoArg, "True" },
|
|
|
|
{ "-move", "move", XrmoptionNoArg, "True" },
|
|
{ "-mv", "move", XrmoptionNoArg, "True" },
|
|
{ "-confirmReplace", "confirmReplace", XrmoptionNoArg, "True" },
|
|
{ "-cr", "confirmReplace", XrmoptionNoArg, "True" },
|
|
{ "-confirmErrors", "confirmErrors", XrmoptionNoArg, "True" },
|
|
{ "-ce", "confirmErrors", XrmoptionNoArg, "True" },
|
|
{ "-popDown", "popDown", XrmoptionNoArg, "True" },
|
|
{ "-delay", "delay", XrmoptionSepArg, NULL },
|
|
{ "-slow", "slow", XrmoptionNoArg, "True" },
|
|
{ "-toggle", "toggle", XrmoptionNoArg, "True" },
|
|
{ "-notoggle", "toggle", XrmoptionNoArg, "False" },
|
|
{ "-checkPerms", "checkPermissions",XrmoptionNoArg, "True" },
|
|
};
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* display update functions
|
|
*------------------------------------------------------------------*/
|
|
|
|
static void
|
|
UpdateSummary(void)
|
|
{
|
|
XmString xs;
|
|
char msg[1024];
|
|
char files[128];
|
|
char dirs[128];
|
|
int new_nfiles = nfiles, new_ndirs = ndirs;
|
|
|
|
if (nfiles == 1)
|
|
strcpy(files, GETMESSAGE(2, 3, "file"));
|
|
else
|
|
strcpy(files, GETMESSAGE(2, 4, "files"));
|
|
|
|
if (ndirs == 1)
|
|
strcpy(dirs, GETMESSAGE(2, 5, "subfolder"));
|
|
else
|
|
strcpy(dirs, GETMESSAGE(2, 6, "subfolders"));
|
|
|
|
if ( nfiles < 0 )
|
|
new_nfiles = 0;
|
|
if ( ndirs < 0 )
|
|
new_ndirs = 0;
|
|
sprintf(msg, "%4d %s\n%4d %s", new_nfiles, files, new_ndirs, dirs);
|
|
|
|
xs = XmStringCreateLocalized(msg);
|
|
XtVaSetValues (G_summary_text,
|
|
XmNlabelString, xs,
|
|
NULL);
|
|
XmStringFree(xs);
|
|
}
|
|
|
|
|
|
static void
|
|
UpdateStatus(
|
|
char *msg1,
|
|
char *msg2)
|
|
{
|
|
|
|
String msg;
|
|
String pad;
|
|
const String ellipsis="...";
|
|
const int lenEllipsis = 3;
|
|
int lenSourceDir, lenMsg, lenMsg2, numBlanks;
|
|
static int maxMsg = -1;
|
|
|
|
DPRINTF(("%s %s\n",msg1,msg2));
|
|
/*
|
|
XtUnmanageChild(G_status_text2);
|
|
|
|
XtVaSetValues (G_status_text,
|
|
XmNvalue, msg1,
|
|
XmNcursorPosition, 0,
|
|
NULL);
|
|
|
|
XtVaSetValues (G_status_text2,
|
|
XmNvalue, msg2,
|
|
NULL);
|
|
|
|
XtManageChild(G_status_text2);
|
|
|
|
XtVaSetValues (G_status_text2,
|
|
XmNcursorPosition, strlen(msg2),
|
|
NULL);
|
|
*/
|
|
|
|
/* The pathname is truncated, if possible, by replacing */
|
|
/* the name of the source directory with "...". Thus, */
|
|
/* when copying /u/joeuser/mydir/myfile, the pathanme */
|
|
/* is written as .../myfile */
|
|
|
|
lenSourceDir = strlen(G_source_dir);
|
|
lenMsg2 = strlen(msg2);
|
|
if ( (strncmp(G_source_dir,msg2,lenSourceDir) == 0) &&
|
|
(lenMsg2 > lenSourceDir) )
|
|
{
|
|
msg = XtMalloc(strlen(msg1) + lenEllipsis + (lenMsg2 - lenSourceDir) + 2);
|
|
sprintf(msg, "%s %s%s", msg1, ellipsis, msg2+lenSourceDir);
|
|
}
|
|
else
|
|
{
|
|
msg = XtMalloc(strlen(msg1) + lenMsg2 + 2);
|
|
sprintf(msg, "%s %s", msg1, msg2);
|
|
}
|
|
|
|
/* In order to minimize re-sizing of the dialog, the */
|
|
/* length of the message is not allowed to decrease. */
|
|
/* Blanks are added to the end of shorter messages. */
|
|
|
|
lenMsg = strlen(msg);
|
|
maxMsg = (maxMsg > lenMsg) ? maxMsg : lenMsg; /* MAX(maxMsg,lenMsg) */
|
|
if (lenMsg < maxMsg)
|
|
{
|
|
numBlanks = maxMsg - lenMsg;
|
|
pad = XtMalloc(numBlanks+1);
|
|
memset(pad,' ',numBlanks);
|
|
pad[numBlanks] = '\0';
|
|
msg = XtRealloc(msg,maxMsg+1);
|
|
strcat(msg,pad);
|
|
XtFree(pad);
|
|
}
|
|
|
|
|
|
XmTextFieldSetString(G_status_text, msg);
|
|
|
|
XtFree(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
UpdateErrorCount(void)
|
|
{
|
|
char msg[128];
|
|
|
|
if (nerr == 0)
|
|
strcpy(msg, GETMESSAGE(2, 7, "Errors: none"));
|
|
else
|
|
sprintf(msg, GETMESSAGE(2, 8, "Errors: %d"), nerr);
|
|
|
|
/* for the first error, manage the widgets used to display errors */
|
|
if (nerr == 1)
|
|
{
|
|
XtVaSetValues(G_status_text,
|
|
XmNbottomAttachment, XmATTACH_NONE,
|
|
NULL);
|
|
/*
|
|
XtVaSetValues(G_status_text2,
|
|
XmNbottomAttachment, XmATTACH_NONE,
|
|
NULL);
|
|
*/
|
|
XtManageChild(G_error_count);
|
|
XtManageChild(G_error_msgs);
|
|
XtManageChild(XtParent(G_error_msgs));
|
|
}
|
|
|
|
XtVaSetValues (G_error_count,
|
|
XmNvalue, msg,
|
|
XmNcursorPosition, 0,
|
|
NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
AppendErrorMsg(char *msg)
|
|
{
|
|
XmTextPosition pos;
|
|
|
|
pos = XmTextGetLastPosition (G_error_msgs);
|
|
XmTextInsert (G_error_msgs, pos, msg);
|
|
XmTextSetInsertionPosition (G_error_msgs, pos);
|
|
XmTextShowPosition (G_error_msgs, pos);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* Callback functions
|
|
*------------------------------------------------------------------*/
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
CheckForMap(
|
|
Widget w,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont)
|
|
/* set a flag when the main window is mapped */
|
|
{
|
|
if (event->type == MapNotify)
|
|
is_mapped = True;
|
|
}
|
|
|
|
|
|
static int
|
|
EventCheck(void)
|
|
/* process X events until there are no more pending events queued */
|
|
{
|
|
XEvent event;
|
|
unsigned long pend_result;
|
|
|
|
for (;;) {
|
|
if (!G_pause_copy) {
|
|
/* check if there are any X events */
|
|
if (!(XtAppPending(app_context) & XtIMXEvent)) {
|
|
/* maybe more events are "in the pipe" */
|
|
XSync(XtDisplay(G_toplevel), False);
|
|
if (!(XtAppPending(app_context) & XtIMXEvent))
|
|
break;
|
|
}
|
|
}
|
|
/* get the next event and process it */
|
|
XtAppNextEvent(app_context, &event);
|
|
XtDispatchEvent(&event);
|
|
}
|
|
|
|
/* if the user clicked on the Cancel button and Warning 'yes' btn, abort the copy */
|
|
if (G_do_copy)
|
|
return 0;
|
|
else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
ErrorHandler(FileOp op, char *fname, int errnum)
|
|
{
|
|
char msg[2048];
|
|
|
|
/* increment the error count */
|
|
nerr++;
|
|
UpdateErrorCount();
|
|
|
|
/* don't count this file as one that has been copied */
|
|
nfiles--;
|
|
UpdateSummary();
|
|
|
|
/* add error message to error_msgs */
|
|
sprintf(msg, "%s: %s\n", fname, strerror(errnum));
|
|
AppendErrorMsg(msg);
|
|
|
|
XmUpdateDisplay(G_toplevel);
|
|
|
|
/* Initialize the error status variable. It will be set if the user */
|
|
/* has chosen not to ignore errors */
|
|
G_error_status = 0;
|
|
|
|
if (!G_ignore_errors)
|
|
{
|
|
create_error_dialog(G_toplevel, LongFileOpNames[op], fname, errnum);
|
|
|
|
G_wait_on_input = TRUE;
|
|
while (G_wait_on_input)
|
|
EventCheck();
|
|
}
|
|
|
|
return (G_error_status);
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
ConfirmHandler(
|
|
FileOp op,
|
|
char *sname,
|
|
int stype,
|
|
char *tname,
|
|
int ttype,
|
|
char *link)
|
|
{
|
|
char msg[1024];
|
|
Arg args[5];
|
|
Boolean is_overwrite = False;
|
|
Boolean overwrite_dialog = False; /* was overwrite dialog invoked? */
|
|
char *fname;
|
|
int rc = 0;
|
|
SyncParams sync;
|
|
|
|
/* update copy counts */
|
|
if (op == op_sync)
|
|
{
|
|
ndirs++;
|
|
strcpy(last_dir, sname);
|
|
UpdateSummary();
|
|
}
|
|
else if (op == op_copy || op == op_cplink || op == op_mklink)
|
|
{
|
|
if (ttype != ft_noent)
|
|
is_overwrite = True;
|
|
if (!is_overwrite)
|
|
{
|
|
nfiles++;
|
|
UpdateSummary();
|
|
}
|
|
}
|
|
|
|
/* display a message that tells the user what we are working on */
|
|
if (op == op_delete || op == op_mkdir)
|
|
UpdateStatus(LongFileOpNames[op], tname);
|
|
else
|
|
UpdateStatus(LongFileOpNames[op], sname);
|
|
|
|
XmUpdateDisplay(G_toplevel);
|
|
|
|
|
|
if (is_overwrite) {
|
|
|
|
/* target already exists and would be replaced */
|
|
|
|
/* if confirmation is turned on, ask the user */
|
|
/* set overwrite_dialog so we know if the user was prompted for this file */
|
|
/* Otherwise, G_overwrite_selection is either the default or was set */
|
|
/* by the user in a prior invocation of the overwrite dialog */
|
|
if (G_overwrite_confirm)
|
|
{
|
|
overwrite_dialog = TRUE;
|
|
create_overwrite_dialog (G_toplevel, sname, tname, ttype & ft_isdir);
|
|
|
|
G_wait_on_input = TRUE;
|
|
while (G_wait_on_input)
|
|
EventCheck();
|
|
|
|
}
|
|
|
|
if (G_overwrite_selection != G_SKIP)
|
|
{
|
|
nfiles++;
|
|
UpdateSummary();
|
|
XmUpdateDisplay(G_toplevel);
|
|
}
|
|
|
|
switch (G_overwrite_selection)
|
|
{
|
|
case G_OVERWRITE_EXISTING:
|
|
rc = 0;
|
|
break;
|
|
|
|
case G_RENAME_EXISTING: /* i.e. move clashing target */
|
|
if (!overwrite_dialog)
|
|
{
|
|
if (auto_rename(tname) == 0)
|
|
{
|
|
touch(tname); /* SyncDirectory complains if the file is gone */
|
|
rc = 0;
|
|
}
|
|
else
|
|
{
|
|
ErrorHandler(op_rename, tname, errno);
|
|
rc = 1; /* do not do the copy */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = 0;
|
|
}
|
|
break;
|
|
|
|
case G_SKIP:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (app_args.slow) {
|
|
XFlush(XtDisplay(G_toplevel));
|
|
XSync(XtDisplay(G_toplevel), False);
|
|
sleep(1);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
/*
|
|
* moveDeleteCallback, moveErrorCallback:
|
|
* called if "-move" option was given, when the
|
|
* source directory is deleted after a successful copy.
|
|
*/
|
|
|
|
static int
|
|
moveDeleteCallback(char *fname)
|
|
{
|
|
return ConfirmHandler(op_delete, "", ft_noent, fname, 0, "");
|
|
}
|
|
|
|
|
|
static int
|
|
moveErrorCallback(char *fname, int errnum)
|
|
{
|
|
return ErrorHandler(op_delete, fname, errnum);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* Get command line arguments
|
|
*------------------------------------------------------------------*/
|
|
|
|
static int
|
|
get_command_line(int argc, char *argv[])
|
|
{
|
|
int i = 1;
|
|
|
|
#define USAGE \
|
|
"Usage: %s [options ...] source target\n"
|
|
|
|
/* get source & target directory, if not yet set */
|
|
|
|
if (app_args.source_name == NULL && i < argc)
|
|
app_args.source_name = argv[i++];
|
|
|
|
if (app_args.target_name == NULL && i < argc)
|
|
app_args.target_name = argv[i++];
|
|
|
|
/*
|
|
* There should be no more arguments left, and
|
|
* source & target directory should be set
|
|
*/
|
|
|
|
if (i < argc ||
|
|
app_args.source_name == NULL ||
|
|
app_args.target_name == NULL)
|
|
{
|
|
fprintf(stderr, GETMESSAGE(2, 10, USAGE), argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* Initialize LongFileOpNames by message catalog.
|
|
*------------------------------------------------------------------*/
|
|
|
|
static void
|
|
InitNlsMessage(void)
|
|
{
|
|
int i;
|
|
char *msg;
|
|
|
|
for (i = 0; i < FILEOPNUM; i++) {
|
|
msg = GETMESSAGE(2, i + 20, DefaultLongFileOpNames[i]);
|
|
LongFileOpNames[i] = XtNewString(msg);
|
|
}
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
* Main
|
|
*------------------------------------------------------------------*/
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
char msg[1024];
|
|
XEvent event;
|
|
Arg args[3];
|
|
int rc, n,perm_status=0;
|
|
char * tmpStr;
|
|
|
|
Boolean copy_status;
|
|
|
|
_DtEnvControl(DT_ENV_SET);
|
|
XtSetLanguageProc(NULL, NULL, NULL);
|
|
|
|
/* initialize debugging flag */
|
|
#ifdef DEBUG
|
|
if ((tmpStr = getenv("DTFILE_DEBUG")) != NULL)
|
|
{
|
|
debug = atoi(tmpStr);
|
|
if (debug <= 0)
|
|
debug = 1;
|
|
}
|
|
#endif
|
|
|
|
/* Initialize the toolkit and Open the Display */
|
|
n=0;
|
|
XtSetArg (args[n], XmNmappedWhenManaged, FALSE); n++;
|
|
|
|
G_toplevel = XtAppInitialize(&app_context,
|
|
"Dtfile", /* Dtcopy is considered part of Dtfile */
|
|
option_list, XtNumber(option_list),
|
|
&argc, argv, NULL, args, n);
|
|
|
|
InitNlsMessage();
|
|
|
|
XtGetApplicationResources(G_toplevel, &app_args,
|
|
resources, XtNumber(resources), NULL, 0);
|
|
|
|
/* add support for editres debugging tool */
|
|
/* XtAddEventHandler(G_toplevel, (EventMask) 0, True, _XEditResCheckMessages, NULL); */
|
|
|
|
/* Get the source and destination directories */
|
|
get_command_line(argc,argv);
|
|
CheckDeleteAccess(app_context,app_args.delay,app_args.checkPerms,
|
|
app_args.move,app_args.source_name);
|
|
G_ignore_errors = !app_args.confirmerrors;
|
|
G_overwrite_confirm = app_args.confirmreplace;
|
|
G_move = app_args.move;
|
|
|
|
/* Set resources for the shell */
|
|
n = 0;
|
|
XtSetArg(args[n], XmNallowShellResize, TRUE); n++;
|
|
if (G_move)
|
|
{
|
|
XtSetArg(args[n], XmNtitle, GETMESSAGE(2, 11, "File Manager - Folder Move"));
|
|
n++;
|
|
}
|
|
else
|
|
{
|
|
XtSetArg(args[n], XmNtitle, GETMESSAGE(2, 12, "File Manager - Folder Copy"));
|
|
n++;
|
|
}
|
|
|
|
XtSetValues(G_toplevel, args, n);
|
|
|
|
/* Initialize images for error, warning, ... icons */
|
|
ImageInitialize(XtDisplay(G_toplevel));
|
|
|
|
/* Create The Copy Directory Dialog */
|
|
copy_status = create_copydir_dialog(G_toplevel, app_args.source_name,
|
|
app_args.target_name);
|
|
|
|
if(copy_status == False)
|
|
{
|
|
XtRealizeWidget(G_toplevel);
|
|
XtAppAddTimeOut(app_context, app_args.delay, TimeoutHandler, NULL);
|
|
|
|
/* wait for user to close the dialog before exiting */
|
|
while (!G_dialog_closed)
|
|
{
|
|
XtAppNextEvent(app_context, &event);
|
|
XtDispatchEvent(&event);
|
|
}
|
|
exit (-1);
|
|
}
|
|
|
|
/* initialize status, error count, etc ... */
|
|
sensitize_copy_action_area(G_copy_action_area_pbuttons);
|
|
nfiles = 0;
|
|
ndirs = -1; /* -1 so the source folder does not get counted, only subfolders */
|
|
UpdateSummary();
|
|
nerr = 0;
|
|
UpdateErrorCount();
|
|
|
|
/* Realize the top level Widget */
|
|
XtRealizeWidget(G_toplevel);
|
|
XtMapWidget(G_toplevel);
|
|
|
|
/*
|
|
* Wait for the top level Widget to be mapped.
|
|
* Reason: The routine for selecting a window position for popup windows
|
|
* (error and overwrite warning dialogs) won't work until the main window
|
|
* is mapped. Therefore, we don't want to start the actual copy operation
|
|
* (which might generate error or warning messages) before the main window
|
|
* is mapped.
|
|
*/
|
|
XtAddEventHandler(G_toplevel, StructureNotifyMask, False, CheckForMap, NULL);
|
|
while (!is_mapped)
|
|
EventCheck();
|
|
XtRemoveEventHandler(G_toplevel, XtAllEvents, True, CheckForMap, NULL);
|
|
|
|
/* Set up the Callbacks for the copy operation */
|
|
periodicCallback = EventCheck;
|
|
syncConfirmCallback = ConfirmHandler;
|
|
syncErrorCallback = ErrorHandler;
|
|
|
|
/* set up parameters for the copy operation */
|
|
app_args.sync.source = app_args.source_name; /* source directory */
|
|
app_args.sync.target = app_args.target_name; /* target directory */
|
|
app_args.sync.verbose++;
|
|
strcpy(last_dir, app_args.sync.source);
|
|
|
|
/*
|
|
* Call the Copy Function. This copy function will look at the
|
|
* even queue and see if there are any pending events. If so,
|
|
* it will dispatch these events and then resume the copy
|
|
* operation. The function will return after the copy operation
|
|
* has completed or when the user aborts the operation by
|
|
* clicking the "Cancel" button.
|
|
*/
|
|
SyncDirectory(&app_args.sync);
|
|
|
|
/* if move was requested and the copy was successful, delete the source now */
|
|
if (G_move)
|
|
{
|
|
if (nerr > 0)
|
|
{
|
|
sprintf(msg, GETMESSAGE(2, 13, "%s not removed because of errors."),
|
|
app_args.sync.source);
|
|
AppendErrorMsg(msg);
|
|
}
|
|
else
|
|
{
|
|
/* arrange for callback's during recursive directory delete */
|
|
progressCallback = moveDeleteCallback;
|
|
errorCallback = moveErrorCallback;
|
|
|
|
/* delete the source directory */
|
|
fsErase(app_args.sync.source, &rc, True);
|
|
}
|
|
}
|
|
|
|
/* display the result */
|
|
if (G_do_copy)
|
|
UpdateStatus(GETMESSAGE(2, 14, "Completed."), "");
|
|
else
|
|
UpdateStatus(GETMESSAGE(2, 15, "Cancelled in"), last_dir);
|
|
|
|
XtVaSetValues (G_error_msgs,
|
|
XmNcursorPosition, 0,
|
|
XmNtopCharacter, 0,
|
|
NULL);
|
|
|
|
/* desensitize the copy area */
|
|
desensitize_copy_action_area(G_copy_action_area_pbuttons);
|
|
|
|
/* if successful popdown the window after a delay */
|
|
if (app_args.popdown && nerr == 0)
|
|
XtAppAddTimeOut(app_context, app_args.delay, TimeoutHandler, NULL);
|
|
|
|
/* wait for user to close the dialog before exiting */
|
|
while (!G_dialog_closed)
|
|
{
|
|
XtAppNextEvent(app_context, &event);
|
|
XtDispatchEvent(&event);
|
|
}
|
|
|
|
exit(nerr);
|
|
}
|
|
|