/* save.c
   make the file save dialog popup, and manage it. */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.3     08 April 1993                  */
     /*                version 1.2     20 November 1992               */
     /*                version 1.1     20 April 1992                  */
     /*                version 1.0     04 March 1992                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing and Communications Services Office   */
     /* Copyright 1992, 1993 by                                       */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/

#include <stdio.h>
#include <ctype.h>


#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Label.h>
#include <X11/Shell.h>

#include <sys/types.h>
#include <sys/stat.h>

#include "compatR4.h"
#include "gopher.h"
#include "osdep.h"
#include "appres.h"
#include "globals.h"
#include "xglobals.h"
#include "gui.h"
#include "misc.h"


/* 
	"Save" is single-threaded by issuing a grab nonexclusive when
	poped up.  So it is safe to use these globals to store an open
	file descriptor and other information.  Be careful if this
	ever changes.
*/
typedef enum {SAVE_copy, SAVE_displayedText} saveType;

#define OPENFLAGS_NEWFILE	(O_CREAT | O_EXCL | O_WRONLY)
#define OPENFLAGS_OVERWRITE	(O_CREAT | O_TRUNC | O_WRONLY)
#define OPENFLAGS_APPEND	(O_APPEND | O_WRONLY)

static	int		FDToSave;
static	int		saveLen;
static	gopherItemP	giSaved;
static	XtPointer	tepSaved;
/*
static	BOOLEAN		(*copyProc)();
*/
static	saveType	returnTo;

void	makeCD();
void	makeDupFile();


static Widget	topLevel;
static Widget	saveShell;
static Widget	fileNameText, dirPath;
static Widget	fileErrMessage;
static Widget	saveLabel1, saveLabel2;

static char	currentDir[PATH_NAME_LEN];

#define SAVE_POPUP_NAME		"savePopup"
				/* default values */
static popupPosResources	placementSave = {
	/* position at the top of the main panel, centered across */
	from_widget, 0, 10, justify_top_left, justify_top_left, True, True
	};

#define COPY_POPUP_NAME		"copyPopup"
				/* default values */
static popupPosResources	placementCopy = {
	/* position at the top of the main panel, centered across */
	from_main, 0, 10, justify_top_left, justify_top_left, True, True
	};

typedef enum {Dup_none, Dup_overwrite, Dup_again, Dup_append, Dup_cancel}
	dupType;

static dupType duplicateName = Dup_none;


/* saveOkProc
   accept file name and complete the copy-to-file or the 
   save-displayed-text command */

void
saveOkProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	int		c;
	char		*tempFile, *newFile, *p;
	int		outFD;
	BOOLEAN		rc;
	char		message[MESSAGE_STRING_LEN];
	struct stat	buf;
	Arg		args[10];
	Cardinal	n = 0;
	int		openFlags;

	/* clear previous warning */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(fileErrMessage, args, n);

	/* get the file name */

	n = 0;
	XtSetArg(args[n], XtNstring, &tempFile);  n++;
	XtGetValues(fileNameText, args, n);

	newFile = tildePath(tempFile);

	for (p=newFile; isgraph(*p); p++) ;
	if (*p != NULLC) {
		/* truncated at first non-printable character */
		*p = NULLC;
	} 
	if (*newFile == NULLC) {
		sprintf(message, "Warning: This is not a legal file name");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(fileErrMessage, args, n);

		return;
	}

	switch (duplicateName) {
	case Dup_none:			/* first time through */
	case Dup_again:			/* already informed user */
		if (stat(newFile, &buf) == 0) {
			displayDupFile(newFile);
			return;
		}
		openFlags = OPENFLAGS_NEWFILE;
		break;
	case Dup_overwrite:
		openFlags = OPENFLAGS_OVERWRITE;
		break;
	case Dup_append:
		openFlags = OPENFLAGS_APPEND;
		break;
	case Dup_cancel:	/* should not actually get here */
		XtPopdown(saveShell);
		return;
		break;
	}

	if ((outFD = open(newFile, openFlags,
					SAVE_FILE_MODE)) < 0) {
		perror("save");
		sprintf(message, "Warning: The file cannot be opened");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(fileErrMessage, args, n);

		return;
	}

	XtPopdown(saveShell);

	if (returnTo == SAVE_displayedText) {
		rc = saveDisplayedText(outFD, tepSaved);
	} else {
		rc = GI_copyFromNet(outFD, giSaved, (char *) NULL);
	}

	close(outFD);

	if (! rc) {
		unlink( newFile );
	}

	return;
}


