/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (c) 1995-1999.  The Regents of the University of California.  All     */
/*   rights reserved.                                                      */
/*                                                                         */
/*   This work was produced at the University of California, Lawrence      */
/*   Livermore National Laboratory (UC LLNL) under contract no.            */
/*   W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy     */
/*   (DOE) and The Regents of the University of California (University)    */
/*   for the operation of UC LLNL.  Copyright is reserved to the           */
/*   University for purposes of controlled dissemination,                  */
/*   commercialization through formal licensing, or other disposition      */
/*   under terms of Contract 48; DOE policies, regulations and orders;     */
/*   and U.S. statutes.  The rights of the Federal Government are          */
/*   reserved under Contract 48 subject to the restrictions agreed upon    */
/*   by the DOE and University.                                            */
/*                                                                         */
/*                                                                         */
/*                              DISCLAIMER                                 */
/*                                                                         */
/*   This software was prepared as an account of work sponsored by an      */
/*   agency of the United States Government.  Neither the United States    */
/*   Government nor the University of California nor any of their          */
/*   employees, makes any warranty, express or implied, or assumes any     */
/*   liability or responsibility for the accuracy, completeness, or        */
/*   usefulness of any information, apparatus, product, or process         */
/*   disclosed, or represents that its specific commercial products,       */
/*   process, or service by trade name, trademark, manufacturer, or        */
/*   otherwise, does not necessarily constitute or imply its               */
/*   endorsement, recommendation, or favoring by the United States         */
/*   Government or the University of California. The views and opinions    */
/*   of the authors expressed herein do not necessarily state or reflect   */
/*   those of the United States Government or the University of            */
/*   California, and shall not be used for advertising or product          */
/*   endorsement purposes.                                                 */
/*                                                                         */
/*   Permission to use, copy, modify and distribute this software and its  */
/*   documentation for any non-commercial purpose, without fee, is         */
/*   hereby granted, provided that the above copyright notice and this     */
/*   permission notice appear in all copies of the software and            */
/*   supporting documentation, and that all UC LLNL identification in      */
/*   the user interface remain unchanged.  The title to copyright LLNL     */
/*   XDIR shall at all times remain with The Regents of the University     */
/*   of California and users agree to preserve same. Users seeking the     */
/*   right to make derivative works with LLNL XDIR for commercial          */
/*   purposes may obtain a license from the Lawrence Livermore National    */
/*   Laboratory's Technology Transfer Office, P.O. Box 808, L-795,         */
/*   Livermore, CA 94550.                                                  */
/*                                                                         */
/***************************************************************************/
/***************************************************************************/

#include <stdio.h>
#include <errno.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#include <Xm/LabelG.h>
#include <Xm/SeparatoG.h>
#include "xdir.h"
#include "list.h"
#include "str.h"

#define MAXARGV  300

static struct {
	struct dirwin_st *dirwin;
	struct entry_link *head;
} lc;

struct dirwin_st *launch_dirwin;

extern struct sl_struct *launcher_mappings;
extern XtAppContext app;
extern struct st_host_info hinfo[];
extern int beep_when_ops_done;
extern int child_to_parent_pipe[];
extern struct dirwin_st *dirwin_head;
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__GNU_LIBRARY__) && !defined(__GLIBC__) && !defined(__EMX__)
extern char *sys_errlist[];
#endif

char *entry_to_full_path();
struct sl_struct *create_array_list();
int cb_launch_commands();
char *system_name();
char *server_name();
char *decrypt_password();
char *cstring_to_text();
void concat();
void update_launch_menus();


/*
 * cb_launch - Callback to launch the command selected in the "Launch"
 *             menu.
 */
