/*Last Modified: 2-DEC-1992 14:22:35.18, By: MARK */
/* gopher.c
*
* Part of the Internet Gopher program, copyright (C) 1991
* University of Minnesota Microcomputer Workstation and Networks Center
*
* See the README file for information about the Gopher program.
*/
#include "gopher.h"
/* Connect_to_gopher performs a connection to socket 'service' on host
* 'host'. Host can be a hostname or ip-address. If 'host' is null, the
* local host is assumed. The parameter full_hostname will, on return,
* contain the expanded hostname (if possible). Note that full_hostname is a
* pointer to a char *, and is allocated by connect_to_gopher()
*
* Errors:
*
* -1 get service failed
*
* -2 get host failed
*
* -3 socket call failed
*
* -4 connect call failed
*/
/*
** Feed a gopher takes a line of text and parses it.
** It returns a 0 when successful and -1 when it isn't
*/
int feed_a_gopher(j, sockfd)
int j;
int sockfd;
{
char *cPtr = NULL;
char foo[255];
readfield(sockfd, foo, 255);
Gopher[j].sFileType = foo[0];
/** Get the kind of file from the first character **/
/** Filter out files that we can't deal with **/
switch (Gopher[j].sFileType) {
case A_FILE:
case A_DIRECTORY:
case A_CSO:
case A_INDEX:
case A_TELNET:
case A_SOUND:
case A_EVENT:
/* case A_CALENDAR: not ready for prime time yet */
break;
case A_EOI:
return(0);
default:
return(-1);
}
/** Suck off the User Displayable name **/
strncpy(Gopher[j].sTitle, foo + 1,79);
/** Suck off the Pathname **/
readfield(sockfd, Gopher[j].sPath, 150);
/** Suck off the hostname **/
if (readfield(sockfd, Gopher[j].sHost, 80) == 0)
return(-1);
if (readline(sockfd, foo, 255)==0)
; /** Panic! **/
Gopher[j].iPort = 0;
/** Get the port number **/
Gopher[j].iPort = atoi(foo);
return(0);
}
/*
** Feed_gophers simply loops through feed_a_gopher until it reaches its
** limit (MAXGOPHERS) or runs out of new data.
**
*/
int feed_gophers(sockfd)
int sockfd;
{
char ZesTmp[512];
int j;
if (feed_a_gopher(j, sockfd)!=0) {
j = j -1; /** feed a gopher failed, try again **/
readline(sockfd, ZesTmp, 512); /** Get rid of rest of line **/
}
if (Gopher[j].sFileType == '.')
break;
}
return(j);
}
/*
** Open a connection to another host
*/
do_telnet(ZeGopher)
GopherStruct *ZeGopher;
{
char *sMessage1;
char *sMessage2;
char *sTelCmd;
char telcom[64];
short int ch;
int ret_status, row, col;
$DESCRIPTOR(line1, "Warning!!!!!, you are about to leave the Internet");
$DESCRIPTOR(line2, "Gopher program and connect to another host.");
$DESCRIPTOR(line3, "If you get stuck, press the control key and the ^ ");
$DESCRIPTOR(line4, "key, and then type q or c.");
$DESCRIPTOR(line5, "Press return to connect: ");
$DESCRIPTOR(d_sMessage1, sMessage1);
$DESCRIPTOR(d_sMessage2, sMessage2);
$DESCRIPTOR(d_sTelCmd, sTelCmd);
/* retrieve the gopher information for the telnet command*/
/*
** do_index gets keywords from the user to search for. It returns
** it to the calling process. This storage is volotile. Callers should
** make a copy if they want to call do_index multiple times.
*/
/* This should be a generalized stack type. This is icky for now... */
static int SavedLinenum[MAXGOPHERS];
static int SavedLinePtr = 0;
main(argc, argv)
int argc;
char *argv[];
{
int iLine=0;
int iNum=0;
BOOLEAN bDone = FALSE;
char sTmp[40];
GopherStruct TmpGopher, *Gopherp;
short int TypedChar;
/*** for getopt processing ***/
int c, tmplen;
extern char *optarg;
extern int optind;
int errflag, ret_status, disp_row, disp_col, p_row, p_col;
iLine = GetMenu(iMenuLines, Gopher, SavedTitle, &TypedChar, iLine);
switch(TypedChar)
{
case SMG$K_TRM_CR:
case SMG$K_TRM_LF:
case SMG$K_TRM_RIGHT:
/*** Select the designated item ***/
iNum = iLine - 1;
if (Gopher[iNum].sFileType == A_DIRECTORY ||
Gopher[iNum].sFileType == A_INDEX) {
SavedLinenum[++SavedLinePtr] = iLine;
iLine=1;
}
process_request(&(Gopher[iNum]));
break;
case SMG$K_TRM_NULL_CHAR:
/*** What the heck? ***/
popgopher(&TmpGopher);
popgopher(&TmpGopher);
CursesErrorMsg("Strange Error occurred!");
process_request(&TmpGopher);
break;
case SMG$K_TRM_LOWERCASE_U:
case SMG$K_TRM_UPPERCASE_U:
case SMG$K_TRM_LEFT:
/*** Go up a directory level ***/
iNum=0;
popgopher(&TmpGopher);
popgopher(&TmpGopher);
iLine = SavedLinenum[(SavedLinePtr ==0) ? 0:SavedLinePtr--];
process_request(&TmpGopher);
break;
case SMG$K_TRM_LOWERCASE_S:
case SMG$K_TRM_UPPERCASE_S:
/*** Save the thing in a file ***/
break;
case SMG$K_TRM_LOWERCASE_N:
case SMG$K_TRM_UPPERCASE_N:
/*** Create a new file ***/
/* createobject();
popgopher(&TmpGopher); /** Get the altered directory **/
/* process_request(&TmpGopher);*/
break;
case SMG$K_TRM_LOWERCASE_D:
case SMG$K_TRM_UPPERCASE_D:
/* deleteobject(&(Gopher[iLine-1]));*/
/* popgopher(&TmpGopher); /** Get the altered directory **/
/* process_request(&TmpGopher);*/
break;
case SMG$K_TRM_UPPERCASE_M:
case SMG$K_TRM_LOWERCASE_M:
iNum = 0;
while (popgopher(&TmpGopher) != -1)
;
process_request(&TmpGopher);
break;
case SMG$K_TRM_LOWERCASE_Q:
case SMG$K_TRM_UPPERCASE_Q:
/*** Quit the program ***/
bDone = TRUE;
ret_status = smg$erase_display( &DisplayId );
break;
case SMG$K_TRM_LOWERCASE_O:
case SMG$K_TRM_UPPERCASE_O:
/*** Change various program things ***/
SetOptions();
break;
case SMG$K_TRM_EQUAL:
iNum = iLine - 1;
describe_gopher(&(Gopher[iNum]));
break;
case SMG$K_TRM_QUESTION_MARK:
/*** Display help file ***/
display_file(GOPHERHELP);
break;
default :
break;
pushgopher(ZeGopher); /* Risky; sometimes they push back */
i = feed_gophers(sockfd); /* Get next level's gophers*/
if (i <= 0) {
CursesErrorMsg("Nothing available.");
popgopher(ZeGopher);
strcpy(SavedTitle, sOldTitle);
SavedLinePtr--;
}
else
iMenuLines = i;
}
i = close(sockfd);
}
void
process_request(ZeGopher)
GopherStruct *ZeGopher;
{
int sockfd;
char *cp;
switch(ZeGopher->sFileType) {
case -1:
break;
case A_EVENT:
/* HandleEvent(ZeGopher);*/
break;
case A_FILE:
Draw_Status("Receiving Text...");
showfile(ZeGopher);
break;
case A_DIRECTORY:
Draw_Status("Receiving Directory...");
Load_Dir(ZeGopher);
break;
case A_TELNET:
do_telnet(ZeGopher);
break;
case A_INDEX:
Draw_Status("Searching Text...");
Searchstring = do_index(ZeGopher);
if (Searchstring != NULL)
Load_Index(ZeGopher);
break;
case A_CSO:
do_cso(ZeGopher);
break;
case A_SOUND:
Draw_Status("Receiving Sound...");
do_sound(ZeGopher);
break;
}
}
int
describe_gopher(ZeGopher)
GopherStruct *ZeGopher;
{
char tmpfilename[40];
FILE *tmpfile;
sprintf(tmpfilename,"sys$scratch:gopher.%d", getpid());
if ((tmpfile = fopen(tmpfilename, "w")) == NULL)
fprintf(stderr, "Couldn't make a tmp file!\n"), exit(-1);