/* SaveOk
   accept the OK action from a keyboard <cr> instead of the OK button.
   The <cr> translation is defined elsewhere.
   Capitalized name is for X action proc convention. */

void
SaveOk(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	saveOkProc(w, NULL, NULL);
	return;
}


/* saveCancelProc
   reject file name and do not process the save command */

void
saveCancelProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown(saveShell);
}


/* SaveCancel
   accept the cancel action from a translation.
   Capitalized name is for X action proc convention. */

void
SaveCancel(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	saveCancelProc(w, NULL, NULL);
	return;
}


/* saveCdProc
   display change directory panel */

void
saveCdProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	Arg		args[10];
	Cardinal	n = 0;

	displayCD();

	/* clear previous warning */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(fileErrMessage, args, n);
}


/* SaveCd
   accept the change directory action from a translation.
   Capitalized name is for X action proc convention. */

void
SaveCd(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	saveCdProc(w, NULL, NULL);
	return;
}


/* saveHelpProc
   display save help information */

void
saveHelpProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	showHelp("save-copy help");
}


/* SaveHelp
   accept the change directory action from a translation.
   Capitalized name is for X action proc convention. */

void
SaveHelp(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	saveHelpProc(w, NULL, NULL);
	return;
}


/* makeSaveDialog
   create popup dialog for saving files */