void
cb_launch(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
	XmString string;
	char *command_name;
	char *raw_command_line;
	char *command_line;
	char *ptr;
	int found_percent;
	int found_percent_s;
	int found_percent_l;
	int len;
	int i;
	int j;
	int k;
	char ch;
	struct entry_link *head_selected_entries = NULL;
	struct entry_link *head_command_lines = NULL;
	char *full_path;
	struct sl_struct *list;
	char buf[2];
	int nlaunches;
	char *passwrd;

	/* Start operation */
	if (!start_op(True))
		return;

	/* Clear error flag */
	raise_okflag();

	XtVaGetValues(widget, XmNlabelString, &string, NULL);
	command_name = cstring_to_text(string);
	XmStringFree(string);   /* Yes, this is necessary */

	/* Get command line associated with command name */
    for (i=0; i<launcher_mappings->nentries; i++)
		if (!compare_command_names(command_name,
				launcher_mappings->entries[i]))
			break;
	if (i == launcher_mappings->nentries)
		fatal_error("Bug in cb_launch()");
	if ((ptr = strchr(launcher_mappings->entries[i], ':')) == NULL)
		fatal_error("Bug in cb_launch()");
	XtFree(command_name);
	raw_command_line = ptr+2;

	/* Create list of full paths of selected entries */
	for (i=0; i<dirwin->nentries; i++)
		if (dirwin->entries[i].state == SELECTED) {
			full_path = entry_to_full_path(&dirwin->entries[i]);
			add_to_linked_list(&head_selected_entries, full_path);
			XtFree(full_path);
		}
	list = create_array_list(&head_selected_entries);

	/* Are %l and/or %s present in command line? */
	found_percent = False;
	found_percent_s = False;
	found_percent_l = False;
	len = strlen(raw_command_line);
	for (j=0; j<len; j++) {
		ch = raw_command_line[j];
		if (found_percent) {
			switch (ch) {
				case 's':
					found_percent_s = True;
					break;
				case 'l':
					found_percent_l = True;
				}
			found_percent = False;
		} else if (ch == '%')
			found_percent = True;
	}

	/* Should the command be launched? */
	if ((list->nentries == 0) && (found_percent_s || found_percent_l)) {
		warn("Can't launch command -- Requires selected entries.",
			dirwin->w_shell);
		release_array_list(list);
		end_op();
		return;
	}

	/* Interpret command line and create actual command line(s) */
	if (found_percent_s)
		nlaunches = list->nentries;
	else
		nlaunches = 1;
	for (i=nlaunches-1; i>=0; i--) {
		found_percent = False;
		len = strlen(raw_command_line);
		command_line = XtNewString("");
		for (j=0; j<len; j++) {
			ch = raw_command_line[j];
			if (found_percent) {
				switch (ch) {
				case 'h':
					concat(&command_line, hinfo[dirwin->host].hostname);
					break;
				case 'u':
					concat(&command_line, hinfo[dirwin->host].username);
					break;
				case 's':
					concat(&command_line, list->entries[i]);
					break;
				case 'l':
					for (k=0; k<list->nentries; k++) {
						concat(&command_line, list->entries[k]);
						if (k != list->nentries-1)
							concat(&command_line, " ");
					}
					break;
				case 'y':
					concat(&command_line,
						system_name(hinfo[dirwin->host].system));
					break;
				case 'v':
					concat(&command_line,
						server_name(hinfo[dirwin->host].server));
					break;
				case 'p':
					if (hinfo[dirwin->host].password) {
						passwrd =
							decrypt_password(hinfo[dirwin->host].password);
						concat(&command_line, passwrd);
						bzero(passwrd, (int)strlen(passwrd));
						XtFree(passwrd);
					} else
						concat(&command_line, "NO_PASSWORD");
					break;
				default:
					buf[0] = ch;
					buf[1] = '\0';
					concat(&command_line, buf);
				}
				found_percent = False;
			} else if (ch == '%')
				found_percent = True;
			else {
				buf[0] = ch;
				buf[1] = '\0';
				concat(&command_line, buf);
			}
		}
		if (found_percent)
			concat(&command_line, "%");
		add_to_linked_list(&head_command_lines, command_line);
		XtFree(command_line);
	}

	/* Construct control block for launch commands */
	lc.dirwin = dirwin;
	lc.head = head_command_lines;
	release_array_list(list);

	/* Pop up launch monitor */
	show_mp_monitor(dirwin, "Now Launching:");

	/* Make operation interruptable */
	show_stop_button(dirwin);

	/* Launch commands */
	XtAppAddWorkProc(app, (XtWorkProc)cb_launch_commands, NULL);
}


/*
 * init_launch_menus - Create the popup launch menu and then initialize the
 *                     popup and pulldown launch menus by creating a bunch
 *                     of placeholder menu items.
 */
void
init_launch_menus(dirwin)
struct dirwin_st *dirwin;
{
	XmString string;
	int i;
	Widget w_pulldown;

	/* Get pulldown menu */
	XtVaGetValues(dirwin->w_launchMenu, XmNsubMenuId, &w_pulldown, NULL);

	/* Create popup menu */
	dirwin->w_popupLaunchMenu = XmCreatePopupMenu(dirwin->w_drawingArea,
		"popup", NULL, 0);

	/* Create header for popup menu */
	XtVaCreateManagedWidget("popupLaunchMenuLabel", xmLabelGadgetClass,
		dirwin->w_popupLaunchMenu, NULL);
	XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass,
		dirwin->w_popupLaunchMenu, NULL);
	XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass,
		dirwin->w_popupLaunchMenu, NULL);

	/* Now create the menu items, but leave them unmanaged */
	string = XmStringCreateSimple("Dummy");
	for (i=0; i<MAXLAUNCH; i++) {
		dirwin->w_launchMenuItem[i] = XtVaCreateWidget(
            "",
            xmPushButtonGadgetClass,
            w_pulldown,
            XmNlabelString, string,
            NULL
        );
        XtAddCallback(dirwin->w_launchMenuItem[i], XmNactivateCallback,
            cb_launch, (XtPointer)dirwin);
   		dirwin->w_popupLaunchMenuItem[i] = XtVaCreateWidget(
            "",
            xmPushButtonGadgetClass,
            dirwin->w_popupLaunchMenu,
            XmNlabelString, string,
            NULL
        );
        XtAddCallback(dirwin->w_popupLaunchMenuItem[i], XmNactivateCallback,
            cb_launch, (XtPointer)dirwin);
    }
    XmStringFree(string);
}


