saving URL's

dcmartin@library.ucsf.edu (David C. Martin)
Message-id: <199307152348.AA18502@library.ucsf.edu>
From: dcmartin@library.ucsf.edu (David C. Martin)
Organization: UCSF Center for Knowledge Management
Email: dcmartin@ckm.ucsf.edu or uunet!dcmartin
Phone: 415/476-6111
Fax: 415/476-4653
To: www-talk@library.ucsf.edu
Precedence: special-delivery
Subject: saving URL's
Date: Thu, 15 Jul 1993 16:44:36 PDT
Sender: dcmartin@library.ucsf.edu
Status: RO
I have wanted to be able to save URL's for some time and have now hacked
Xmosaic to support this feature.  This feature allows you to find a
document via navigation and then save the URL for that document in the
UNIX filesystem as a symbolic link (and, of course, open the local file
and have it interpreted as a URL).

Comments, bug fixes, etc... appreciated.

dcm

BTW: You need to -DCKM and add search.[co] to the Makefile.
--------
#!/bin/sh
# This is a shell archive (produced by shar 3.50)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 07/15/1993 23:42 UTC by dcmartin@brasil
# Source directory /local/dcmartin/work/xmosaic-1.2/src
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2909 -r--r--r-- search.c
#   9163 -rw-r--r-- gui2.c-dif
#
# ============= search.c ==============
if test -f 'search.c' -a X"$1" != X"-c"; then
	echo 'x - skipping search.c (File already exists)'
else
echo 'x - extracting search.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'search.c' &&
/* 
X * search.c -- alternate file search procedure
X *
X * Replaces the default file search procedure of a FileSelectionBoxWidget.
X * The default procedure skips over any matching symbolic links which
X * cannot be resolved (don't seem to point anywhere).
X *
X * This search procedure checks symbolic links (which match the given filter)
X * to see if they might encode a URL (Universal Resource Locator).  Such links
X * are included in the resulting file list along with any other matching files.
X *
X *
X */
X
#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/FileSB.h>
#include <Xm/DialogS.h>
#include <Xm/PushBG.h>
#include <Xm/PushB.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
X
extern char *re_comp();
extern int re_exec();
X
void alt_file_search_proc(fs, cbs)
Widget	fs;
XXmFileSelectionBoxCallbackStruct*	cbs;
{
X    DIR*		dir;
X    char*		dirbuf;
X    char*		patbuf;
X    char*		expbuf = alloca(BUFSIZ);
X    int			i = 0;
X    
X    /* convert to strings */
X    if (XmStringGetLtoR(cbs->dir, XmSTRING_DEFAULT_CHARSET, &dirbuf)) {
X	if (XmStringGetLtoR(cbs->pattern, XmSTRING_DEFAULT_CHARSET, &patbuf)) {
X	    /* fix up the regular expression */
X	    expbuf[i++] = '^';
X	    while (*patbuf) {
X		switch(*patbuf) {
X		case '*':
X		    expbuf[i++] = '.';
X		    expbuf[i++] = '*';
X		    break;
X		case '.':
X		    expbuf[i++] = '\\';
X		    expbuf[i++] = '.';
X		    break;
X		default:
X		    expbuf[i++] = *patbuf;
X		    break;
X		}
X		++patbuf;
X	    }
X	    expbuf[i++] = '$';
X	    expbuf[i] = '\0';
X    
X	    /* compile the reg exp */
X	    if (re_comp(expbuf) == NULL) {
X		/* open the dirbuf */
X		if ((dir = opendir(dirbuf)) != NULL) {
X		    struct dirent*	ent;
X		    static int		count = 0;
X		    static XmString	names[256];
X
X		    while (count > 0) XmStringFree(names[count--]);
X		    while ((ent = readdir(dir)) != (struct dirent*) NULL) {
X			if (re_exec(ent->d_name) == 1) {
X			    char		path[MAXPATHLEN];
X			    struct stat	stat_buf;
X
X			    (void) strcpy(path, dirbuf);
X			    (void) strcat(path, ent->d_name);
X			    if (lstat(path, &stat_buf) == 0) {
X				if (S_ISREG(stat_buf.st_mode) || 
X				    S_ISLNK(stat_buf.st_mode)) {
X				    /* remember matching entries */
X				    names[count] = XmStringCreateSimple(path);
X				    /* only take the first 256 */
X				    if (++count == 256) break;
X				}
X			    } else {
X				perror("lstat");
X			    }
X			}
X		    }
X		    /* update the file list */
X		    if (count > 0) {
X			XtVaSetValues(fs,
X				      XmNfileListItems,      names,
X				      XmNfileListItemCount,  count,
X				      XmNdirSpec,            names[0],
X				      XmNdirectoryValid,     True,
X				      XmNlistUpdated,        True,
X				      NULL);
X			return;
X		    }
X		}
X	    }
X	}
X    }
X    XtVaSetValues(fs,
X		  XmNfileListItems,      NULL,
X		  XmNfileListItemCount,  0,
X		  XmNdirectoryValid,     False,
X		  XmNlistUpdated,        False,
X		  NULL);
}
SHAR_EOF
chmod 0444 search.c ||
echo 'restore of search.c failed'
Wc_c="`wc -c < 'search.c'`"
test 2909 -eq "$Wc_c" ||
	echo 'search.c: original size 2909, current size' "$Wc_c"