void
makeSaveDialog(top)
Widget	top;
{
	Widget		okButton, cancelButton, cdButton, helpButton;
	Widget		saveForm, dirLabel;
	Arg		args[10];
	Cardinal	n = 0;
	Dimension	wid;
	static XtActionsRec	saveActionsTable[] = {
				{ "saveok", (XtActionProc) SaveOk },
				{ "saveCancel", (XtActionProc) SaveCancel }
				};

	topLevel = top;

	n = 0;
	XtSetArg(args[n], XtNtitle, "Save or Copy to a File");  n++;
	saveShell = XtCreatePopupShell("saveShell", 
					transientShellWidgetClass,
					topLevel, args, n);


	n = 0;
	XtSetArg(args[n], XtNlabel, "Save text to file ...");  n++;
	XtSetArg(args[n], XtNvalue, "");  n++;
	saveForm= XtCreateManagedWidget("saveForm", 
					formWidgetClass,
					saveShell, args, n);

	/* create save directory label */

		n=0;
		XtSetArg(args[n], XtNjustify,   XtJustifyLeft);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;

	dirLabel = XtCreateManagedWidget("dirLabel", labelWidgetClass,
					saveForm, args, n);

	/* create current directory text */

		n=0;
		XtSetArg(args[n], XtNeditType, XawtextRead);  n++;
		XtSetArg(args[n], XtNstring, "");  n++;
		XtSetArg(args[n], XtNfromVert,  dirLabel);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;
	dirPath = XtCreateManagedWidget("dirPath", asciiTextWidgetClass,
					saveForm, args, n);
	setTextWidgetSize(dirPath, 50, 1);

	n=0;
	XtSetArg(args[n], XtNwidth, &wid);  n++;
	XtGetValues(dirPath, args, n);


	/* create save labels */

		n=0;
		XtSetArg(args[n], XtNfromVert,  dirPath);  n++;
		XtSetArg(args[n], XtNwidth,	wid);  n++;
		XtSetArg(args[n], XtNjustify,   XtJustifyLeft);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	saveLabel1 = XtCreateManagedWidget("saveLabel1", labelWidgetClass,
					saveForm, args, n);

		n=0;
		XtSetArg(args[n], XtNfromVert,  saveLabel1);  n++;
		XtSetArg(args[n], XtNwidth,	wid);  n++;
		XtSetArg(args[n], XtNjustify,   XtJustifyLeft);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	saveLabel2 = XtCreateManagedWidget("saveLabel2", labelWidgetClass,
					saveForm, args, n);

	/* create file name text */

		n=0;
		XtSetArg(args[n], XtNeditType,  XawtextEdit);  n++;
		XtSetArg(args[n], XtNstring,    "");  n++;
		XtSetArg(args[n], XtNwidth,     wid);  n++;
		XtSetArg(args[n], XtNfromVert,  saveLabel2);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;
	fileNameText = XtCreateManagedWidget("fileName", asciiTextWidgetClass,
					saveForm, args, n);
	XtOverrideTranslations(fileNameText, oneLineParsed);


	/* create file name error message */

		n=0;
		XtSetArg(args[n], XtNwidth,     wid);  n++;
		XtSetArg(args[n], XtNfromVert,  fileNameText);  n++;
		XtSetArg(args[n], XtNlabel,     "");  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;
	fileErrMessage = XtCreateManagedWidget("fileErrMessage",
					labelWidgetClass,
					saveForm, args, n);

	/* create save ok button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  fileErrMessage);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	okButton = XtCreateManagedWidget("ok", commandWidgetClass,
					saveForm, args, n);
	XtAddCallback(okButton, XtNcallback, saveOkProc, NULL);

	/* create save cancel button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  fileErrMessage);  n++;
		XtSetArg(args[n], XtNfromHoriz, okButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	cancelButton = XtCreateManagedWidget("cancel", commandWidgetClass,
					saveForm, args, n);
	XtAddCallback(cancelButton, XtNcallback, saveCancelProc, NULL);

	/* create save change directory button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  fileErrMessage);  n++;
		XtSetArg(args[n], XtNfromHoriz, cancelButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	cdButton = XtCreateManagedWidget("chdir", commandWidgetClass, 
					saveForm, args, n);
		XtAddCallback(cdButton, XtNcallback, saveCdProc, NULL);

	/* create save help button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  fileErrMessage);  n++;
		XtSetArg(args[n], XtNfromHoriz, cdButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	helpButton = XtCreateManagedWidget("help", commandWidgetClass,
					saveForm, args, n);
	XtAddCallback(helpButton, XtNcallback, saveHelpProc, NULL);

	XtAppAddActions(appcon, saveActionsTable, XtNumber(saveActionsTable));

	XtSetKeyboardFocus(saveForm, fileNameText);

        /* for ICCCM window manager protocol complience */

        XtOverrideTranslations (saveShell,
            XtParseTranslationTable ("<Message>WM_PROTOCOLS: saveCancel()"));
        XtRealizeWidget(saveShell);
        (void) XSetWMProtocols (XtDisplay(saveShell),
			 XtWindow(saveShell), &wmDeleteAtom, 1);


	/* find the popup placement for this shell */

	{
	popupPosResources *resourcePlacement;

	resourcePlacement = getPopupPosResources(
			SAVE_POPUP_NAME, POPUP_POS_CLASS, &placementSave);
	bcopy( (char *) resourcePlacement, (char *) &placementSave,
				sizeof(popupPosResources) );

	resourcePlacement = getPopupPosResources(
			COPY_POPUP_NAME, POPUP_POS_CLASS, &placementCopy);
	bcopy( (char *) resourcePlacement, (char *) &placementCopy,
				sizeof(popupPosResources) );
	}


	makeCD(saveShell);
	makeDupFile(saveShell);
	
}


/* saveRequest
   enable popup dialog for saving files */