/*
 * update_all_launch_menus - Update the "Launch" menu in each directory
 *                           window.
 */
void
update_all_launch_menus()
{
	struct dirwin_st *dirwin;

	dirwin = dirwin_head;
	while (dirwin) {
		update_launch_menus(dirwin);
		dirwin = dirwin->next;
	}
}


/*
 * update_launch_menus - Update the popup and pulldown launch menus with 
 *                       the latest values from the launch preferences.
 */
void
update_launch_menus(dirwin)
struct dirwin_st *dirwin;
{
	int i;
	XmString label;
	char *temp_buf;
	char *command_name;

    /* Get rid of current launch menus items */
    for (i=0; i<MAXLAUNCH; i++) {
        XtUnmanageChild(dirwin->w_launchMenuItem[i]);
		XtUnmanageChild(dirwin->w_popupLaunchMenuItem[i]);
	}

	/* Set sensitivity of launch menu */
	if (launcher_mappings->nentries)
		XtSetSensitive(dirwin->w_launchMenu, True);
	else
		XtSetSensitive(dirwin->w_launchMenu, False);

    /* Enter launch command names into launch menus */
    for (i=0; i<launcher_mappings->nentries; i++) {
		temp_buf = XtNewString(launcher_mappings->entries[i]);
		command_name = strtok(temp_buf, ":");
        label = XmStringCreateSimple(command_name);
		XtFree(temp_buf);
        XtVaSetValues(dirwin->w_launchMenuItem[i], XmNlabelString, label,
			NULL);
        XtVaSetValues(dirwin->w_popupLaunchMenuItem[i], XmNlabelString, label,
			NULL);
        XmStringFree(label);
        XtManageChild(dirwin->w_launchMenuItem[i]);
		XtManageChild(dirwin->w_popupLaunchMenuItem[i]);
    }
}


/*
 * concat - Concatenates string "s2" to string "s1".  "s1" is actually a
 *          pointer to a string.  The original string pointed to by "s1"
 *          is freed with XtFree().  Use XtFree() to release the memory
 *          returned in "s2".
 */
void
concat(s1, s2)
char **s1;
char *s2;
{
	char *new_s1 = XtMalloc(strlen(*s1)+strlen(s2)+1);

	strcpy(new_s1, *s1);
	strcat(new_s1, s2);
	XtFree(*s1);
	*s1 = new_s1;
}


/*
 * cb_launch_commands - Work proc to actually launch commands.
 */
cb_launch_commands()
{
	struct entry_link *ptr;
	int pid;
	char *argv[MAXARGV+1];
	int argc;
	char *cmd;
	char *msg;
	int saved_errno;
	int len;

	/* Did user push stop button? */
	if (stop()) {
		goto abort;
	}

    /* Are we done? */
    if (lc.head == NULL)
        goto done;

	/* Let user know where we are */
	update_mp_monitor(lc.head->entry);

	/* Parse execute line into tokens */
	cmd = XtNewString(lc.head->entry);
	argc = 0;
    if ((argv[argc++] = strtok(cmd, " ")) == NULL)
        fatal_error("Trouble in cb_launch_commands()");
    while (argc < MAXARGV && (argv[argc] = strtok(NULL, " ")) != NULL)
        argc++;
    if (argc == MAXARGV) {
        warn("Can't launch command -- Bad execute line", lc.dirwin->w_shell);
		XtFree(cmd);
		goto done;
	}

    /* Fork and exec */
	launch_dirwin = lc.dirwin;
    if ((pid = fork()) == 0)
        if (execvp(argv[0], argv) == -1) {
			saved_errno = errno;
			msg = XtMalloc(50+strlen(lc.head->entry)+
				strlen(sys_errlist[saved_errno]));
			sprintf(msg, "Unable to launch command:\n\n%s\n\n", lc.head->entry);
			strcat(msg, sys_errlist[saved_errno]);
			strcat(msg, "\n\007");
			len = strlen(msg);
			if (iwrite(child_to_parent_pipe[1], msg, len) != len)
				fatal_error("Trouble in cb_launch_commands()");
            exit(-1);
        }

	/* Finished launching this command */
	XtFree(cmd);
	ptr = lc.head;
	lc.head = lc.head->next;
	XtFree(ptr->entry);
	XtFree((char *)ptr);
	sleep(1);
	return False;

abort:

	hide_mp_monitor();
	record_abort("Launch Command");
	goto final;

done:

	hide_mp_monitor();

final:

	/* Miscellaneous cleanup */
	release_linked_list(&lc.head);
	if (beep_when_ops_done)
		beep();
	restore_prev_cursor();

	/* Signal end of operation */
	hide_stop_button();
	end_op();
	return True;
}



syntax highlighted by Code2HTML, v. 0.9.1