444 lines
10 KiB
C
444 lines
10 KiB
C
|
/*
|
||
|
* Copyright (c) 1993 by the University of Southern California
|
||
|
*
|
||
|
* For copying and distribution information, please see the file
|
||
|
* <usc-copyr.h>.
|
||
|
*
|
||
|
* The menu API and client were written by Kwynn Buess (buess@isi.edu)
|
||
|
*/
|
||
|
|
||
|
#include <usc-copyr.h>
|
||
|
|
||
|
/*
|
||
|
* Future directions: this code needs to change so that it's internally
|
||
|
* consistent. It should always use popen() or always fork, etc.
|
||
|
|
||
|
Noted. Partially done. See my message. -buess
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/types.h> /* for lseek() */
|
||
|
#include <unistd.h> /* for lseek() */
|
||
|
#include <pfs.h>
|
||
|
#include <stdlib.h> /* For malloc and free */
|
||
|
#include "config.h"
|
||
|
#include "p_menu.h"
|
||
|
#include "menu.h"
|
||
|
char *getenv();
|
||
|
|
||
|
/* We include <pmachine.h> which, on SOLARIS, will make up for deficiencies in
|
||
|
stdio.h (fdopen() undeclared, popen() undeclared. */
|
||
|
#include <pmachine.h>
|
||
|
|
||
|
static void save_file(int fd);
|
||
|
static void mail_file(int fd);
|
||
|
|
||
|
static void pipe_output_to_subprogram(int fd, char *subprogram, char *error_msg);
|
||
|
|
||
|
static void run_subsystem_with_fd_as_stdin(int fd, char *subprogram, char *error_msg);
|
||
|
static int retrieve_link(VLINK vl);
|
||
|
|
||
|
void
|
||
|
open_and_display(VLINK vl)
|
||
|
{
|
||
|
int fd;
|
||
|
int fd_dup;
|
||
|
int get_option();
|
||
|
int option;
|
||
|
static char *pager; /* pager to use */
|
||
|
|
||
|
if (!pager) {
|
||
|
pager = getenv("PAGER");
|
||
|
if (!pager)
|
||
|
pager = "more";
|
||
|
}
|
||
|
|
||
|
fd = retrieve_link(vl); /* retrieve link, print error messages if
|
||
|
failure. */
|
||
|
if (fd < 0) return;
|
||
|
run_subsystem_with_fd_as_stdin(fd,pager,"unable to display file");
|
||
|
|
||
|
/* Finish work after display. */
|
||
|
if(lseek(fd, (off_t) 0, SEEK_SET)) {
|
||
|
fprintf(stderr, "lseek failed: this should never happen.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (;;) {
|
||
|
printf("\n\nPress <RETURN> to continue, <m> to mail, <s> to save, or <p> to print:");
|
||
|
option = get_option();
|
||
|
if (option == -1)
|
||
|
break;
|
||
|
if (option == 's') {
|
||
|
save_file(fd);
|
||
|
break;
|
||
|
} else if (option == 'm') {
|
||
|
mail_file(fd);
|
||
|
break;
|
||
|
} else if (option == 'p') {
|
||
|
run_subsystem_with_fd_as_stdin(fd,PRINT_PROGRAM,
|
||
|
"Unable to print file");
|
||
|
break;
|
||
|
} else
|
||
|
continue;
|
||
|
}
|
||
|
close(fd);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Pass it an open file descriptor.
|
||
|
It might close it internally (due to the way fdopen() works), but caller
|
||
|
should also run close() just to be sure. */
|
||
|
|
||
|
/* Pass it an open file descriptor.
|
||
|
Caller takes responsibility for closing it.
|
||
|
*/
|
||
|
static
|
||
|
void
|
||
|
save_file(int fd)
|
||
|
{
|
||
|
char *name;
|
||
|
FILE *org_fp;
|
||
|
FILE *save_fp;
|
||
|
int temp = 25;
|
||
|
|
||
|
char *get_line();
|
||
|
|
||
|
printf("\n\nEnter save file name: ");
|
||
|
name = get_line();
|
||
|
|
||
|
if (name == NULL)
|
||
|
return;
|
||
|
|
||
|
save_fp = fopen(name, "w");
|
||
|
while (save_fp == NULL) {
|
||
|
printf("Error opening : Enter new name or <Enter> to cancel: ");
|
||
|
stfree(name);
|
||
|
name = get_line();
|
||
|
save_fp = fopen(name, "w");
|
||
|
}
|
||
|
|
||
|
org_fp = fdopen(fd, "r");
|
||
|
if (org_fp == NULL) {
|
||
|
fprintf(stderr, "\nError retrieving file\n");
|
||
|
return;
|
||
|
}
|
||
|
while (fgetc(org_fp) != EOF) {
|
||
|
if (fputc(temp, save_fp) == EOF) {
|
||
|
fprintf(stderr, "\nError while writing to output file\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* done; cleanup. */
|
||
|
fclose(save_fp);
|
||
|
fclose(org_fp);
|
||
|
}
|
||
|
|
||
|
/* Pass it an open file descriptor.
|
||
|
It might close it internally (due to the way fdopen() works), but caller
|
||
|
should also run close() just to be sure. */
|
||
|
static
|
||
|
void
|
||
|
mail_file(int fd)
|
||
|
{
|
||
|
char *address;
|
||
|
|
||
|
char *get_line();
|
||
|
static char *command = NULL;
|
||
|
|
||
|
printf("\n\nMail document to:");
|
||
|
fflush(stdout);
|
||
|
address = get_line();
|
||
|
if (address == NULL)
|
||
|
return;
|
||
|
|
||
|
command = qsprintf_stcopyr(command, "%s %s", MAIL_SENDING_PROGRAM, address);
|
||
|
|
||
|
run_subsystem_with_fd_as_stdin(fd,command,"Unable to mail");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
open_telnet(VLINK vl)
|
||
|
{
|
||
|
TOKEN args; /* Used to get access method args. */
|
||
|
char *paren; /* used during parsing. */
|
||
|
char *endparen; /* Used during parsing. */
|
||
|
char *hostpart; /* HOST breaks into host part & port part. */
|
||
|
char *portpart; /* Either NULL or the start of a string whose
|
||
|
numeric interpretation is the appropriate
|
||
|
port. */
|
||
|
int ch_par; /* Used for fork(). */
|
||
|
int tmp; /* Return from subfunctions */
|
||
|
|
||
|
if (pget_am(vl, &args, P_AM_TELNET) != P_AM_TELNET) {
|
||
|
cant_find_am:
|
||
|
fprintf(stderr, "Unable to find an appropriate access method to use \
|
||
|
this portal -- sorry.\n");
|
||
|
return;
|
||
|
}
|
||
|
/* ARGS are guaranteed to be a safe copy for us to work with. */
|
||
|
/* Length guaranteed by pget_am to be at least 5 elements. */
|
||
|
tmp = qsscanf(elt(args, 2), "%r%*[^(]%r(%r%*d%r)", &hostpart, &paren,
|
||
|
&portpart, &endparen);
|
||
|
if (tmp < 1)
|
||
|
goto cant_find_am;
|
||
|
if (tmp >= 2)
|
||
|
*paren = '\0';
|
||
|
if (tmp < 4)
|
||
|
portpart = NULL;
|
||
|
else
|
||
|
*endparen = '\0';
|
||
|
|
||
|
/* HOSTPART and PORTPART are now both correctly set. */
|
||
|
|
||
|
/* display prompt if present and not just the empty string. */
|
||
|
if (elt(args, 5) && *elt(args, 5))
|
||
|
puts(elt(args, 5));
|
||
|
/* Now fork. */
|
||
|
ch_par = fork();
|
||
|
|
||
|
if (ch_par == -1) {
|
||
|
perror("menu: fork() failed");
|
||
|
return;
|
||
|
} else if (ch_par == 0) {
|
||
|
/* CHILD */
|
||
|
if (portpart)
|
||
|
execlp(TELNET_PROGRAM, TELNET_PROGRAM, hostpart, portpart, (char *) 0);
|
||
|
else
|
||
|
execlp(TELNET_PROGRAM, TELNET_PROGRAM, hostpart, (char *) NULL);
|
||
|
/* Only get here if the execlp() failed. */
|
||
|
fprintf(stderr,
|
||
|
"Couldn't run the telnet program \"%s\" -- sorry!\n",
|
||
|
TELNET_PROGRAM);
|
||
|
_exit(1);
|
||
|
} else {
|
||
|
/* Parent */
|
||
|
wait((int *) NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
open_data(VLINK vl)
|
||
|
{
|
||
|
/*
|
||
|
int query_save_data();
|
||
|
int fd = retrieve_link(vl);
|
||
|
int fd_dup;
|
||
|
char *n = vl->name;
|
||
|
char *command;
|
||
|
char *tn;
|
||
|
char *to_free;
|
||
|
static int hassuffix(char *,char *);
|
||
|
pid_t pid;
|
||
|
char *dummy_argv[3];
|
||
|
|
||
|
if (hassuffix(n,"Z")) {
|
||
|
tn = tmpnam(NULL);
|
||
|
|
||
|
to_free = (char *)malloc(sizeof(char) * (9+strlen(tn)));
|
||
|
strcpy(to_free,"zcat > ");
|
||
|
strcat(to_free,tn);
|
||
|
pipe_output_to_subprogram(fd,to_free,"Unable to zcat");
|
||
|
stfree(to_free);
|
||
|
close(fd);
|
||
|
}
|
||
|
|
||
|
pid = fork();
|
||
|
if (pid == -1) {
|
||
|
fprintf(stderr, "%s: fork() failed.\n", "Unable to run gs");
|
||
|
return;
|
||
|
}
|
||
|
if (pid == 0) {
|
||
|
dummy_argv[0] = "gs";
|
||
|
dummy_argv[1] = tn;
|
||
|
dummy_argv[2] = NULL;
|
||
|
|
||
|
if (execvp(dummy_argv[0], dummy_argv) == -1) {
|
||
|
fprintf(stderr, "couldn't execute the program %s.\n",
|
||
|
"gs");
|
||
|
_exit(1);
|
||
|
}
|
||
|
_exit(0);
|
||
|
} else {
|
||
|
wait((int *) NULL);
|
||
|
}
|
||
|
|
||
|
*/
|
||
|
/* Original function... */
|
||
|
if (query_save_data()) {
|
||
|
int fd = retrieve_link(vl);
|
||
|
if (fd >= 0) save_file(fd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
hassuffix(char *name, char *suf)
|
||
|
{
|
||
|
char *lastdot = strrchr(name, '.');
|
||
|
if (lastdot) return strequal(lastdot + 1, suf); /* 1 if true */
|
||
|
else return 0; /* false */
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
/* Returns 1 if a file descriptor refers to a file that has more than 95%
|
||
|
printing characters. Note that this code is broken, since it gobbles up the
|
||
|
file you give it and since it is never used and has never been tested.
|
||
|
So we comment it out for now. --swa */
|
||
|
int
|
||
|
m_file_has_more_than_95_percent_printing_chars(int fd)
|
||
|
{
|
||
|
FILE *fp = fdopen(fd,"r");
|
||
|
int num_printing_chars = 0;
|
||
|
int tot_cnt = 0;
|
||
|
int retval;
|
||
|
|
||
|
do {
|
||
|
retval = fgetc(fp);
|
||
|
if (isprint(retval)) num_printing_chars++;
|
||
|
tot_cnt++;
|
||
|
} while (retval != -1 && tot_cnt < 1000);
|
||
|
|
||
|
if (((float) num_printing_chars / tot_cnt) > 0.95)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
TOKEN
|
||
|
get_token(VLINK vl, char *which_token)
|
||
|
{
|
||
|
PATTRIB temp;
|
||
|
PATTRIB highest = NULL;
|
||
|
int compare_precedence(char, char); /* defined in comp.c */
|
||
|
TOKEN temp_tok;
|
||
|
|
||
|
if (vl == NULL)
|
||
|
return NULL;
|
||
|
if ((temp = vl->lattrib) == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
while (temp != NULL) {
|
||
|
if (!strcmp(which_token, temp->aname))
|
||
|
if (highest == NULL)
|
||
|
highest = temp;
|
||
|
else if (compare_precedence(highest->precedence, temp->precedence)
|
||
|
== -1)
|
||
|
highest = temp;
|
||
|
temp = temp->next;
|
||
|
} /* while temp != NULL */
|
||
|
|
||
|
if (highest == NULL)
|
||
|
return NULL;
|
||
|
return highest->value.sequence;
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void
|
||
|
pipe_output_to_subprogram(int fd, char *subprogram, char *error_msg)
|
||
|
{
|
||
|
FILE *org_fp;
|
||
|
FILE *output_fp;
|
||
|
int temp = 25;
|
||
|
|
||
|
org_fp = fdopen(fd, "r");
|
||
|
if (org_fp == NULL) {
|
||
|
fprintf(stderr,error_msg);
|
||
|
return;
|
||
|
}
|
||
|
output_fp = popen(subprogram, "w");
|
||
|
if (output_fp == NULL) {
|
||
|
fprintf(stderr,error_msg);
|
||
|
fclose(org_fp);
|
||
|
return;
|
||
|
}
|
||
|
while(fgetc(org_fp) != EOF) {
|
||
|
int err = fputc(temp, output_fp);
|
||
|
if (err == EOF) {
|
||
|
fprintf(stderr,error_msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
pclose(output_fp); /* This was corrected from fclose. */
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
void
|
||
|
run_subsystem_with_fd_as_stdin(int fd, char *subprogram, char *error_msg)
|
||
|
{
|
||
|
/* char *dummy_argv[2];*/
|
||
|
char *execvp_argv[30]; /* Over 30 parameters would be nuts! */
|
||
|
int argc = 0;
|
||
|
pid_t pid;
|
||
|
int retval;
|
||
|
char *progcopy = stcopy(subprogram);
|
||
|
char *org_pc = progcopy;
|
||
|
|
||
|
memset(execvp_argv,0,sizeof(char *) * 30);
|
||
|
while (qsscanf(progcopy,"%&s",&(execvp_argv[argc]))==1) {
|
||
|
progcopy += strlen(execvp_argv[argc]);
|
||
|
while (isspace(*progcopy)) progcopy++;
|
||
|
argc++;
|
||
|
}
|
||
|
stfree(org_pc);
|
||
|
execvp_argv[argc] = NULL;
|
||
|
|
||
|
pid = fork();
|
||
|
if (pid == -1) {
|
||
|
fprintf(stderr, "%s: fork() failed.\n", error_msg);
|
||
|
return;
|
||
|
}
|
||
|
if (pid == 0) {
|
||
|
/* Child process */
|
||
|
assert(P_IS_THIS_THREAD_MASTER()); /* SOLARIS: dup2 MT-Unsafe */
|
||
|
if (dup2(fd, 0) == -1) {
|
||
|
fprintf(stderr,
|
||
|
"%s: dup2(fd,0) failed. This should *never* happen.\n",
|
||
|
error_msg);
|
||
|
_exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* dummy_argv[0] = subprogram;
|
||
|
dummy_argv[1] = NULL;
|
||
|
*/
|
||
|
|
||
|
if (execvp(execvp_argv[0], execvp_argv) == -1) {
|
||
|
fprintf(stderr, "%s: couldn't execute the program %s.\n",
|
||
|
error_msg, subprogram);
|
||
|
_exit(1);
|
||
|
}
|
||
|
_exit(0);
|
||
|
} else {
|
||
|
wait((int *) NULL); /* wait for child */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static
|
||
|
int
|
||
|
retrieve_link(VLINK vl)
|
||
|
{
|
||
|
int fd; /* return value */
|
||
|
printf("\nRetrieving %s...", m_item_description(vl));
|
||
|
fflush(stdout);
|
||
|
fd = m_open_file(vl);
|
||
|
if (fd < 0) {
|
||
|
puts("retrieval failed.");
|
||
|
} else {
|
||
|
puts("done.");
|
||
|
}
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|