void
saveRequest(textShell, tep)
Widget		textShell;
XtPointer	tep;
{

	Arg		args[10];
	Cardinal	n = 0;
	Position	x, y;
	Dimension	w, h;
	char		label[MESSAGE_STRING_LEN];
	Widget		posFrom;
	char		*dir;

	tepSaved = tep;
	returnTo = SAVE_displayedText;

	duplicateName = Dup_none;

	dir = getwd(currentDir);
	if (dir == (char *) NULL) {
		fprintf (stderr, "Cannot determine current directory:\n%s\n",
				currentDir);
		currentDir[0] = (char) NULL;
	}

	n = 0;
	XtSetArg(args[n], XtNstring, currentDir);  n++;
	XtSetValues(dirPath, args, n);

	/* should give name of subject that is being saved */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(saveLabel1, args, n);

	sprintf(label, "Enter a file name to save the text to");
	n = 0;
	XtSetArg(args[n], XtNlabel, label);  n++;
	XtSetValues(saveLabel2, args, n);

	n = 0;
	XtSetArg(args[n], XtNstring, "");  n++;
	XtSetValues(fileNameText, args, n);

	n = 0;
	XtSetArg(args[n], XtNtransientFor, textShell);  n++;
	XtSetValues(saveShell, args, n);

	if (placementSave.positionFrom == from_widget) {
		posFrom = (textShell != NULL) ? textShell : topLevel;
	}  else {
		posFrom = topLevel;
	}

	/* clear previous warning */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(fileErrMessage, args, n);

	positionAPopup(saveShell, posFrom, &placementSave);

	XtPopup(saveShell, XtGrabExclusive);

	if (appResources->warpCursor) {
                XWarpPointer(XtDisplay(saveShell), None,
                                XtWindow(fileNameText),
                                0, 0, 0, 0,
                                10, 5);

        }

	return;
}


/* saveNetRequest
   enable popup dialog for saving file directly from a gopher server */

void
saveNetRequest(gi)
gopherItemP	gi;
{
	char	*suggestedName;
	int	len = -1;

	Arg		args[10];
	Cardinal	n = 0;
	Position	x, y;
	Dimension	w, h;
	char		label[MESSAGE_STRING_LEN];
	char		*dir;

	saveLen = len;
	giSaved = gi;
	/* copyProc = gi->sc->copyTypeProc; */
	returnTo = SAVE_copy;

	duplicateName = Dup_none;

	dir = getwd(currentDir);
	if (dir == (char *) NULL) {
		fprintf (stderr, "Cannot determine current directory:\n%s\n",
				currentDir);
		currentDir[0] = (char) NULL;
	}

	n = 0;
	XtSetArg(args[n], XtNstring, currentDir);  n++;
	XtSetValues(dirPath, args, n);

	/* get the last component of the name.  If there is no '/' in
	   the path name, be suspicious and send NULL. */

	suggestedName = rindex(vStringValue(&(gi->selector)), '/');
	if (suggestedName != NULL) suggestedName++;

	/* should give name of subject that is being saved */

	sprintf(label, "Enter a file name to receive contents of:");
	n = 0;
	XtSetArg(args[n], XtNlabel, label);  n++;
	XtSetValues(saveLabel1, args, n);

	sprintf(label, "\"%s\"", USER_STRING(gi));
	n = 0;
	XtSetArg(args[n], XtNlabel, label);  n++;
	XtSetValues(saveLabel2, args, n);

	n = 0;
	if (suggestedName != NULL) {
		XtSetArg(args[n], XtNstring, suggestedName);  n++;
	} else {
		XtSetArg(args[n], XtNstring, "");  n++;
	}
	XtSetValues(fileNameText, args, n);

	/* clear previous warning */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(fileErrMessage, args, n);

	positionAPopup(saveShell, topLevel, &placementCopy);

	XtPopup(saveShell, XtGrabExclusive);

	return;
}


void
dupWrite()
{
	duplicateName = Dup_overwrite;
	saveOkProc((Widget) NULL, (XtPointer) NULL, (XtPointer) NULL);
	return;
}


