/***************************************************************************/
/***************************************************************************/
/* */
/* (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. */
/* */
/***************************************************************************/
/***************************************************************************/
#ifdef NEXT
#include <bsd/sys/unistd.h>
#else
#include <unistd.h>
#endif
#include <sys/time.h>
#include <ctype.h>
#include <Xm/TextF.h>
#include <Xm/Protocols.h>
#include <errno.h>
#include "xdir.h"
#include "list.h"
#include "str.h"
#include "history.h"
static int volume = 0;
static char *msg1 = "Operation aborted.\n\nThis directory window might be out of date.\n\nClick on sun icon in toolbar to refresh.";
static char *msg2 = "Operation aborted.\n\nSource and sink directory windows might be out of date.\n\nClick on sun icon in toolbar to refresh a directory window.";
char *entry_to_rel_path();
extern Display *display;
extern Window root_window;
extern int screen;
extern int need_to_save_prefs;
extern int diagnostics;
extern struct dirwin_st *dirwin_head;
extern struct st_host_info hinfo[];
extern int use_last_dir;
/*
* add_wm_delete_window_cb - Add callback for the WM_DELETE_WINDOW protocol
* for the shell that is the ancestor of widget.
* Set "unmap" to True if the window manager should
* unmap the window.
*/
void
add_wm_delete_window_cb(widget, callback, client_data, unmap)
Widget widget;
XtCallbackProc callback;
XtPointer client_data;
int unmap;
{
Atom WM_DELETE_WINDOW;
Widget shell;
/* First find the dialog's shell widget */
for (shell = widget; !XtIsShell(shell); shell = XtParent(shell));
/* Don't want toolkit to handle Close action */
if (unmap)
XtVaSetValues(shell, XmNdeleteResponse, XmUNMAP, NULL);
else
XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL);
/* Install the WM_DELETE_WINDOW atom */
WM_DELETE_WINDOW = XmInternAtom(display, "WM_DELETE_WINDOW", False);
/* Add callback for the WM_DELETE_WINDOW protocol */
XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, callback, client_data);
}
/*
* beep - Emit a beep.
*/
void
beep()
{
XBell(display, volume);
}
/*
* vertical_sb - Returns the vertical scrollbar of the list widget "w_list".
*/
Widget
vertical_sb(widget)
Widget widget;
{
Widget w_vertical_sb;
XtVaGetValues(widget, XmNverticalScrollBar, &w_vertical_sb, NULL);
return w_vertical_sb;
}
/*
* quit - Quit application. w_parent is the widget to center the error
* and question dialogs over.
*/
void
quit(w_parent)
Widget w_parent;
{
/* See if preferences need to be saved */
if (need_to_save_prefs && question_dialog(
"Do you want to save the user preferences?", w_parent)
&& save_prefs()) {
warn("Unable to save user preferences.", w_parent);
}
/* Get rid of any remaining temporary view directories */
delete_all_viewer_dirs();
if (save_history(w_parent) < 0)
warn("Unable to save history.", w_parent);
exit(0);
}
/*
* cb_quit - Callback to quit application.
*/
void
cb_quit(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
/* Start operation */
if (!start_op(False))
return;
if (question_dialog("Do you really want to terminate Xdir?",
dirwin->w_shell))
quit(dirwin->w_shell);
/* End operation */
end_op();
}
/*
* determine_true_path - Returns the actual path of the directory "path"
* in "true_path" (which might differ from "path"
* because of aliases). Set print_error_msg to
* True if error messages are to be written to
* the log. Set "cfetch_ok" to True if it is ok
* to fetch the true path from the cache. Set
* "cstore_ok" to True if it is ok to use the
* true path to update the cache. The caller is
* responsible for freeing "true_path" with XtFree().
* Returns 0 if successful, -3 for broken connection,
* -6 for stop button pressed, and -1 for other
* errors. "path" must be a full path.
*/
determine_true_path(host, path, print_error_msg, cstore_ok, cfetch_ok,
true_path)
int host;
char *path;
int print_error_msg;
int cstore_ok;
int cfetch_ok;
char **true_path;
{
int retval;
/* Can the directory mapping cache be used? */
if (cfetch_ok && (host != LOCAL)) {
if (fetch_truepath_from_cache(host, path, true_path))
return 0;
}
/* Get true path */
if (host == LOCAL) {
if (local_cd(path, print_error_msg) < 0)
return -1;
if (local_pwd(true_path) != 0)
fatal_error("Unable to get local working directory");
} else {
if ((retval = remote_cd(host, path, print_error_msg)) < 0)
return retval;
if ((retval = remote_pwd(host, true_path)) < 0)
return retval;
if (cstore_ok)
add_truepath_to_cache(host, path, *true_path);
}
return 0;
}
/*
* report_client_timeout - Write notice to diagnostics log that the
* "host" has timed out.
*/
void
report_client_timeout(host)
int host;
{
char *msg;
if (diagnostics >= VERBOSE) {
msg = XtMalloc(strlen(hinfo[host].hostname)+100);
sprintf(msg, "Timed out waiting for remote host %s to respond.\n",
hinfo[host].hostname);
write_log(msg);
XtFree(msg);
}
}
/*
* get_host - Return array index to free host structure. Character string
* Fields are initialized to zeros and NULLs. Returns -1 if
* maximum number of hosts exceeded.
*/
get_host()
{
int host;
/* Use first free structure */
for (host=1; host<MAXHOSTS; host++)
if (!hinfo[host].in_use) {
hinfo[host].homedir = NULL;
hinfo[host].hostname = NULL;
hinfo[host].username = NULL;
hinfo[host].password = NULL;
hinfo[host].account = NULL;
hinfo[host].proxy_host = NULL;
hinfo[host].last_reply_time = 0;
hinfo[host].in_use = True;
return host;
}
/* No free structure available */
return -1;
}
/*
* release_host - Free the host structure referenced by "host". Also free
* memory pointed to by some of the fields.
*/
void
release_host(host)
int host;
{
XtFree(hinfo[host].homedir);
XtFree(hinfo[host].hostname);
XtFree(hinfo[host].username);
XtFree(hinfo[host].password);
XtFree(hinfo[host].account);
XtFree(hinfo[host].proxy_host);
hinfo[host].in_use = False;
}
/*
* center_dialog - Center dialog "w_dialog" in center of display.
*/
void
center_dialog(w_dialog)
Widget w_dialog;
{
Screen *screenptr = ScreenOfDisplay(display, screen);
Dimension width;
Dimension height;
int screen_width = WidthOfScreen(screenptr);
int screen_height = HeightOfScreen(screenptr);
/* Center dialog over display */
XtVaGetValues(w_dialog, XmNwidth, &width, XmNheight, &height, NULL);
XtVaSetValues(w_dialog, XmNx, (Position)((screen_width-(int)width)/2), XmNy,
(Position)((screen_height-(int)height)/2), NULL);
}
/*
* postorder_selected_items - Traverse in postorder the directory entry
* specified by "einfo" and add each entry's
* relative path name to the tail of the linked
* specified by "head" and "tail".
*/
void
postorder_selected_items(einfo, head, tail)
struct entry_info *einfo;
struct entry_link **head;
struct entry_link **tail;
{
int i;
struct dirwin_st *dirwin = einfo->dirwin;
struct entry_link *ptr;
if (einfo->expanded) {
for (i=einfo->indx+1; i<dirwin->nentries; i++)
if (dirwin->entries[i].level <= einfo->level)
break;
else if (dirwin->entries[i].level == einfo->level+1) {
postorder_selected_items(&dirwin->entries[i], head, tail);
}
}
if (einfo->state == SELECTED) {
ptr = XtNew(struct entry_link);
ptr->entry = entry_to_rel_path(einfo);
ptr->next = NULL;
if (*head == NULL) {
*head = ptr;
*tail = ptr;
} else {
(*tail)->next = ptr;
*tail = ptr;
}
}
}
/*
* cb_disconnect - Callback to disconnect host.
*/
void
cb_disconnect(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
struct dirwin_st *dwin;
struct dirwin_st *next;
int host;
static char *msg = "Disconnecting from this host will terminate Xdir. Continue disconnecting?";
/* Start operation */
if (!start_op(False))
return;
/* Clear error flag */
raise_okflag();
/* Will disconnecting host cause application to terminate? */
dwin = dirwin_head;
while (dwin && (dwin->host == dirwin->host))
dwin = dwin->next;
if (dwin == NULL) {
if (question_dialog(msg, dirwin->w_shell))
quit(dirwin->w_shell);
else {
end_op();
return;
}
}
/* Close all directory windows associated with host */
host = dirwin->host;
dwin = dirwin_head;
while (dwin) {
next = dwin->next;
if (dwin->host == host)
close_directory_window(dwin);
dwin = next;
}
/* End operation */
end_op();
}
/*
* cb_map_dialog - Map the dialog (indicated by "widget") over the window
* specified by "client_data".
*/
void
cb_map_dialog(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Window window = (Window)client_data;
Window child;
XWindowAttributes xwa;
Dimension w;
Dimension h;
int x;
int y;
/* Get dialog's dimensions */
XtVaGetValues(widget, XmNwidth, &w, XmNheight, &h, NULL);
/* Get bottom window's geometry */
if (!XGetWindowAttributes(display, window, &xwa))
fatal_error("Bug in cb_map_dialog()");
XTranslateCoordinates(display, window, root_window, 0, 0, &x, &y, &child);
/* Center dialog above bottom window */
XtVaSetValues(widget, XmNx, x+(int)(xwa.width-w)/2, XmNy,
y+(int)(xwa.height-h)/2, NULL);
}
/*
* create_unique_name - Create a unique file name by, if necessary,
* prefixing name with "." followed by a integer
* that ranges from 1 to 99. If successful, a
* pointer to the new name is returned. The
* memory is in a static buffer local to this
* routine. If unsuccessful, NULL is returned.
* "file_path" should be the full path name of
* the file.
*/
char *
create_unique_name(file_path)
char *file_path;
{
static char new_path[MAXPATHLEN+1];
int i;
/* First see if supplied name is unique */
if (access(file_path, 0) < 0) {
if (errno == ENOENT) {
strcpy(new_path, file_path);
return new_path;
} else
return NULL;
}
/* Try concatenating a "." followed by an integer */
for (i=1; i<100; i++) {
sprintf(new_path, "%s.%d", file_path, i);
if (access(new_path, 0) < 0) {
if (errno == ENOENT)
return new_path;
else
return NULL;
}
}
/* Ran out of suffices */
return NULL;
}
/*
* can_create_sinkfile - Returns True if a writable file specifed by
* "snk_path" can be created; else returns False.
*/
can_create_sinkfile(snk_path)
char *snk_path;
{
char *snk_dir;
parse_path(SYS_UNIX, snk_path, &snk_dir, NULL);
if (access(snk_path, W_OK) < 0)
if (errno == ENOENT) { /* File does not exist */
if (access(snk_dir, W_OK) < 0) {
report_perror(snk_path);
XtFree(snk_dir);
return False;
}
} else if (errno == EACCES) { /* Permission denied */
if (access(snk_dir, W_OK) < 0) {
report_perror(snk_path);
XtFree(snk_dir);
return False;
}
if (chmod(snk_path, 0600) < 0) {
report_perror(snk_path);
XtFree(snk_dir);
return False;
}
} else {
report_perror(snk_path);
XtFree(snk_dir);
return False;
}
XtFree(snk_dir);
return True;
}
/*
* cb_iconify_all - Callback to iconify all top-level windows.
*/
void
cb_iconify_all(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
/* Start operation */
if (!start_op(False))
return;
/* Iconify all the windows */
iconify_diag_window();
iconify_lprefs_window();
iconify_vprefs_window();
iconify_fprefs_window();
iconify_gprefs_window();
iconify_directory_windows();
iconify_file_viewer_windows();
/* End operation */
end_op();
}
/*
* cb_deiconify_all - Callback to de-iconify all top-level windows.
*/
void
cb_deiconify_all(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
/* Start operation */
if (!start_op(False))
return;
/* Deiconify all the windows */
deiconify_diag_window();
deiconify_lprefs_window();
deiconify_vprefs_window();
deiconify_fprefs_window();
deiconify_gprefs_window();
deiconify_directory_windows();
deiconify_file_viewer_windows();
/* End the operation */
end_op();
}
/*
* cvt_to_lower - Convert string to lower case.
*/
void
cvt_to_lower(str)
char *str;
{
int i;
for (i=strlen(str); i>=0; i--)
str[i] = tolower(str[i]);
}
/*
* cvt_to_upper - Convert string to upper case.
*/
void
cvt_to_upper(str)
char *str;
{
int i;
for (i=strlen(str); i>=0; i--)
str[i] = toupper(str[i]);
}
/*
* add_commas - Converts "value" to a string, with each group of digits
* delimited with a comma (e.g., long integer 1234567 is
* converted to the string "1,234,567". Call XtFree() to
* free returned string.
*/
char *
add_commas(value)
long value;
{
char buf[25];
char *number;
int negative = False;
int ndigits;
int ncommas;
int nlead;
int i;
int j;
/* Easier to work with positive integer */
if (value < 0) {
negative = True;
value = -value;
}
/* Convert integer to string and add commas */
sprintf(buf, "%ld", value);
ndigits = strlen(buf);
ncommas = (ndigits-1)/3;
if (negative) {
number = XtMalloc(ndigits+ncommas+2);
number[0] = '-';
j = 1;
} else {
number = XtMalloc(ndigits+ncommas+1);
j = 0;
}
nlead = ndigits-((ndigits-1)/3)*3;
for (i=0; i<nlead; i++)
number[j++] = buf[i];
while (i < ndigits) {
number[j++] = ',';
number[j++] = buf[i++];
number[j++] = buf[i++];
number[j++] = buf[i++];
}
number[j] = '\0';
return number;
}
/*
* cstring_to_text - Convert compound string "string" to a null-delimited
* string, which is returned. Call XtFree() to free
* returned string.
*/
char *
cstring_to_text(string)
XmString string;
{
char *text;
#ifdef XmFONTLIST_DEFAULT_TAG /* Motif 1.2.x */
if (!XmStringGetLtoR(string, XmFONTLIST_DEFAULT_TAG, &text))
#else /* Motif 1.1.x */
if (!XmStringGetLtoR(string, XmSTRING_DEFAULT_CHARSET, &text))
#endif
fatal_error("Trouble in cstring_to_text()");
return text;
}
/*
* text_to_cstring - Convert null-delimited string "text" to a compound
* string, which is returned. Call XmStringFree() to
* free returned string.
*/
XmString
text_to_cstring(text)
char *text;
{
#ifdef XmFONTLIST_DEFAULT_TAG /* Motif 1.2.x */
return XmStringCreateLtoR(text, XmFONTLIST_DEFAULT_TAG);
#else /* Motif 1.1.x */
return XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
#endif
}
/*
* traverse_to_widget - Traverse to specified widget.
*/
void
traverse_to_widget(widget)
Widget widget;
{
/* Yep, got to do this twice */
XmProcessTraversal(widget, XmTRAVERSE_CURRENT);
XmProcessTraversal(widget, XmTRAVERSE_CURRENT);
}
/*
* starting_dir - Returns the path of the first directory to be entered
* after connecting to "host". Returns 0 if successful
* -3 for broken connection, -6 for stop button pushed,
* and -1 for other errors. If successful, the caller
* is responsible for calling XtFree() to free returned
* string, "path".
*/
starting_dir(host, path)
int host;
char **path;
{
struct sl_struct *list;
int retval;
/* Use last referenced directory if requested */
if (use_last_dir) {
retrieve_history(DIRECTORY, hinfo[host].hostname, &list, False);
if (list->nentries > 0) {
retval = determine_true_path(host, list->entries[0], False, False,
False, path);
release_array_list(list);
if (retval != -1)
return retval;
} else
release_array_list(list);
}
/* Default to home directory */
*path = XtNewString(hinfo[host].homedir);
return 0;
}
/*
* cmp_long_vms_entries - Compares two long VMS entries (basically the
* first blank-delimited tokens in "string1" and
* "string2". Returns negative value if "string1"
* is less than "string2, 0 if "string1" equals
* string2, and positive value if "string1" is
* greater than "string2".
*/
cmp_long_vms_entries(string1, string2)
char *string1;
char *string2;
{
char str1[MAXPATHLEN+1];
char str2[MAXPATHLEN+1];
/* Make copies of strings because strtok() modifies input string */
strcpy(str1, string1);
strcpy(str2, string2);
/* Strip off entry names */
if (!strtok(str1, " \t") || !strtok(str2, " \t"))
fatal_error("Bug in cmp_long_vms_entries()");
/* Make comparison */
return strcmp(str1, str2);
}
/*
* cmp_symbol_entries - Compares two strings, starting with the second
* character of each string. Returns negative
* value if "string1" is less than "string2,
* 0 if "string1" equals "string2", and positive
* value if "string1" is greater than "string2".
*/
cmp_symbol_entries(string1, string2)
char *string1;
char *string2;
{
return strcmp(string1+1, string2+1);
}
/*
* sort_symbol_entries - Sort the "n" strings pointed to by the array of
* character pointers "s". If a string ends with
* '@', '*', '=', or '/', ignore the last character
* when comparing two strings.
*/
void
sort_symbol_entries(s, n)
char *s[];
int n;
{
int i;
int len;
char *p;
char ch;
/* Move special character to first position in string, else use space */
for (i=0; i<n; i++) {
len = strlen(s[i]);
switch (s[i][len-1]) {
case '@':
case '*':
case '=':
case '/':
p = XtMalloc(len+1);
p[0] = s[i][len-1];
s[i][len-1] = '\0';
break;
default:
p = XtMalloc(len+2);
p[0] = ' ';
}
strcpy(p+1, s[i]);
XtFree(s[i]);
s[i] = p;
}
/* Sort the entries */
quicksort(s, n, cmp_symbol_entries);
/* Move special character back to end of each string */
for (i=0; i<n; i++) {
ch = s[i][0];
p = s[i];
while (*(p+1)) {
*p = *(p+1);
p++;
}
if (ch != ' ')
*p++ = ch;
*p = '\0';
}
}
/*
* add_timevals - Add times "time1" and "time2" to produce "total_time".
* All times are represented using the standard timeval
* structure.
*/
void
add_timevals(time1, time2, total_time)
struct timeval *time1;
struct timeval *time2;
struct timeval *total_time;
{
long carry_secs;
total_time->tv_sec = time1->tv_sec+time2->tv_sec;
total_time->tv_usec = time1->tv_usec+time2->tv_usec;
carry_secs = total_time->tv_usec/1000000;
total_time->tv_usec = total_time->tv_usec-1000000*carry_secs;
total_time->tv_sec += carry_secs;
}
/*
* cmp_timevals - Returns negative value if "time1" is less than "time2",
* 0 if "time1" equals "time2", and positive value if
* "time1" is greater than "time2". All times are
* represented using the standard timeval structure.
*/
cmp_timevals(time1, time2)
struct timeval *time1;
struct timeval *time2;
{
if (time1->tv_sec > time2->tv_sec)
return 1;
else if (time1->tv_sec < time2->tv_sec)
return -1;
else if (time1->tv_usec > time2->tv_usec)
return 1;
else if (time1->tv_usec < time2->tv_usec)
return -1;
else
return 0;
}
/*
* dirwin_out_of_date_alert - Alert the user that the directory window might
* out of date because of the aborted operation.
* The alert dialog is placed over the directory
* window specified by "dirwin".
*/
void
dirwin_out_of_date_alert(dirwin)
struct dirwin_st *dirwin;
{
info_dialog(msg1, dirwin->w_shell);
}
/*
* dirwins_out_of_date_alert - Alert the user that the directory windows might
* out of date because of the aborted operation.
* The alert dialog is placed over the directory
* window specified by "dirwin".
*/
void
dirwins_out_of_date_alert(dirwin)
struct dirwin_st *dirwin;
{
info_dialog(msg2, dirwin->w_shell);
}
/*
* set_textfield - Set the textfield widget "widget" to the character
* string "string". If the textfield already has this
* value, this routine is a no-op (to prevent the widget
* from blinking).
*/
void
set_textfield(widget, string)
Widget widget;
char *string;
{
char *old_string;
old_string = XmTextFieldGetString(widget);
if (strcmp(string, old_string))
XmTextFieldSetString(widget, string);
XtFree(old_string);
}
syntax highlighted by Code2HTML, v. 0.9.1