/***************************************************************************/
/***************************************************************************/
/* */
/* (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 <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <Xm/Form.h>
#include <Xm/PushBG.h>
#include <Xm/Text.h>
#include <Xm/RowColumn.h>
#include "xdir.h"
#include "xfer.h"
#include "list.h"
#include "str.h"
#include "pulldown.h"
#include "view.h"
#define MAXBUF 1024
#define MAXARGV 50
#define VINTERVAL 15*1000
struct decompressor_st {
char *extension;
char *command_line;
};
struct viewdir_link {
struct viewdir_link *next;
struct viewdir_link *prev;
int pid;
int ready_for_removal;
int in_place;
char *dir;
};
static struct decompressor_st decompressor_mappings[] = {
{ ".Z", "uncompress %i" },
{ ".btoa", "atob < %i > %o" },
{ ".gz", "gunzip %i" },
{ ".z", "gunzip %i" },
{ ".uu", "cd %d ; uudecode %i" }
};
static int ndecompressor_mappings = XtNumber(decompressor_mappings);
static struct viewdir_link *viewdir_head = NULL;
static struct viewdir_link *viewdir_tail = NULL;
static int fake_pid = -10;
static int garbage_collector_running = False;
static Widget w_findAgainItem;
static char *view_help_overview[] = {
"You can use the \"Viewer Preferences\" dialog (accessible",
"via the \"Options\" menu) to control whether a file will",
"be displayed in this built-in viewer or in an external",
"viewer of the user's choice (e.g., emacs or xv).\n",
"\n",
"Use the general preference INITIAL MAX VIEWER WIDTH to set",
"the maximum initial width in characters that the built-in",
"viewer takes on. The first part of the file to be viewed",
"is examined to determine an appropriate width to initialize",
"the viewer to. The initial width will not exceed the value",
"of this preference.",
NULL
};
static char *view_help_saving[] = {
"Select SAVE in the FILE menu to pop up a dialog for selecting",
"a directory to save the viewed file in. If the original file",
"was decompressed prior to viewing, it is this decompressed file",
"that will be saved.",
NULL
};
static char *view_help_searching[] = {
"Select FIND in the SEARCH menu to pop up a dialog for initiating",
"a search of the displayed text for a simple text string. Select",
"FIND AGAIN in the SEARCH menu to continue the search once a match",
"has been found",
NULL
};
extern Widget w_toplev;
extern Display *display;
extern struct sl_struct *viewer_mappings;
extern XtAppContext app;
extern struct st_host_info hinfo[];
extern int initial_max_viewer_width;
void cb_internal_viewer_save();
void cb_internal_viewer_close();
void cb_internal_viewer_find();
void cb_internal_viewer_find_again();
void cb_viewer_help_overview();
void cb_viewer_help_saving();
void cb_viewer_help_searching();
void delete_viewer_dir();
void use_external_viewer();
void set_view_dir_remover_timer();
Widget BuildPulldownMenu();
struct view_dialog *create_internal_viewer_dialog();
char *merge_paths();
void cb_view_dir_remover();
char *get_filename();
struct sl_struct *create_null_array_list();
char *entry_to_rel_path();
char *system_name();
char *server_name();
char *decrypt_password();
static MenuItem file_menu[3] = {
{ "Save", &xmPushButtonGadgetClass,
'S', "Ctrl<Key>S", "Ctrl-S", cb_internal_viewer_save, (MenuItem *)NULL,
(Widget *)NULL },
{ "Close", &xmPushButtonGadgetClass,
'C', "Ctrl<Key>C", "Ctrl-C", cb_internal_viewer_close, (MenuItem *)NULL,
(Widget *)NULL },
{ NULL }
};
static MenuItem search_menu[3] = {
{ "Find...", &xmPushButtonGadgetClass,
'F', "Ctrl<Key>F", "Ctrl-F", cb_internal_viewer_find, (MenuItem *)NULL,
(Widget *)NULL },
{ "Find Again", &xmPushButtonGadgetClass,
'A', "Ctrl<Key>G", "Ctrl-G", cb_internal_viewer_find_again,
(MenuItem *)NULL, &w_findAgainItem },
{ NULL }
};
static MenuItem help_menu[4] = {
{ "Overview", &xmPushButtonGadgetClass,
'S', NULL, NULL, cb_viewer_help_overview, (MenuItem *)NULL,
(Widget *)NULL },
{ "Saving Viewed File", &xmPushButtonGadgetClass,
'S', NULL, NULL, cb_viewer_help_saving, (MenuItem *)NULL,
(Widget *)NULL },
{ "Searching for Text String", &xmPushButtonGadgetClass,
'T', NULL, NULL, cb_viewer_help_searching, (MenuItem *)NULL,
(Widget *)NULL },
{ NULL }
};
/*
* create_internal_viewer_dialog - Returns a pointer to structure for a
* dialog for viewing a text file.
*/
struct view_dialog *
create_internal_viewer_dialog()
{
int i;
Arg args[3];
struct view_dialog *view;
Widget widget;
/* Need to create a new dialog */
view = XtNew(struct view_dialog);
/* Create toplevel shell for internal viewer window */
view->w_shell = XtVaCreatePopupShell("view", topLevelShellWidgetClass,
w_toplev, NULL);
/* Attach custom icon */
attach_wm_icon(view->w_shell);
/* Add callback for the WM_DELETE_WINDOW protocol */
add_wm_delete_window_cb(view->w_shell, cb_internal_viewer_close,
(XtPointer)view, True);
/* Create form */
view->w_form = XtVaCreateManagedWidget("form", xmFormWidgetClass,
view->w_shell, NULL);
/* Create menu bar */
i = 0;
XtSetArg(args[i], XmNtopAttachment, XmATTACH_FORM); i++;
XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
view->w_viewMenuBar = XmCreateMenuBar(view->w_form, "viewMenuBar", args ,i);
/* Create File menu */
widget = BuildPulldownMenu(view->w_viewMenuBar, "File", 'F', file_menu,
(XtPointer)view);
/* Create Search menu */
widget = BuildPulldownMenu(view->w_viewMenuBar, "Search", 'S', search_menu,
(XtPointer)view);
view->w_findAgainItem = w_findAgainItem;
/* Create Help Menu */
widget = BuildPulldownMenu(view->w_viewMenuBar, "Help", 'H', help_menu,
(XtPointer)view);
XtVaSetValues(view->w_viewMenuBar, XmNmenuHelpWidget, widget, NULL);
XtManageChild(view->w_viewMenuBar);
/* Create scrolled text window to hold list */
i = 0;
XtSetArg(args[i], XmNeditable, False); i++;
XtSetArg(args[i], XmNeditMode, XmMULTI_LINE_EDIT); i++;
view->w_text = XmCreateScrolledText(view->w_form,
"text", args, i);
XtVaSetValues(XtParent(view->w_text),
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, view->w_viewMenuBar,
XmNtopOffset, 8,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 8,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 8,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 8,
NULL
);
XtManageChild(view->w_text);
fix_vertical_text_sb_color(view->w_text);
fix_horizontal_text_sb_color(view->w_text);
return view;
}
/*
* close_internal_viewer - Close the internal viewer and delete the file
* being viewed (and its directory). Set is_mapped
* to True is viewer is visible, else False.
*/
void
close_internal_viewer(view, is_mapped)
struct view_dialog *view;
int is_mapped;
{
int pid;
/* Pop dialog down */
if (is_mapped)
XtUnmapWidget(view->w_shell);
/* Free memory associated with viewer */
XtFree(view->filename);
XtFree(view->text);
XtFree(view->find.pattern);
/* Delete view directory */
XtVaGetValues(view->w_form, XmNuserData, &pid, NULL);
delete_viewer_dir(pid);
/* Destroy window */
XtDestroyWidget(view->w_shell);
/* Now update directory window menus */
unmanage_file_viewer(view->w_shell);
/* Finally, free view structure */
XtFree((char *)view);
}
/*
* cb_internal_viewer_save - Callback for internal viewer dialog's "Save"
* button.
*/
void
cb_internal_viewer_save(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
char *snk_file;
char *filename;
int src_file_fd;
int snk_file_fd;
char msg[MAXPATHLEN+30];
struct stat status;
long file_len;
long file_index = 0;
char *buf;
int nbytes;
int pid;
struct view_dialog *view = (struct view_dialog *)client_data;
struct viewdir_link *ptr;
/* Consistency check */
XtVaGetValues(view->w_form, XmNuserData, &pid, NULL);
ptr = viewdir_head;
while (ptr) {
if (ptr->pid == pid)
break;
ptr = ptr->next;
}
if (ptr == NULL)
fatal_error("Viewer not present. Unable to save file.");
/* Determine source file name */
parse_path(SYS_UNIX, view->filename, NULL, &filename);
/* Get name for sink file */
if (!(snk_file = get_filename("Save Viewed File",
"Name for saved file:", view->w_shell))) {
XtFree(filename);
return;
}
/* Open source file */
if ((src_file_fd = iopen2(view->filename, O_RDONLY)) < 0) {
report_perror(view->filename);
goto error;
}
/* Get length of file */
if (fstat(src_file_fd, &status) < 0) {
report_perror(view->filename);
close(src_file_fd);
goto error;
}
file_len = status.st_size;
/* Create sink file */
if (unlink(snk_file) == -1)
if (errno != ENOENT) {
report_perror(snk_file);
close(src_file_fd);
goto error;
}
if ((snk_file_fd = iopen3(snk_file, O_CREAT|O_WRONLY, 0644)) < 0) {
report_perror(snk_file);
close(src_file_fd);
goto error;
}
/* Copy file */
buf = XtMalloc(MAXBUF);
while (file_index < file_len) {
nbytes = MIN(file_len-file_index, MAXBUF);
if (iread(src_file_fd, buf, nbytes) != nbytes) {
report_perror(view->filename);
close(src_file_fd);
close(snk_file_fd);
XtFree(buf);
goto error;
}
if (iwrite(snk_file_fd, buf, nbytes) != nbytes) {
report_perror(snk_file);
close(src_file_fd);
close(snk_file_fd);
XtFree(buf);
goto error;
}
file_index += nbytes;
}
close(src_file_fd);
close(snk_file_fd);
XtFree(buf);
/* Success */
write_log("*** Successfully saved file: ");
write_log(filename);
goto done;
error:
sprintf(msg, "Unable to save %s.", filename);
record_and_alert(msg, view->w_shell);
done:
XtFree(snk_file);
XtFree(filename);
}
/*
* cb_internal_viewer_close - Callback for internal viewer dialog's "Close"
* button.
*/
void
cb_internal_viewer_close(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct view_dialog *view = (struct view_dialog *)client_data;
/* Remove dialog from cursor linked list */
remove_dialog_from_list(view->w_shell);
/* Now get rid of viewer */
close_internal_viewer(view, True);
}
/*
* cb_viewer_help_overview - Callback to display "View" dialog's help main
* help message.
*/
void
cb_viewer_help_overview(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct view_dialog *view = (struct view_dialog *)client_data;
help_dialog(view->w_shell, False, "Overview of Built-in Viewer",
view_help_overview);
}
/*
* cb_viewer_help_saving - Callback to display "View" dialog's help package
* for saving file.
*/
void
cb_viewer_help_saving(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct view_dialog *view = (struct view_dialog *)client_data;
help_dialog(view->w_shell, False, "Saving Viewed File", view_help_saving);
}
/*
* cb_viewer_help_searching - Callback to display "View" dialog's help
* package for searching displayed text.
*/
void
cb_viewer_help_searching(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct view_dialog *view = (struct view_dialog *)client_data;
help_dialog(view->w_shell, False, "Searching For Text String",
view_help_searching);
}
/*
* delete_viewer_dir - Delete the temporary view directory associated with
* "pid". (The internal viewers use fake pid's which
* have a negative value.) If there is no directory
* associated with "pid", this routine is a no-op.
* No error is reported if the directory does not
* exist, or if unable to delete the directory or its
* contents.
*/
void
delete_viewer_dir(pid)
int pid;
{
char *dir = NULL;
struct viewdir_link *ptr;
int in_place;
/* Is there a directory associated with the pid? */
ptr = viewdir_head;
while (ptr) {
if (ptr->pid == pid) {
dir = ptr->dir;
in_place = ptr->in_place;
if (ptr == viewdir_head)
viewdir_head = ptr->next;
else
ptr->prev->next = ptr->next;
if (ptr == viewdir_tail)
viewdir_tail = ptr->prev;
else
ptr->next->prev = ptr->prev;
XtFree((char *)ptr);
break;
}
ptr = ptr->next;
}
if (dir == NULL)
return;
/* Delete the directory and all its files */
if (!in_place)
delete_dir_and_its_files(dir);
XtFree(dir);
}
/*
* delete_all_viewer_dirs - Deletes all temporary view directories. This
* function should be called before terminating.
*/
void
delete_all_viewer_dirs()
{
struct viewdir_link *ptr;
/* Delete all directories from list of active view directories */
while (viewdir_head) {
ptr = viewdir_head;
viewdir_head = viewdir_head->next;
if (!ptr->in_place)
delete_dir_and_its_files(ptr->dir);
XtFree(ptr->dir);
XtFree((char *)ptr);
}
}
/*
* use_internal_viewer - Pop up an internal viewer to display "file". The
* view deletes "file" and its directory when it is
* finished displaying it. "dirwin" is used only for
* error reporting purposes. Set "pid" to a phoney
* value that is used to associate the viewer with
* the temporary view directory. If stop button
* pressed, -6 is returned. If error occurs, -1
* is returned.
*/
use_internal_viewer(dirwin, pid, file)
struct dirwin_st *dirwin;
int *pid;
char *file;
{
int fd;
char *name;
struct view_dialog *view;
long file_len;
long file_index = 0;
char *buf;
int nbytes;
struct stat status;
int i;
int width;
int count;
char msg[MAXPATHLEN+20];
/* Generate fake pid */
*pid = --fake_pid;
/* Don't exceed maximum allowable viewers */
if (number_of_internal_viewers() == MAXVIEWERS) {
record_warning("Exceeded maximum allowable number of active viewers");
goto error;
}
/* Open file */
if ((fd = iopen2(file, O_RDONLY)) < 0) {
report_perror(file);
record_warning("Trouble accessing temporary view file");
goto error;
}
/* Get length of file */
if (fstat(fd, &status) < 0) {
record_warning("Trouble accessing temporary view file");
close(fd);
goto error;
}
file_len = status.st_size;
/* Determine viewer width */
buf = XtMalloc(MAXBUF+1);
nbytes = MIN(file_len, MAXBUF);
if (iread(fd, buf, nbytes) != nbytes) {
report_perror(file);
XtFree(buf);
close(fd);
goto error;
}
width = 0;
count = 0;
for (i=0; i<nbytes; i++)
if (buf[i] == '\n') {
width = MAX(width, count);
count = 0;
} else if (buf[i] == '\t')
count = (count/8+1)*8;
else
count++;
if (width)
width = MIN(width, initial_max_viewer_width);
else
width = initial_max_viewer_width;
XtFree(buf);
if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
report_perror(file);
close(fd);
goto error;
}
/* Get a view dialog to work with */
view = create_internal_viewer_dialog();
/* Adjust the width */
XtVaSetValues(view->w_text, XmNcolumns, width, NULL);
/* Associate fake pid with internal viewer */
XtVaSetValues(view->w_form, XmNuserData, *pid, NULL);
/* Remember file name for possible save operation */
view->filename = XtNewString(file);
/* Indicate that other text fields have not been allocated yet */
view->text = NULL;
view->find.pattern = NULL;
/* Grey out the "Find Again" menu item */
XtSetSensitive(view->w_findAgainItem, False);
/* Manage the viewer */
parse_path(SYS_UNIX, file, NULL, &name);
manage_file_viewer(name, view->w_shell);
XtFree(name);
/* Display file */
XmTextSetString(view->w_text, "");
buf = XtMalloc(MAXBUF+1);
while (file_index < file_len) {
if (stop()) {
XtFree(buf);
close_internal_viewer(view, False);
close(fd);
return -6;
}
nbytes = MIN(file_len-file_index, MAXBUF);
if (iread(fd, buf, nbytes) != nbytes) {
report_perror(file);
sprintf(msg, "Unable to view %s", file);
record_and_alert(msg, dirwin->w_shell);
XtFree(buf);
close_internal_viewer(view, False);
close(fd);
return -1;
}
#if !defined(_UNICOS) && !defined __QNX__ /* Compilers don't like toasci() */
for (i=0; i<nbytes; i++)
buf[i] = toascii(buf[i]);
#endif
buf[nbytes] = '\0';
XmTextInsert(view->w_text, XmTextGetLastPosition(view->w_text), buf);
file_index += nbytes;
}
XFlush(display);
XtFree(buf);
/* Close file */
close(fd);
/* Show beginning of file */
XmTextShowPosition(view->w_text, (XmTextPosition)0);
/* Pop up viewer */
XtPopup(view->w_shell, XtGrabNone);
add_dialog_to_list(view->w_shell);
XMapRaised(display, XtWindow(view->w_shell));
return 0;
error:
sprintf(msg, "Unable to view %s", file);
record_and_alert(msg, dirwin->w_shell);
delete_viewer_dir(*pid);
return -1;
}
/*
* view_file - Pop up a viewer to display "file". Set "in_place" to
* True if "file" is a local, uncompressed file. "dirwin"
* is used only for error reporting purposes. Returns -6
* if stop button pressed, otherwise 0.
*/
view_file(dirwin, file, in_place)
struct dirwin_st *dirwin;
char *file;
int in_place;
{
struct viewdir_link *ptr;
char *viewable_file;
char *dir;
int i;
char *ext;
char *q;
int indx;
char *ext_command;
char *extension;
char *command_line;
char *p;
char msg[MAXPATHLEN+20];
int retval;
/* See if file needs to be decompressed */
if (in_place)
viewable_file = XtNewString(file);
else
switch (decompress_file(file, &viewable_file)) {
case -1:
sprintf(msg, "Can't expand %s", file);
record_and_alert(msg, dirwin->w_shell);
viewable_file = XtNewString(file);
break;
case -6:
return -6;
}
/* Add directory which contains file to list of active view directories */
parse_path(SYS_UNIX, viewable_file, &dir, NULL);
ptr = XtNew(struct viewdir_link);
ptr->dir = dir;
ptr->ready_for_removal = False;
ptr->in_place = in_place;
ptr->prev = NULL;
ptr->next = viewdir_head;
if (viewdir_head)
viewdir_head->prev = ptr;
viewdir_head = ptr;
if (viewdir_tail == NULL)
viewdir_tail = ptr;
/* Determine which viewer to use */
indx = -1;
if ((q = strrchr(viewable_file, '.')))
ext = XtNewString(q);
else
ext = XtNewString("");
for (i=0; i<viewer_mappings->nentries; i++) {
ext_command = XtNewString(viewer_mappings->entries[i]);
extension = strtok(ext_command, " ");
if (!strcmp(extension, "OTHERS"))
indx = i;
else if (!strcmp(extension, ext)) {
indx = i;
XtFree(ext_command);
break;
}
XtFree(ext_command);
}
if (indx == -1)
fatal_error("Trouble in view_file.");
XtFree(ext);
/* View file */
set_xfermon_status(STATUS_VIEWER);
XSync(display, 0);
if ((p = strchr(viewer_mappings->entries[indx], ' '))) {
command_line = ++p;
use_external_viewer(dirwin, &(ptr->pid), command_line, viewable_file);
retval = 0;
} else
retval = use_internal_viewer(dirwin, &(ptr->pid), viewable_file);
XtFree(viewable_file);
if (retval == -6)
return -6;
else
return 0;
}
/*
* need_to_decompress - Returns True if "file" is recognized as compressed.
*/
need_to_decompress(file)
char *file;
{
int i;
int len_filename;
int len_ext;
/* Does file extension indicate compression? */
len_filename = strlen(file);
for (i=0; i<ndecompressor_mappings; i++) {
len_ext = strlen(decompressor_mappings[i].extension);
if (len_filename > len_ext && !strcmp(&file[len_filename-len_ext],
decompressor_mappings[i].extension))
return True;
}
return False;
}
/*
* decompress_file - Decompresses "file" and returns the name of the
* decompressed file in "new_file". Returns 0 for
* success, -6 for stop button pushed, and -1 for
* errors. If successful, the original file is
* destroyed. If file is not recognized as compressed,
* the original file name is returned. Use XtFree()
* to free the returned string.
*/
decompress_file(file, new_file)
char *file;
char **new_file;
{
int i;
int len_ext;
int len_filename;
char *output_file;
char *command_line;
int retval;
char *temp;
char *q;
char *dir;
char *entry;
struct sl_struct *dlist;
char *uncompressed_file;
char *full_path;
/* Does file extension indicate compression? */
len_filename = strlen(file);
for (i=0; i<ndecompressor_mappings; i++) {
len_ext = strlen(decompressor_mappings[i].extension);
if (len_filename > len_ext && !strcmp(&file[len_filename-len_ext],
decompressor_mappings[i].extension))
break;
}
if (i == ndecompressor_mappings) {
*new_file = XtNewString(file);
return 0;
}
/* Construct command line for decompressor */
parse_path(SYS_UNIX, file, &dir, &entry);
command_line = XtMalloc(strlen(decompressor_mappings[i].command_line)+
len_filename+MAXPATHLEN+1);
temp = XtNewString(decompressor_mappings[i].command_line);
q = strtok(temp, " ");
strcpy(command_line, q);
while ((q = strtok(NULL, " "))) {
strcat(command_line, " ");
if (!strcmp(q, "%i"))
strcat(command_line, file);
else if (!strcmp(q, "%o")) {
output_file = XtNewString(file);
output_file[len_filename-len_ext] = '\0';
strcat(command_line, output_file);
XtFree(output_file);
} else if (!strcmp(q, "%d"))
strcat(command_line, dir);
else
strcat(command_line, q);
}
XtFree(temp);
/* Decompress file */
set_xfermon_status(STATUS_EXPAND);
XSync(display, 0);
retval = execute(command_line);
XtFree(command_line);
if (retval) {
XtFree(dir);
XtFree(entry);
return retval;
}
/* Determine name of decompressed file */
if (get_dirlist(LOCAL, dir, TABULAR, True, False, False, &dlist) != 0) {
XtFree(dir);
XtFree(entry);
return -1;
}
if (dlist->nentries == 0)
uncompressed_file = NULL;
else if (dlist->nentries == 1)
uncompressed_file = dlist->entries[0];
else {
for (i=0; i<dlist->nentries; i++)
if (strcmp(dlist->entries[i], entry)) {
uncompressed_file = dlist->entries[i];
break;
}
if (i == dlist->nentries)
fatal_error("Trouble in decompress_file()");
}
if (uncompressed_file)
full_path = merge_paths(SYS_UNIX, dir, uncompressed_file);
else
full_path = NULL;
XtFree(entry);
XtFree(dir);
release_array_list(dlist);
if (full_path) {
*new_file = full_path;
return 0;
} else
return -1;
}
/*
* use_external_viewer - Pop up an external viewer to display "file".
* "command_line" is the command to be executed,
* after replacing all instances of "%s" with the
* file name, "%u" with the user name, "%h" with
* the host name, %v with the server name, %y with
* the system name, and %p with the password.
* "file" and its directory are deleted when the
* viewer terminates (or when Xdir terminates).
* "dirwin" is the source directory window. Sets
* "pid" to the external viewer's pid, which is
* used to associate the viewer with the temporary
* temporary view directory.
*/
void
use_external_viewer(dirwin, pid, command_line, file)
struct dirwin_st *dirwin;
int *pid;
char *command_line;
char *file;
{
char *cmd;
int i;
char *argv[MAXARGV+1];
int argc = 0;
int found_percent;
int len;
char ch;
char buf[2];
char *passwrd;
char msg[MAXPATHLEN+60];
/* Interpret command line and create actual command line */
found_percent = False;
len = strlen(command_line);
cmd = XtNewString("");
for (i=0; i<len; i++) {
ch = command_line[i];
if (found_percent) {
switch (ch) {
case 'h':
concat(&cmd, hinfo[dirwin->host].hostname);
break;
case 'u':
concat(&cmd, hinfo[dirwin->host].username);
break;
case 's':
concat(&cmd, file);
break;
case 'y':
concat(&cmd, system_name(hinfo[dirwin->host].system));
break;
case 'v':
concat(&cmd, server_name(hinfo[dirwin->host].server));
break;
case 'p':
if (hinfo[dirwin->host].password) {
passwrd = decrypt_password(hinfo[dirwin->host].password);
concat(&cmd, passwrd);
bzero(passwrd, (int)strlen(passwrd));
XtFree(passwrd);
} else
concat(&cmd, "NO_PASSWORD");
break;
default:
buf[0] = ch;
buf[1] = '\0';
concat(&cmd, buf);
}
found_percent = False;
} else if (ch == '%')
found_percent = True;
else {
buf[0] = ch;
buf[1] = '\0';
concat(&cmd, buf);
}
}
if (found_percent)
concat(&cmd, "%");
/* Parse execute line into tokens */
if ((argv[argc++] = strtok(cmd, " ")) == NULL)
fatal_error("Trouble in use_external_viewer()");
while (argc < MAXARGV && (argv[argc] = strtok(NULL, " ")) != NULL)
argc++;
if (argc == MAXARGV) {
sprintf(msg, "Unable to view %s because of bad viewer command line.",
file);
record_and_alert(msg, dirwin->w_shell);
}
/* Start up view directory garbage collector */
if (!garbage_collector_running) {
set_view_dir_remover_timer();
garbage_collector_running = True;
}
/* Fork and exec */
if ((*pid = fork()) == 0)
if (execvp(argv[0], argv) == -1) {
fprintf(stderr, "\007*** Unable to launch viewer %s: ", argv[0]);
perror("");
exit(-1);
}
XtFree(cmd);
}
/*
* mark_viewdir_for_removal - Flag the directory used by the external
* viewer with "pid" as no longer needed.
*/
void
mark_viewdir_for_removal(pid)
int pid;
{
struct viewdir_link *ptr = viewdir_head;
while (ptr) {
if (ptr->pid == pid) {
ptr->ready_for_removal = True;
return;
}
ptr = ptr->next;
}
}
/*
* cb_view_dir_remover - Callback that removes directories used by external
* viewers when they are no longer needed.
*/
void
cb_view_dir_remover(client_data, id)
XtPointer client_data;
XtIntervalId *id;
{
struct viewdir_link *ptr;
/* Delete flagged directories used by terminated external viewers */
ptr = viewdir_head;
while (ptr)
if (ptr->ready_for_removal) {
delete_viewer_dir(ptr->pid);
ptr = viewdir_head; /* Yes, this is correct */
} else
ptr = ptr->next;
/* Reset timer if there still more active external viewers */
ptr = viewdir_head;
while (ptr) {
if (ptr->pid > 0) {
set_view_dir_remover_timer();
return;
}
ptr = ptr->next;
}
/* Through garbage collecting for now */
garbage_collector_running = False;
}
/*
* set_view_dir_remover_timer - Set the timer to invoke cb_view_dir_remover().
*/
void
set_view_dir_remover_timer()
{
XtAppAddTimeOut(app, (unsigned long)VINTERVAL, cb_view_dir_remover,
(XtPointer)NULL);
}
/*
* cb_view_selected_files - Callback to view selected files.
*/
void
cb_view_selected_files(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
struct sl_struct *list;
int i;
char *temp;
int retval;
/* Start operation */
if (!start_op(True))
return;
/* Form list of selected items to view */
list = create_null_array_list();
for (i=0; i<dirwin->nentries; i++)
if (dirwin->entries[i].state == SELECTED) {
temp = entry_to_rel_path(&dirwin->entries[i]);
add_to_array_list(&list, temp);
XtFree(temp);
}
/* Start file transfers */
retval = init_view(dirwin, list);
release_array_list(list);
}
syntax highlighted by Code2HTML, v. 0.9.1