void
dupAppend()
{
	duplicateName = Dup_append;
	saveOkProc((Widget) NULL, (XtPointer) NULL, (XtPointer) NULL);
	return;
}


void
dupChange()
{
	duplicateName = Dup_again;
	return;
}


void
dupCancel()
{
	duplicateName = Dup_cancel;
	saveCancelProc((Widget) NULL, (XtPointer) NULL, (XtPointer) NULL);
	return;
}


/* ====================================================================== */
/* Change Directory popup                                                 */
/* ====================================================================== */

static Widget	cdParent;
static Widget	cdShell;
static Widget	cdErrMessage;
static Widget	cdPathName;

#define CD_POPUP_NAME		"cdPopup"
				/* default values */
static popupPosResources	placementCD = {
	/* position on the parent shell, centered near the left bottom */
	from_widget, 0, 33, justify_top_left, justify_top_left, True, True
	};


/* cdOkProc
   accept change directory command */

void
cdOkProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	char		*path, *tempPath;
	struct stat	buf;
	char		message[MESSAGE_STRING_LEN];
	Arg		args[10];
	Cardinal	n = 0;


	/* clear error text */

	n = 0;
	XtSetArg(args[n], XtNlabel, "");  n++;
	XtSetValues(cdErrMessage, args, n);

	/* ensure that the selected path exists and is writable */

	n = 0;
	XtSetArg(args[n], XtNstring, &tempPath);  n++;
	XtGetValues(cdPathName, args, n);

	path = tildePath(tempPath);

	if (stat(path, &buf) != 0) {
		/* file/directory doesn't exist */

		fprintf (stderr, "%s does not exist\n", path);
		sprintf (message, "This directory does not exist");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(cdErrMessage, args, n);

		return;
	}
	else if ((buf.st_mode & S_IFDIR) == 0) {
		/* not directory */

		fprintf (stderr, "%s is not a directory\n", path);
		sprintf (message, "This is not a directory");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(cdErrMessage, args, n);

		return;
	}
	else if (! isWriteableMode(&buf)) {
		/* not writable */

		fprintf (stderr, "%s is not writeable\n", path);
		sprintf (message, "You cannot write to this directory");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(cdErrMessage, args, n);

		return;
	}

	if (chdir(path) != 0) {
		perror("save");

		fprintf (stderr, "Cannot change to directory:\n%s\n",
				path);
		sprintf (message, "You cannot change to this directory");

		n = 0;
		XtSetArg(args[n], XtNlabel, message);  n++;
		XtSetValues(cdErrMessage, args, n);

		return;
	}

	XtPopdown (cdShell);

	strcpy(currentDir, path);

	n = 0;
	XtSetArg(args[n], XtNstring, currentDir);  n++;
	XtSetValues(dirPath, args, n);

	return;
}


/* CDOk
   accept the OK action from a keyboard <cr> instead of the OK button.
   The <cr> translation is defined elsewhere.
   Capitalized name is for X action proc convention. */

void
CDOk(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	cdOkProc(w, NULL, NULL);
	return;
}


/* cdCancelProc
   cancel change directory dialog */

void
cdCancelProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown(cdShell);
}


/* CDCancel
   accept the Cancel action from a keyboard <cr> instead of the Cancel button.
   Capitalized name is for X action proc convention. */

void
CDCancel(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	cdCancelProc(w, NULL, NULL);
	return;
}


/* cdHelpProc
   give help for change directory dialog */

void
cdHelpProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	showHelp("change dir help");
}


/* CDHelp
   accept the Help action from a keyboard <cr> instead of the Help button.
   Capitalized name is for X action proc convention. */

void
CDHelp(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	cdHelpProc(w, NULL, NULL);
	return;
}


/* displayCD
   pop up the change diretory panel */

displayCD()
{
	Arg		args[10];
	Cardinal	n = 0;

	/* clear previous directory name and error text */

	n = 0;
	XtSetArg(args[n], XtNstring, "");  n++;
	XtSetValues(cdPathName, args, n);

	n = 0;
	XtSetArg(args[n], XtNstring, "");  n++;
	XtSetValues(cdErrMessage, args, n);

	positionAPopup(cdShell, cdParent, &placementCD);
	
	XtPopup (cdShell, XtGrabExclusive);
}