fi
# ============= gui2.c-dif ==============
if test -f 'gui2.c-dif' -a X"$1" != X"-c"; then
	echo 'x - skipping gui2.c-dif (File already exists)'
else
echo 'x - extracting gui2.c-dif (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gui2.c-dif' &&
*** 1.1	1993/06/30 19:33:21
--- gui2.c	1993/07/15 00:35:44
***************
*** 54,59 ****
--- 54,76 ----
X  
X  #include "mosaic.h"
X  
+ /*
+  * Include these for symbolic link encoded URL's
+  */
+ #ifdef CKM
+ #include <sys/stat.h>
+ #include <sys/param.h>
+ #endif
+ 
+ #ifdef CKM
+ 
+ /*
+  * Alternate file searching procedure
+  */
+ extern void	alt_file_search_proc();
+ 
+ #endif
+ 
X  #include <Xm/LabelG.h>
X  #include <Xm/PushB.h>
X  #include <Xm/ScrolledW.h>
***************
*** 74,80 ****
X  
X  typedef enum
X  {
!   mo_plaintext = 0, mo_formatted_text, mo_html, mo_latex, mo_postscript,
X    mo_mif
X  } mo_format_token;
X  
--- 91,102 ----
X  
X  typedef enum
X  {
!   mo_plaintext = 0, 
!   mo_url,
!   mo_formatted_text, 
!   mo_html, 
!   mo_latex, 
!   mo_postscript,
X    mo_mif
X  } mo_format_token;
X  
***************
*** 83,88 ****
--- 105,111 ----
X    { "Plain Text",     mo_plaintext,      XmxSet },
X    { "Formatted Text", mo_formatted_text, XmxNotSet },
X    { "PostScript",     mo_postscript,     XmxNotSet },
+   { "URL",            mo_url,            XmxNotSet },
X    { "HTML",           mo_html,           XmxNotSet },
X    { "LaTeX Source",   mo_latex,          XmxNotSet },
X    { "Frame MIF",      mo_mif,            XmxNotSet },
***************
*** 102,172 ****
X  
X  static XmxCallback (save_win_cb)
X  {
!   char *fname = (char *)malloc (sizeof (char) * 128);
!   FILE *fp;
!   mo_window *win = mo_fetch_window_by_id 
!     (XmxExtractUniqid ((int)client_data));
! 
!   mo_busy ();
! 
!   XtUnmanageChild (win->save_win);
!   
!   XmStringGetLtoR (((XmFileSelectionBoxCallbackStruct *)call_data)->value,
!                    XmSTRING_DEFAULT_CHARSET,
!                    &fname);
! 
!   if (can_instrument && win->instrument_usage)
!     mo_inst_register_action (mo_inst_save, win->current_node->url);
X  
!   fp = fopen (fname, "w");
!   if (!fp)
!     {
!       XmxMakeErrorDialog (win->save_win, 
!                           "Unable to save document.", "Save Error");
!       XtManageChild (Xmx_w);
!     }
!   else
!     {
!       if (win->save_format == mo_plaintext)
!         {
!           char *text = HTMLGetText (win->view, 0);
!           if (text)
!             {
!               fputs (text, fp);
!               free (text);
!             }
!         }
!       else if (win->save_format == mo_formatted_text)
!         {
!           char *text = HTMLGetText (win->view, 1);
!           if (text)
!             {
!               fputs (text, fp);
!               free (text);
!             }
!         }
!       else if (win->save_format == mo_postscript)
!         {
!           char *text = HTMLGetText (win->view, 2);
!           if (text)
!             {
!               fputs (text, fp);
!               free (text);
!             }
!         }
!       else if (win->current_node->text)
!         {
!           /* HTML source */
!           fputs (win->current_node->text, fp);
!         }
!       fclose (fp);
!     }
X  
!   mo_not_busy ();
X  
!   free (fname);
X    
!   return;
X  }
X  
X  static XmxCallback (format_optmenu_cb)
--- 125,191 ----
X  
X  static XmxCallback (save_win_cb)
X  {
!     char*	fname = (char*) calloc(128, sizeof (char));
!     FILE*	fp;
!     mo_window*	win;
X  
!     win = mo_fetch_window_by_id(XmxExtractUniqid((int)client_data));
X  
!     mo_busy ();
X  
!     XtUnmanageChild (win->save_win);
X    
!     XmStringGetLtoR (((XmFileSelectionBoxCallbackStruct *)call_data)->value,
! 		     XmSTRING_DEFAULT_CHARSET,
! 		     &fname);
! 
!     if (can_instrument && win->instrument_usage)
! 	mo_inst_register_action (mo_inst_save, win->current_node->url);
! 
!     if (win->save_format == mo_url) {
! 	/*
! 	 * Save symbolic link encoded URL for document
! 	 */
! 	if (symlink(win->current_node->url, fname) != 0) {
! 	    XmxMakeErrorDialog (win->save_win, 
! 				"Unable to save document.", "Save Error");
! 	    XtManageChild (Xmx_w);
! 	}
!     } else {
! 
! 	if ((fp = fopen (fname, "w")) == NULL) {
! 	    XmxMakeErrorDialog (win->save_win, 
! 				"Unable to save document.", "Save Error");
! 	    XtManageChild (Xmx_w);
! 	} else {
! 	    if (win->save_format == mo_plaintext) {
! 		char *text = HTMLGetText (win->view, 0);
! 		if (text) {
! 		    fputs (text, fp);
! 		    free (text);
! 		}
! 	    } else if (win->save_format == mo_formatted_text) {
! 		char *text = HTMLGetText (win->view, 1);
! 		if (text) {
! 		    fputs (text, fp);
! 		    free (text);
! 		}
! 	    } else if (win->save_format == mo_postscript) {
! 		char *text = HTMLGetText (win->view, 2);
! 		if (text) {
! 		    fputs (text, fp);
! 		    free (text);
! 		}
! 	    } else if (win->current_node->text) {
! 		/* HTML source */
! 		fputs (win->current_node->text, fp);
! 	    }
! 	    fclose (fp);
! 	}
!     }
!     mo_not_busy ();
!     free (fname);
!     return;
X  }
X  
X  static XmxCallback (format_optmenu_cb)
***************
*** 189,194 ****
--- 208,223 ----
X          (win->base, "NCSA Mosaic: Save Document", "Name for saved document:",
X           save_win_cb, 0);
X  
+ #ifdef CKM
+ 	/*
+ 	 * Replace the current file-search procedure with one which
+ 	 * knows about symbolic-link-encoded-URL's
+ 	 */
+ 	XtVaSetValues (win->save_win, 
+ 		       XmNfileSearchProc, (XtArgVal) &alt_file_search_proc,
+ 		       NULL);
+ #endif
+ 
X        /* This makes a frame as a work area for the dialog box. */
X        XmxSetArg (XmNmarginWidth, 5);
X        XmxSetArg (XmNmarginHeight, 5);
***************
*** 298,344 ****
X  
X  static XmxCallback (open_local_win_cb)
X  {
!   char *fname = (char *)malloc (sizeof (char) * 128);
!   char *url;
!   mo_window *win = mo_fetch_window_by_id (XmxExtractUniqid ((int)client_data));
! 
!   XtUnmanageChild (win->open_local_win);
!   
!   XmStringGetLtoR (((XmFileSelectionBoxCallbackStruct *)call_data)->value,
!                    XmSTRING_DEFAULT_CHARSET,
!                    &fname);
X  
!   url = (char *)malloc 
!     ((strlen (fname) + strlen (shortmachine) + 16) * sizeof (char));
!   sprintf (url, "file://%s%s\0", shortmachine, fname);
!   if (url[strlen(url)-1] == '/')
!     url[strlen(url)-1] = '\0';
!   mo_load_window_text (win, url, NULL);
X  
!   free (fname);
! 
!   return;
X  }
X  
X  mo_status mo_post_open_local_window (mo_window *win)
X  {
!   XmxSetUniqid (win->id);
!   if (!win->open_local_win)
!     {
!       Widget frame, workarea, format_label;
! 
!       win->open_local_win = XmxMakeFileSBDialog
!         (win->base, "NCSA Mosaic: Open Local Document", 
!          "Name of local document to open:",
!          open_local_win_cb, 0);
X      }
!   else
!     {
!       XmFileSelectionDoSearch (win->open_local_win, NULL);
!     }
!   
!   XmxManageRemanage (win->open_local_win);
!   return mo_succeed;
X  }
X  
X  /* ----------------------- mo_post_open_window ------------------------ */
--- 327,410 ----
X  
X  static XmxCallback (open_local_win_cb)
X  {
!     char*	fname = calloc(128, sizeof(char));
!     char*	url;
!     mo_window*	win;
! #ifdef CKM
!     struct stat	stat_buf;
!     int		lnksiz = 0, bufsiz = MAXPATHLEN;
! #endif
X  
!     win = mo_fetch_window_by_id(XmxExtractUniqid ((int)client_data));
X  
!     XtUnmanageChild (win->open_local_win);
!   
!     XmStringGetLtoR (((XmFileSelectionBoxCallbackStruct *)call_data)->value,
! 		     XmSTRING_DEFAULT_CHARSET,
! 		     &fname);
! 
! #ifdef CKM
!     /*
!      * If the file is a symbolic link that doesn't seem to point
!      * anywhere, then assume it is a symbolic link encoded URL
!      */
!     if (lstat(fname, &stat_buf) == 0 && 
! 	S_ISLNK(stat_buf.st_mode) && 
! #ifndef AIX
! 	((bufsiz = stat_buf.st_size) > 0) &&
! #endif
! 	stat(fname, &stat_buf) == -1) {
! 	char*	buf = calloc(bufsiz, sizeof(char));
! 
! 	if ((lnksiz = readlink(fname, buf, bufsiz)) < 0) {
! 	    perror("readlink");
! 	    (void) free(buf);
! 	    return;
! 	} else {
! 	    url = (char*) calloc(lnksiz + 1, sizeof(char));
! 	    buf[lnksiz] = (char) NULL;
! 	    (void) strcpy(url, buf);
! 	}
! 	(void) free(buf);
!     } else {
! #endif
! 	url = (char*) malloc((strlen(fname) +
! 			      strlen(shortmachine) + 16) * sizeof(char));
! 	sprintf (url, "file://%s%s\0", shortmachine, fname);
! 	if (url[strlen(url)-1] == '/') url[strlen(url)-1] = '\0';
! #ifdef CKM
!     }
! #endif
!     (void) free(fname);
!     mo_load_window_text (win, url, NULL);
!     return;
X  }
X  
X  mo_status mo_post_open_local_window (mo_window *win)
X  {
!     XmxSetUniqid (win->id);
!     if (!win->open_local_win) {
! 	Widget		frame, workarea, format_label;
! 
! 	win->open_local_win = 
! 	    XmxMakeFileSBDialog(win->base,
! 				"NCSA Mosaic: Open Local Document", 
! 				"Name of local document to open:",
! 				open_local_win_cb, 0);
! #ifdef CKM
! 	/*
! 	 * Replace the current file-search procedure with one which
! 	 * knows about symbolic-link-encoded-URL's
! 	 */
! 	XtVaSetValues (win->open_local_win, 
! 		       XmNfileSearchProc, (XtArgVal) &alt_file_search_proc,
! 		       NULL);
! #endif
!     } else {
! 	XmFileSelectionDoSearch (win->open_local_win, NULL);
X      }
!     XmxManageRemanage (win->open_local_win);
!     return mo_succeed;
X  }
X  
X  /* ----------------------- mo_post_open_window ------------------------ */
SHAR_EOF
chmod 0644 gui2.c-dif ||
echo 'restore of gui2.c-dif failed'
Wc_c="`wc -c < 'gui2.c-dif'`"
test 9163 -eq "$Wc_c" ||
	echo 'gui2.c-dif: original size 9163, current size' "$Wc_c"
fi
exit 0