/* makeCD
   create change directory dialog */

void
makeCD(top)
Widget	top;
{
	Widget		okButton, cancelButton, helpButton;
	Widget		dirLabel;
	Widget		cdForm;
	Arg		args[10];
	Cardinal	n = 0;
	Dimension	wid;
	static XtActionsRec	cdActionsTable[] = {
				{ "cdok", (XtActionProc) CDOk },
				{ "cdCancel", (XtActionProc) CDCancel },
				{ "cdHelp", (XtActionProc) CDHelp },
				};

	cdParent = top;

		n = 0;
		XtSetArg(args[n], XtNtitle, "Change Working Directory");  n++;
		XtSetArg(args[n], XtNtransientFor, cdParent);  n++;
	cdShell = XtCreatePopupShell("cdShell", transientShellWidgetClass,
					cdParent, args, n);

		n = 0;
	cdForm= XtCreateManagedWidget("cdForm", formWidgetClass,
					cdShell, args, n);

	/* create cd label */

		n=0;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;

	dirLabel = XtCreateManagedWidget("cdLabel", labelWidgetClass,
					cdForm, args, n);

	/* create cd text */

		n=0;
		XtSetArg(args[n], XtNeditType, XawtextEdit);  n++;
		XtSetArg(args[n], XtNstring, "");  n++;
		XtSetArg(args[n], XtNfromVert,  dirLabel);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;
	cdPathName = XtCreateManagedWidget("cdPathName", asciiTextWidgetClass,
					cdForm, args, n);
	setTextWidgetSize(cdPathName, 50, 1);
	XtOverrideTranslations(cdPathName, oneLineParsed);

	n=0;
	XtSetArg(args[n], XtNwidth, &wid);  n++;
	XtGetValues(dirPath, args, n);


	/* create cd error message */

		n=0;
		XtSetArg(args[n], XtNwidth,     wid);  n++;
		XtSetArg(args[n], XtNfromVert,  cdPathName);  n++;
		XtSetArg(args[n], XtNlabel,     " ");  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;
	cdErrMessage = XtCreateManagedWidget("cdErrMessage", labelWidgetClass,
					cdForm, args, n);

	/* create cd ok button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  cdErrMessage);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	okButton = XtCreateManagedWidget("ok", commandWidgetClass,
					cdForm, args, n);
	XtAddCallback(okButton, XtNcallback, cdOkProc, NULL);

	/* create cd cancel button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  cdErrMessage);  n++;
		XtSetArg(args[n], XtNfromHoriz, okButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	cancelButton = XtCreateManagedWidget("cancel", commandWidgetClass,
					cdForm, args, n);
	XtAddCallback(cancelButton, XtNcallback, cdCancelProc, NULL);

	/* create cd help button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  cdErrMessage);  n++;
		XtSetArg(args[n], XtNfromHoriz, cancelButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	helpButton = XtCreateManagedWidget("help", commandWidgetClass,
					cdForm, args, n);
	XtAddCallback(helpButton, XtNcallback, cdHelpProc, NULL);


	XtAppAddActions(appcon, cdActionsTable, XtNumber(cdActionsTable));

	XtSetKeyboardFocus(cdForm, cdPathName);

        /* for ICCCM window manager protocol complience */

        XtOverrideTranslations (cdShell,
            XtParseTranslationTable ("<Message>WM_PROTOCOLS: cdCancel()"));
        XtRealizeWidget(cdShell);
        (void) XSetWMProtocols (XtDisplay(cdShell),
			 XtWindow(cdShell), &wmDeleteAtom, 1);


	/* find the popup placement for this shell */

	{
	popupPosResources *resourcePlacement;

	resourcePlacement = getPopupPosResources(
			CD_POPUP_NAME, POPUP_POS_CLASS, &placementCD);
	bcopy( (char *) resourcePlacement, (char *) &placementCD,
				sizeof(popupPosResources) );
	}
}


/* ====================================================================== */
/* File exists already popup                                              */
/* ====================================================================== */

static Widget	dupFileParent;
static Widget	dupFileShell;
static Widget	dupFileLabelFN;

#define DUPFILE_POPUP_NAME		"dupFilePopup"
				/* default values */
static popupPosResources	placementDupFile = {
	/* position on the parent shell, centered, with bottoms aligned */
	from_widget, 50, 90, justify_center, justify_bottom_right, True, True
	};


/* dupFileOkProc
   accept overwrite contents command */

void
dupFileOkProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown (dupFileShell);

	dupWrite();
	return;
}


/* DupFileOk
   accept the OK action from a keyboard <cr> instead of the OK button.
   The <cr> translation is defined elsewhere.
   Capitalized name is for X action proc convention. */

void
DupFileOk(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	dupFileOkProc(w, NULL, NULL);
	return;
}


/* dupFileAppendProc
   accept append contents command */

void
dupFileAppendProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown (dupFileShell);

	dupAppend();
	return;
}


/* DupFileAppend
   accept the append action from a keyboard action instead of the append button.
   Capitalized name is for X action proc convention. */

void
DupFileAppend(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	dupFileAppendProc(w, NULL, NULL);
	return;
}


/* dupFileChangeProc
   change this save request because duplicate file name */

void
dupFileChangeProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown(dupFileShell);

	dupChange();
}


/* DupFileChange
   accept the Change action from a keyboard action instead of the Change button.
   Capitalized name is for X action proc convention. */

void
DupFileChange(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	dupFileChangeProc(w, NULL, NULL);
	return;
}


/* dupFileCancelProc
   cancel this save request because duplicate file name */

void
dupFileCancelProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XtPopdown(dupFileShell);

	dupCancel();
}


/* DupFileCancel
   accept the Cancel action from a keyboard action instead of the Cancel button.
   Capitalized name is for X action proc convention. */

void
DupFileCancel(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	dupFileCancelProc(w, NULL, NULL);
	return;
}


/* dupFileHelpProc
   give help for duplicate file name dialog */

void
dupFileHelpProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	showHelp("dup file help");
}


/* DupFileHelp
   accept the Help action from a keyboard action instead of the Help button.
   Capitalized name is for X action proc convention. */

void
DupFileHelp(w, event, parms, nparms)
Widget		w;
XEvent		*event;
String		*parms;
Cardinal	*nparms;
{
	dupFileHelpProc(w, NULL, NULL);
	return;
}


/* displayDupFile
   pop up the file already exists (duplicate file) panel */

displayDupFile(path)
char	*path;
{
	Arg		args[10];
	Cardinal	n = 0;

	n = 0;
	XtSetArg(args[n], XtNlabel, path);  n++;
	XtSetValues(dupFileLabelFN, args, n);

	positionAPopup(dupFileShell, dupFileParent, &placementDupFile);
	
	XtPopup (dupFileShell, XtGrabExclusive);
}


/* makeDupFile
   create duplicate file name notice dialog */

void
makeDupFile(top)
Widget	top;
{
	Widget		okButton, appendButton, changeButton,
			cancelButton, helpButton;
	Widget		label1, label2;
	Widget		dupFileForm;
	Arg		args[10];
	Cardinal	n = 0;
	Dimension	wid;
	static XtActionsRec	dupFileActionsTable[] = {
				{ "dupFileok", (XtActionProc) DupFileOk },
			     { "dupFileappend", (XtActionProc) DupFileAppend },
			     { "dupFileCancel", (XtActionProc) DupFileCancel },
				{ "dupFileHelp", (XtActionProc) DupFileHelp },
				};

	dupFileParent = top;

		n = 0;
		XtSetArg(args[n], XtNtitle, "File Already Exists");  n++;
		XtSetArg(args[n], XtNtransientFor, dupFileParent);  n++;
	dupFileShell = XtCreatePopupShell("dupFileShell",
					transientShellWidgetClass,
					dupFileParent, args, n);

		n = 0;
	dupFileForm= XtCreateManagedWidget("dupFileForm", formWidgetClass,
					dupFileShell, args, n);

	/* create dupFile label */

		n=0;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;

	label1 = XtCreateManagedWidget("label1", labelWidgetClass,
					dupFileForm, args, n);

	/* create dupFile file name label */

		n=0;
		XtSetArg(args[n], XtNfromHoriz, label1);  n++;
		XtSetArg(args[n], XtNjustify,   XtJustifyLeft);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainRight);  n++;

	dupFileLabelFN = XtCreateManagedWidget("labelFile", labelWidgetClass,
					dupFileForm, args, n);
	{
		Dimension	w, h;

		getTextSize(dupFileLabelFN, 40, 1, &w, &h);
		n=0;
		XtSetArg(args[n], XtNwidth, w);  n++;
		XtSetValues(dupFileLabelFN, args, n);
	}

	/* create dupFile label */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label1);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;

	label2 = XtCreateManagedWidget("label2", labelWidgetClass,
					dupFileForm, args, n);


	/* create dupFile ok button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label2);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	okButton = XtCreateManagedWidget("ok", commandWidgetClass,
					dupFileForm, args, n);
	XtAddCallback(okButton, XtNcallback, dupFileOkProc, NULL);


	/* create dupFile cancel button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label2);  n++;
		XtSetArg(args[n], XtNfromHoriz, okButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	cancelButton = XtCreateManagedWidget("cancel", commandWidgetClass,
					dupFileForm, args, n);
	XtAddCallback(cancelButton, XtNcallback, dupFileCancelProc, NULL);


	/* create dupFile append button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label2);  n++;
		XtSetArg(args[n], XtNfromHoriz, cancelButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	appendButton = XtCreateManagedWidget("append", commandWidgetClass,
					dupFileForm, args, n);
	XtAddCallback(appendButton, XtNcallback, dupFileAppendProc, NULL);

	/* create dupFile change button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label2);  n++;
		XtSetArg(args[n], XtNfromHoriz, appendButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	changeButton = XtCreateManagedWidget("change", commandWidgetClass,
					dupFileForm, args, n);
	XtAddCallback(changeButton, XtNcallback, dupFileChangeProc, NULL);

	/* create dupFile help button */

		n=0;
		XtSetArg(args[n], XtNfromVert,  label2);  n++;
		XtSetArg(args[n], XtNfromHoriz, changeButton);  n++;
		XtSetArg(args[n], XtNtop,       XawChainTop);  n++;
		XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
		XtSetArg(args[n], XtNleft,      XawChainLeft);  n++;
		XtSetArg(args[n], XtNright,     XawChainLeft);  n++;
	helpButton = XtCreateManagedWidget("help", commandWidgetClass,
					dupFileForm, args, n);
	XtAddCallback(helpButton, XtNcallback, dupFileHelpProc, NULL);


	XtAppAddActions(appcon, dupFileActionsTable,
				XtNumber(dupFileActionsTable));


        /* for ICCCM window manager protocol complience */

        XtOverrideTranslations (dupFileShell,
            XtParseTranslationTable (
				"<Message>WM_PROTOCOLS: dupFileCancel()"));
        XtRealizeWidget(dupFileShell);
        (void) XSetWMProtocols (XtDisplay(dupFileShell),
			 XtWindow(dupFileShell), &wmDeleteAtom, 1);


	/* find the popup placement for this shell */

	{
	popupPosResources *resourcePlacement;

	resourcePlacement = getPopupPosResources(
		DUPFILE_POPUP_NAME, POPUP_POS_CLASS, &placementDupFile);
	bcopy( (char *) resourcePlacement, (char *) &placementDupFile,
				sizeof(popupPosResources) );
	}

}
