зеркало из https://github.com/mozilla/pjs.git
1177 строки
35 KiB
C
1177 строки
35 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/* A state machine to implement the Gopher protocol
|
|
* Designed and Implemented by Lou Montulli circa '94
|
|
*/
|
|
|
|
#include "rosetta.h"
|
|
#include "xp.h"
|
|
#include "plstr.h"
|
|
#include "prmem.h"
|
|
#include "netutils.h"
|
|
#include "mkselect.h"
|
|
#include "mktcp.h"
|
|
#include "prerror.h"
|
|
|
|
/* Gopher types:
|
|
*/
|
|
#define GTYPE_TEXT '0' /* text/plain */
|
|
#define GTYPE_MENU '1' /* menu - becomes text/html */
|
|
#define GTYPE_CSO '2' /* cso search - becomes text/html */
|
|
#define GTYPE_ERROR '3' /* some sort of error */
|
|
#define GTYPE_MACBINHEX '4' /* application/binhex */
|
|
#define GTYPE_PCBINARY '5' /* application/octet-stream */
|
|
#define GTYPE_UUENCODED '6' /* application/uuencoded */
|
|
#define GTYPE_INDEX '7' /* search - becomes text/html */
|
|
#define GTYPE_TELNET '8' /* maps to telnet URL */
|
|
#define GTYPE_BINARY '9' /* application/octet-stream */
|
|
#define GTYPE_GIF 'g' /* image/gif */
|
|
#define GTYPE_HTML 'h' /* HTML URL */
|
|
#define GTYPE_HTMLCAPS 'H' /* HTML URL Capitalized */
|
|
#define GTYPE_INFO 'i' /* unselectable info */
|
|
#define GTYPE_IMAGE 'I' /* image/gif */
|
|
#define GTYPE_MIME 'm' /* not used */
|
|
#define GTYPE_SOUND 's' /* audio/(wildcard) */
|
|
#define GTYPE_TN3270 'T' /* maps to tn3270 program (url) */
|
|
#define GTYPE_WWW 'w' /* W3 address */
|
|
#define GTYPE_MPEG ';' /* video/mpeg */
|
|
|
|
#include "mkgeturl.h" /* URL Struct */
|
|
#include "mkstream.h"
|
|
#include "mkformat.h" /* for File Format stuff (cinfo) */
|
|
#include "gophurl.h" /* function prototypes */
|
|
#include "mktcp.h" /* connect, read, etc. */
|
|
#include "mkparse.h" /* NET_ParseURL() */
|
|
#include "remoturl.h" /* NET_RemoteHostLoad */
|
|
|
|
/* for XP_GetString() */
|
|
#include "xpgetstr.h"
|
|
extern int XP_HTML_GOPHER_INDEX;
|
|
extern int XP_HTML_CSO_SEARCH;
|
|
extern int XP_PROGRESS_WAITREPLY_GOTHER;
|
|
extern int MK_OUT_OF_MEMORY;
|
|
extern int MK_SERVER_DISCONNECTED;
|
|
extern int MK_TCP_READ_ERROR;
|
|
extern int MK_TCP_WRITE_ERROR;
|
|
extern int XP_ERRNO_EWOULDBLOCK;
|
|
extern int XP_SERVER_RETURNED_NO_DATA;
|
|
extern int MK_MALFORMED_URL_ERROR;
|
|
|
|
#include "merrors.h"
|
|
|
|
#define CD_OUTPUT_BUFFER_SIZE 4*1024
|
|
|
|
typedef struct _GopherConData {
|
|
int next_state; /* the next state or action to be taken */
|
|
char *data_buf; /* temporary string storage */
|
|
int32 data_buf_size; /* current size of the line buffer */
|
|
char gopher_type; /* the gopher type */
|
|
char *command; /* the request command */
|
|
char *output_buf; /* temporary output buffer */
|
|
NET_StreamClass *stream; /* The output stream */
|
|
Bool pause_for_read; /* Pause now for next read? */
|
|
Bool destroy_graph_progress; /* do we need to destroy graph progress? */
|
|
int32 original_content_length; /* the content length at the time of
|
|
* calling graph progress
|
|
*/
|
|
char cso_last_char;
|
|
TCP_ConData *tcp_con_data;
|
|
} GopherConData;
|
|
|
|
#define PUTSTRING(s) (*connection_data->stream->put_block) \
|
|
(connection_data->stream, s, PL_strlen(s))
|
|
#define PUTBLOCK(b, l) (*connection_data->stream->put_block) \
|
|
(connection_data->stream, b, l)
|
|
#define COMPLETE_STREAM (*connection_data->stream->complete) \
|
|
(connection_data->stream)
|
|
#define ABORT_STREAM(s) (*connection_data->stream->abort) \
|
|
(connection_data->stream, s)
|
|
|
|
/* helpful shortcut names
|
|
*/
|
|
#define CD_NEXT_STATE connection_data->next_state
|
|
#define CD_DATA_BUF connection_data->data_buf
|
|
#define CD_DATA_BUF_SIZE connection_data->data_buf_size
|
|
#define CD_STREAM connection_data->stream
|
|
#define CD_GOPHER_TYPE connection_data->gopher_type
|
|
#define CD_COMMAND connection_data->command
|
|
#define CD_OUTPUT_BUF connection_data->output_buf
|
|
#define CD_PAUSE_FOR_READ connection_data->pause_for_read
|
|
#define CD_DESTROY_GRAPH_PROGRESS connection_data->destroy_graph_progress
|
|
#define CD_ORIGINAL_CONTENT_LENGTH connection_data->original_content_length
|
|
#define CD_CSO_LAST_CHAR connection_data->cso_last_char
|
|
#define CD_TCP_CON_DATA connection_data->tcp_con_data
|
|
|
|
|
|
#define CE_WINDOW_ID cur_entry->window_id
|
|
#define CE_URL_S cur_entry->URL_s
|
|
#define CE_STATUS cur_entry->status
|
|
#define CE_SOCK cur_entry->socket
|
|
#define CE_CON_SOCK cur_entry->con_sock
|
|
#define CE_BYTES_RECEIVED cur_entry->bytes_received
|
|
|
|
/* states for the state machine
|
|
*/
|
|
#define GOPHER_BEGIN_CONNECT 1
|
|
#define GOPHER_FINISH_CONNECT 2
|
|
#define GOPHER_SEND_REQUEST 3
|
|
#define GOPHER_BEGIN_TRANSFER 4
|
|
#define GOPHER_TRANSFER_MENU 5
|
|
#define GOPHER_TRANSFER_CSO 6
|
|
#define GOPHER_TRANSFER_BINARY 7
|
|
#define GOPHER_DONE 8
|
|
#define GOPHER_ERROR_DONE 9
|
|
#define GOPHER_FREE 10
|
|
|
|
|
|
/* forward decl */
|
|
PRIVATE int32 net_ProcessGopher(ActiveEntry * cur_entry);
|
|
|
|
/* net_begin_gopher_menu
|
|
*
|
|
* adds little bits to the begining of the document so that is looks nice
|
|
*/
|
|
|
|
PRIVATE int
|
|
net_begin_gopher_menu(GopherConData * connection_data)
|
|
{
|
|
|
|
CD_NEXT_STATE = GOPHER_TRANSFER_MENU;
|
|
|
|
PL_strcpy(CD_OUTPUT_BUF, "<H1>Gopher Menu</H1>\n<PRE>");
|
|
return(PUTSTRING(CD_OUTPUT_BUF));
|
|
|
|
}
|
|
|
|
/* parse the gopher menu type
|
|
*/
|
|
PRIVATE int
|
|
net_parse_menu (ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
char gopher_type;
|
|
char *name=NULL;
|
|
char *gopher_path=0;
|
|
char *port;
|
|
char *ptr;
|
|
char *line;
|
|
char *host=NULL;
|
|
|
|
CE_STATUS = NET_BufferedReadLine(CE_SOCK, &line, &CD_DATA_BUF,
|
|
&CD_DATA_BUF_SIZE, &CD_PAUSE_FOR_READ);
|
|
|
|
if(CE_STATUS == 0)
|
|
{
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
if(CE_BYTES_RECEIVED < 4)
|
|
{
|
|
PL_strcpy(CD_OUTPUT_BUF, XP_GetString( XP_SERVER_RETURNED_NO_DATA ) );
|
|
PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
|
|
return(MK_DATA_LOADED);
|
|
}
|
|
|
|
/* if TCP error of if there is not a full line yet return
|
|
*/
|
|
if(!line)
|
|
{
|
|
return CE_STATUS;
|
|
}
|
|
else if(CE_STATUS < 0)
|
|
{
|
|
NET_ExplainErrorDetails(MK_TCP_READ_ERROR, PR_GetOSError());
|
|
|
|
/* return TCP error
|
|
*/
|
|
return MK_TCP_READ_ERROR;
|
|
}
|
|
|
|
if(CE_STATUS > 1)
|
|
{
|
|
CE_BYTES_RECEIVED += CE_STATUS;
|
|
FE_GraphProgress(CE_WINDOW_ID, CE_URL_S, CE_BYTES_RECEIVED, CE_STATUS, CE_URL_S->content_length);
|
|
}
|
|
|
|
gopher_type = *line;
|
|
|
|
if(gopher_type != '\0')
|
|
ptr = line+1;
|
|
else
|
|
return(0);
|
|
|
|
/* remove trailing spaces */
|
|
XP_StripLine(line);
|
|
|
|
TRACEMSG(("gopher_parse_menu: parsing line: %s\n",line));
|
|
|
|
/* quit when just a dot is found on a line by itself
|
|
*/
|
|
if(!PL_strcmp(line,"."))
|
|
{
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
|
|
if(CE_BYTES_RECEIVED < 4)
|
|
{
|
|
PL_strcpy(CD_OUTPUT_BUF, XP_GetString( XP_SERVER_RETURNED_NO_DATA ) );
|
|
PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
|
|
return(MK_DATA_LOADED);
|
|
}
|
|
|
|
if (gopher_type && *ptr)
|
|
{
|
|
name = ptr;
|
|
gopher_path = PL_strchr(name, '\t');
|
|
if (gopher_path)
|
|
{
|
|
*gopher_path++ = 0;
|
|
host = PL_strchr(gopher_path, '\t');
|
|
if (host)
|
|
{
|
|
*host++ = 0;
|
|
port = PL_strchr(host, '\t');
|
|
if (port)
|
|
{
|
|
char *tab;
|
|
|
|
port[0] = ':'; /* fake the port no */
|
|
tab = PL_strchr(port, '\t');
|
|
if (tab)
|
|
*tab++ = '\0';
|
|
|
|
if (port[1]=='0' && port[2]=='\0')
|
|
port[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!gopher_path)
|
|
{
|
|
return(PUTSTRING(ptr)); /* keep going bad data */
|
|
}
|
|
|
|
/* Nameless files are a separator line */
|
|
if (gopher_type == GTYPE_TEXT)
|
|
{
|
|
int i=0;
|
|
while(NET_IS_SPACE(name[i])) i++;
|
|
if(!PL_strlen(name))
|
|
gopher_type = GTYPE_INFO;
|
|
}
|
|
|
|
/* these first few are grouped together with an
|
|
* if else because they each have special needs
|
|
* the rest of them fit nicely in the switch
|
|
*/
|
|
if(gopher_type == GTYPE_ERROR)
|
|
{
|
|
/* ignore it */
|
|
}
|
|
else if(gopher_type == GTYPE_WWW)
|
|
{
|
|
/* points to URL */
|
|
PL_strcpy(CD_OUTPUT_BUF, "<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-text\">");
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
|
|
if(CE_STATUS < 0)
|
|
return(CE_STATUS);
|
|
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"%s\">%s</A>\n", gopher_path, name);
|
|
return(PUTSTRING(CD_OUTPUT_BUF));
|
|
|
|
}
|
|
else if(gopher_type == GTYPE_INFO)
|
|
{
|
|
/* Information or separator line */
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, " %s\n", name);
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
else if(gopher_type == GTYPE_TELNET)
|
|
{
|
|
if (*gopher_path)
|
|
{
|
|
char * temp = NET_Escape(gopher_path, URL_XALPHAS);
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"telnet://%s@%s/\"><IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-telnet\"> %s</A>\n", temp, host, name);
|
|
PR_Free(temp);
|
|
}
|
|
else
|
|
{
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"telnet://%s/\"><IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-telnet\"> %s</A>\n", host, name);
|
|
}
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
else if(gopher_type == GTYPE_TN3270)
|
|
{
|
|
if (gopher_path && *gopher_path)
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"tn3270://%s@%s/\"><IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-telnet\"> %s</A>\n", gopher_path, host, name);
|
|
else
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"tn3270://%s/\"><IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-telnet\"> %s</A>\n", host, name);
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
else
|
|
{
|
|
if(host && gopher_path)
|
|
{
|
|
if(!PL_strcmp(host, "error.host:70"))
|
|
{
|
|
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "Error: %s", name);
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
|
|
}
|
|
else
|
|
{
|
|
char * newpath = NET_Escape(gopher_path, URL_PATH);
|
|
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<A HREF=\"gopher://%s/%c%s\">", host, gopher_type, newpath);
|
|
|
|
switch(gopher_type) {
|
|
case GTYPE_TEXT:
|
|
case GTYPE_HTML:
|
|
case GTYPE_HTMLCAPS:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 "
|
|
"SRC=\"internal-gopher-text\">");
|
|
break;
|
|
case GTYPE_MENU:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-menu\">");
|
|
break;
|
|
case GTYPE_CSO:
|
|
case GTYPE_INDEX:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-index\">");
|
|
break;
|
|
case GTYPE_PCBINARY:
|
|
case GTYPE_UUENCODED:
|
|
case GTYPE_BINARY:
|
|
case GTYPE_MACBINHEX:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-binary\">");
|
|
break;
|
|
case GTYPE_IMAGE:
|
|
case GTYPE_GIF:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-image\">");
|
|
break;
|
|
case GTYPE_SOUND:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-sound\">");
|
|
break;
|
|
case GTYPE_MPEG:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-movie\">");
|
|
break;
|
|
|
|
case GTYPE_MIME:
|
|
default:
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
"<IMG ALIGN=absbottom BORDER=0 SRC=\"internal-gopher-unknown\">");
|
|
break;
|
|
}
|
|
|
|
PR_snprintf(&CD_OUTPUT_BUF[PL_strlen(CD_OUTPUT_BUF)],
|
|
CD_OUTPUT_BUFFER_SIZE
|
|
- PL_strlen(CD_OUTPUT_BUF),
|
|
" %s</A>\n", name);
|
|
PR_Free(newpath);
|
|
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(CE_STATUS); /* keep going */
|
|
|
|
}
|
|
|
|
/* net_begin_gopher_cso
|
|
*
|
|
* adds formatting to the front of the document to make
|
|
* it look pretty
|
|
*/
|
|
PRIVATE int
|
|
net_begin_gopher_cso(GopherConData * connection_data)
|
|
{
|
|
PL_strcpy(CD_OUTPUT_BUF, "<H1>CSO Search Results</H1>\n<PRE>");
|
|
|
|
CD_NEXT_STATE = GOPHER_TRANSFER_CSO;
|
|
|
|
return(PUTSTRING(CD_OUTPUT_BUF));
|
|
}
|
|
|
|
/*
|
|
* parse cso output
|
|
*
|
|
* receives date from the cso server and turns it into HTML
|
|
*/
|
|
PRIVATE int
|
|
net_parse_cso (ActiveEntry * cur_entry)
|
|
{
|
|
char *line;
|
|
char *colon1, *colon2;
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
|
|
CE_STATUS = NET_BufferedReadLine(CE_SOCK, &line, &CD_DATA_BUF,
|
|
&CD_DATA_BUF_SIZE, &CD_PAUSE_FOR_READ);
|
|
|
|
if(CE_STATUS == 0)
|
|
CE_STATUS = MK_SERVER_DISCONNECTED;
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_SERVER_DISCONNECTED);
|
|
|
|
/* if TCP error of if there is not a full line yet return
|
|
*/
|
|
if(CE_STATUS < 0)
|
|
{
|
|
NET_ExplainErrorDetails(MK_TCP_READ_ERROR, PR_GetOSError());
|
|
|
|
/* return TCP error
|
|
*/
|
|
return MK_TCP_READ_ERROR;
|
|
}
|
|
else if(!line)
|
|
{
|
|
return CE_STATUS;
|
|
}
|
|
|
|
if(CE_STATUS > 1)
|
|
{
|
|
CE_BYTES_RECEIVED += CE_STATUS;
|
|
FE_GraphProgress(CE_WINDOW_ID, CE_URL_S, CE_BYTES_RECEIVED, CE_STATUS, CE_URL_S->content_length);
|
|
}
|
|
|
|
/* a line beginning with a 2 means the end of data
|
|
*/
|
|
if (*line == '2')
|
|
{
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
return(MK_DATA_LOADED);
|
|
}
|
|
|
|
/* if it starts with a 5 something went wrong, print
|
|
* out the error message
|
|
*/
|
|
if (*line == '5')
|
|
{
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, "<H2>%s</H2>", line+4);
|
|
PUTSTRING(CD_OUTPUT_BUF);
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
return(MK_DATA_LOADED);
|
|
}
|
|
|
|
if(*line == '-')
|
|
{
|
|
colon1 = PL_strchr(line,':');
|
|
if(colon1)
|
|
colon2 = PL_strchr(colon1+1, ':');
|
|
else
|
|
colon2 = NULL;
|
|
|
|
if(colon2 != NULL)
|
|
{
|
|
if (*(colon2-1) != CD_CSO_LAST_CHAR)
|
|
{ /* print seperator */
|
|
PL_strcpy(CD_OUTPUT_BUF, "</PRE><H2>");
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
|
|
if(CE_STATUS > -1)
|
|
CE_STATUS = PUTSTRING(colon2+1);
|
|
PL_strcpy(CD_OUTPUT_BUF, "\n");
|
|
if(CE_STATUS > -1)
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
|
|
if (*(colon2-1) != CD_CSO_LAST_CHAR)
|
|
{
|
|
/* end seperator */
|
|
PL_strcpy(CD_OUTPUT_BUF, "</H2><PRE>");
|
|
if(CE_STATUS > -1)
|
|
CE_STATUS = PUTSTRING(CD_OUTPUT_BUF);
|
|
}
|
|
|
|
/* remember the last char so that we can
|
|
* tell when the sequence number changes
|
|
*/
|
|
CD_CSO_LAST_CHAR = *(colon2-1);
|
|
|
|
} /* end if colon2 */
|
|
} /* end if *line == '-' */
|
|
|
|
return(1); /* keep going */
|
|
|
|
} /* end of procedure */
|
|
|
|
/* display the page that allows searching of a gopher index
|
|
*/
|
|
PRIVATE int
|
|
net_display_index_splash_screen (ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
char *address_copy = 0;
|
|
|
|
StrAllocCopy(address_copy, CE_URL_S->address);
|
|
NET_UnEscape(address_copy);
|
|
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, XP_GetString(XP_HTML_GOPHER_INDEX), address_copy, address_copy);
|
|
PUTSTRING(CD_OUTPUT_BUF);
|
|
|
|
COMPLETE_STREAM;
|
|
|
|
PR_Free(address_copy);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* parse CSO server output
|
|
*/
|
|
PRIVATE int
|
|
net_display_cso_splash_screen (ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
char *address_copy = 0;
|
|
|
|
StrAllocCopy(address_copy, CE_URL_S->address);
|
|
NET_UnEscape(address_copy);
|
|
|
|
PR_snprintf(CD_OUTPUT_BUF, CD_OUTPUT_BUFFER_SIZE, XP_GetString(XP_HTML_CSO_SEARCH), address_copy, address_copy);
|
|
|
|
PUTSTRING(CD_OUTPUT_BUF);
|
|
|
|
COMPLETE_STREAM;
|
|
|
|
PR_Free(address_copy);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* send the request to get the data
|
|
*/
|
|
PRIVATE int
|
|
net_send_gopher_request (ActiveEntry * cur_entry)
|
|
{
|
|
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
|
|
TRACEMSG(("MKGopher: Connected, writing command `%s' to socket %d\n",
|
|
CD_COMMAND, CE_SOCK));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, CD_COMMAND, PL_strlen(CD_COMMAND));
|
|
|
|
NET_Progress (CE_WINDOW_ID, XP_GetString(XP_PROGRESS_WAITREPLY_GOTHER));
|
|
|
|
/* start the graph progress indicator
|
|
*/
|
|
FE_GraphProgressInit(CE_WINDOW_ID, CE_URL_S, CE_URL_S->content_length);
|
|
CD_DESTROY_GRAPH_PROGRESS = TRUE; /* we will need to destroy it */
|
|
CD_ORIGINAL_CONTENT_LENGTH = CE_URL_S->content_length;
|
|
|
|
CD_NEXT_STATE = GOPHER_BEGIN_TRANSFER;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
if(CE_STATUS < 0)
|
|
CE_STATUS = MK_TCP_WRITE_ERROR;
|
|
|
|
return(CE_STATUS); /* everything OK */
|
|
|
|
} /* end GopherLoad */
|
|
|
|
|
|
/* pull down data in binary mode
|
|
*/
|
|
PRIVATE int
|
|
net_pull_gopher_data(ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
unsigned int write_ready, read_size;
|
|
|
|
/* check to see if the stream is ready for writing
|
|
*/
|
|
write_ready = (*CD_STREAM->is_write_ready)(CD_STREAM);
|
|
|
|
if(write_ready < 1)
|
|
{
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
return(0); /* wait until we are ready to write */
|
|
}
|
|
else if(write_ready < (unsigned int) NET_Socket_Buffer_Size)
|
|
{
|
|
read_size = write_ready;
|
|
}
|
|
else
|
|
{
|
|
read_size = NET_Socket_Buffer_Size;
|
|
}
|
|
|
|
CE_STATUS = PR_Read(CE_SOCK, NET_Socket_Buffer, read_size);
|
|
|
|
if(CE_STATUS == 0)
|
|
{ /* all done */
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
CE_STATUS = MK_DATA_LOADED;
|
|
}
|
|
else if(CE_STATUS > 0)
|
|
{
|
|
CE_BYTES_RECEIVED += CE_STATUS;
|
|
FE_GraphProgress(CE_WINDOW_ID,
|
|
CE_URL_S,
|
|
CE_BYTES_RECEIVED,
|
|
CE_STATUS,
|
|
CE_URL_S->content_length);
|
|
CE_STATUS = PUTBLOCK(NET_Socket_Buffer, CE_STATUS);
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* status less than zero
|
|
*/
|
|
int rv = PR_GetError();
|
|
if(rv == PR_WOULD_BLOCK_ERROR)
|
|
{
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
return 0;
|
|
}
|
|
CE_STATUS = (rv < 0) ? rv : (-rv);
|
|
}
|
|
|
|
return(CE_STATUS);
|
|
|
|
}
|
|
|
|
/* a list of dis-allowed ports for gopher
|
|
* connections
|
|
*/
|
|
PRIVATE int bad_ports_table[] = {
|
|
1, 7, 9, 11 , 13, 15, 17, 19, 20,
|
|
21, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102,
|
|
103, 104, 109, 110, 111, 113, 115, 117, 119,
|
|
135, 143, 512, 513, 514, 515, 526, 530, 531, 532,
|
|
540, 556, 601, 6000, 0 };
|
|
|
|
/* begin the load by initializing data structures and calling Process Gopher
|
|
*/
|
|
PRIVATE int32
|
|
net_GopherLoad (ActiveEntry * cur_entry)
|
|
{
|
|
char gopher_type; /* type */
|
|
char * path; /* the URL path */
|
|
char * gopher_path; /* the gopher path */
|
|
char * gopher_host;
|
|
char * query; /* holds the '?' query string */
|
|
char *ptr;
|
|
GopherConData * connection_data; /* state data for this connection */
|
|
|
|
/* check for illegal gopher port numbers and
|
|
* return invalid URL for those
|
|
*/
|
|
gopher_host = NET_ParseURL(CE_URL_S->address, GET_HOST_PART);
|
|
if(gopher_host)
|
|
{
|
|
int port_number;
|
|
int i;
|
|
char *colon = PL_strchr(gopher_host, ':');
|
|
|
|
if(colon)
|
|
{
|
|
colon++; /* now it points to a port number */
|
|
|
|
port_number = XP_ATOI(colon);
|
|
|
|
/* disallow well known ports */
|
|
for(i=0; bad_ports_table[i]; i++)
|
|
if(port_number == bad_ports_table[i])
|
|
{
|
|
char *error_msg = NET_ExplainErrorDetails(
|
|
MK_MALFORMED_URL_ERROR,
|
|
CE_URL_S->address);
|
|
if(error_msg)
|
|
FE_Alert(CE_WINDOW_ID, error_msg);
|
|
PR_Free(gopher_host);
|
|
return(MK_MALFORMED_URL_ERROR);
|
|
}
|
|
}
|
|
PR_Free(gopher_host);
|
|
}
|
|
|
|
|
|
/* malloc space for connection data
|
|
*/
|
|
connection_data = PR_NEW(GopherConData);
|
|
if(!connection_data)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
memset(connection_data, 0, sizeof(GopherConData)); /* zero it */
|
|
|
|
CE_SOCK = NULL;
|
|
|
|
cur_entry->con_data = connection_data;
|
|
|
|
CD_OUTPUT_BUF = (char*) PR_Malloc(CD_OUTPUT_BUFFER_SIZE);
|
|
if(!CD_OUTPUT_BUF)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
|
|
/* Get entity type, and gopher_path string.
|
|
*/
|
|
path = NET_ParseURL(CE_URL_S->address, GET_PATH_PART);
|
|
|
|
TRACEMSG(("GopherLoad: Got path: %s\n",path));
|
|
|
|
if(*path && *path != '/')
|
|
{
|
|
gopher_type = *path;
|
|
gopher_path = path+1;
|
|
}
|
|
else if ((*path=='/') && (*(path+1))) /* past first slash slash */
|
|
{
|
|
gopher_type = *(path+1); /* get gopher_type */
|
|
gopher_path = path+2; /* go past slash and gopher_type */
|
|
}
|
|
else /* no path or just slash */
|
|
{
|
|
/* special case!!!
|
|
* if the URL looks like gopher://host/?search term
|
|
* treat it as a text file and append the search term
|
|
*/
|
|
if(PL_strchr(CE_URL_S->address, '?'))
|
|
{
|
|
gopher_type = '0';
|
|
}
|
|
else
|
|
{
|
|
gopher_type = '1'; /* menus are the default */
|
|
}
|
|
if(*path == '\0')
|
|
gopher_path = path;
|
|
else
|
|
gopher_path = path+1;
|
|
}
|
|
|
|
CD_GOPHER_TYPE = gopher_type; /* set for later use */
|
|
|
|
TRACEMSG(("URL: %s\ngopher_type: %c\nGopher_Path: %s\n",
|
|
CE_URL_S->address, gopher_type, gopher_path));
|
|
|
|
/* We now have the gopher type so we can safely set up
|
|
* the Stream stack since we know what type will be
|
|
* returned ahead of time
|
|
*/
|
|
switch(gopher_type) {
|
|
case GTYPE_HTML: /* all HTML types */
|
|
case GTYPE_HTMLCAPS:
|
|
case GTYPE_MENU:
|
|
case GTYPE_CSO:
|
|
case GTYPE_INDEX:
|
|
StrAllocCopy(CE_URL_S->content_type, TEXT_HTML);
|
|
break;
|
|
case GTYPE_TEXT:
|
|
StrAllocCopy(CE_URL_S->content_type, TEXT_PLAIN);
|
|
break;
|
|
case GTYPE_MACBINHEX:
|
|
StrAllocCopy(CE_URL_S->content_type, APPLICATION_BINHEX);
|
|
break;
|
|
case GTYPE_PCBINARY:
|
|
case GTYPE_BINARY:
|
|
case GTYPE_MIME:
|
|
StrAllocCopy(CE_URL_S->content_type, APPLICATION_OCTET_STREAM);
|
|
break;
|
|
case GTYPE_UUENCODED:
|
|
StrAllocCopy(CE_URL_S->content_type, APPLICATION_UUENCODE);
|
|
break;
|
|
case GTYPE_TELNET:
|
|
case GTYPE_TN3270:
|
|
#ifdef MOZILLA_CLIENT
|
|
/* do the telnet and return */
|
|
return(NET_RemoteHostLoad(cur_entry));
|
|
#else
|
|
PR_ASSERT(0);
|
|
break;
|
|
#endif /* MOZILLA_CLIENT */
|
|
case GTYPE_GIF:
|
|
case GTYPE_IMAGE:
|
|
StrAllocCopy(CE_URL_S->content_type, IMAGE_GIF);
|
|
break;
|
|
case GTYPE_SOUND:
|
|
StrAllocCopy(CE_URL_S->content_type, AUDIO_BASIC);
|
|
break;
|
|
case GTYPE_MPEG:
|
|
StrAllocCopy(CE_URL_S->content_type, VIDEO_MPEG);
|
|
break;
|
|
default:
|
|
StrAllocCopy(CE_URL_S->content_type, TEXT_PLAIN);
|
|
break;
|
|
}
|
|
|
|
CD_STREAM = NET_StreamBuilder(cur_entry->format_out, CE_URL_S, CE_WINDOW_ID);
|
|
|
|
if (!CD_STREAM)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_UNABLE_TO_CONVERT);
|
|
return(MK_UNABLE_TO_CONVERT);
|
|
}
|
|
|
|
TRACEMSG(("MKGopher: Stream now set up \n"));
|
|
|
|
/* now do all the special handling of each type that
|
|
* doesn't involve just a direct get
|
|
*/
|
|
switch(gopher_type) {
|
|
case GTYPE_INDEX:
|
|
/* Search is allowed */
|
|
query = PL_strchr(CE_URL_S->address, '?'); /* Look for search string */
|
|
|
|
if (!query || !query[1]) { /* No search defined */
|
|
/* Display "cover page" */
|
|
net_display_index_splash_screen(cur_entry);
|
|
CD_NEXT_STATE = GOPHER_DONE;
|
|
return -1; /* Local function only */
|
|
}
|
|
|
|
*query++ = 0; /* Go past '?' */
|
|
|
|
StrAllocCopy(CD_COMMAND, NET_UnEscape(gopher_path));
|
|
|
|
StrAllocCat(CD_COMMAND, "\t");
|
|
|
|
/* Remove plus signs */
|
|
for (ptr=query; *ptr; ptr++)
|
|
if (*ptr == '+')
|
|
*ptr = ' ';
|
|
|
|
StrAllocCat(CD_COMMAND, NET_UnEscape(query));
|
|
|
|
*(query-1) = '?'; /* set it back to the way it was */
|
|
break;
|
|
|
|
case GTYPE_CSO:
|
|
/* Search is allowed */
|
|
query = PL_strchr(CE_URL_S->address, '?'); /* Look for search string */
|
|
|
|
if (!query || !query[1]) /* No search required */
|
|
{
|
|
/* Display "cover page" */
|
|
net_display_cso_splash_screen(cur_entry);
|
|
CE_STATUS = MK_DATA_LOADED;
|
|
return -1; /* Local function only */
|
|
}
|
|
*query++ = 0; /* Go past '?' */
|
|
|
|
StrAllocCopy(CD_COMMAND, "query ");
|
|
|
|
/* Remove plus signs */
|
|
for (ptr=query; *ptr; ptr++)
|
|
if (*ptr == '+')
|
|
*ptr = ' ';
|
|
|
|
StrAllocCat(CD_COMMAND, (char *)NET_UnEscape(query));
|
|
|
|
*(query-1) = '?'; /* set it back to the way it was */
|
|
|
|
break;
|
|
|
|
case GTYPE_TEXT:
|
|
/* Look for search string */
|
|
query = PL_strchr(CE_URL_S->address, '?');
|
|
|
|
/* special case!!!
|
|
* if a query exist treat it special, send
|
|
* the query instead
|
|
*/
|
|
if(query)
|
|
{
|
|
*query++ = 0; /* Go past '?' */
|
|
|
|
/* Remove plus signs */
|
|
for (ptr=query; *ptr; ptr++)
|
|
if (*ptr == '+')
|
|
*ptr = ' ';
|
|
|
|
StrAllocCopy(CD_COMMAND, (char *)NET_UnEscape(query));
|
|
|
|
*(query-1) = '?'; /* set it back to the way it was */
|
|
}
|
|
else if(*path != '\0')
|
|
{
|
|
StrAllocCopy(CD_COMMAND, (char*)NET_UnEscape(gopher_path));
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy(CD_COMMAND, "/");
|
|
}
|
|
break;
|
|
|
|
default: /* all other types besides index and CSO */
|
|
if(*path == '\0')
|
|
StrAllocCopy(CD_COMMAND, "/");
|
|
else
|
|
StrAllocCopy(CD_COMMAND, (char*)NET_UnEscape(gopher_path));
|
|
}
|
|
|
|
PR_FREEIF(path); /* NET_Parse malloc'd the path string */
|
|
path = NULL;
|
|
|
|
/* protect against other protocol attacks by limiting
|
|
* the command to a single line. Terminate the command
|
|
* at any \n or \r
|
|
*/
|
|
if(PL_strchr(CD_COMMAND, '\n') || PL_strchr(CD_COMMAND, '\r'))
|
|
{
|
|
char *error_msg = NET_ExplainErrorDetails(MK_MALFORMED_URL_ERROR,
|
|
CE_URL_S->address);
|
|
if(error_msg)
|
|
FE_Alert(CE_WINDOW_ID, error_msg);
|
|
return(MK_MALFORMED_URL_ERROR);
|
|
}
|
|
|
|
StrAllocCat(CD_COMMAND, CRLF); /* finish off the command */
|
|
|
|
CD_NEXT_STATE = GOPHER_BEGIN_CONNECT;
|
|
|
|
return(net_ProcessGopher(cur_entry));
|
|
}
|
|
|
|
/* NET_ProcessGopher
|
|
* completes the data transfer; is called from NET_ProcessNet()
|
|
*
|
|
* returns negative when complete
|
|
*/
|
|
PRIVATE int32
|
|
net_ProcessGopher(ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
|
|
TRACEMSG(("Entered ProcessGopher: gopher_type=%c\n",CD_GOPHER_TYPE));
|
|
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
|
|
while(!CD_PAUSE_FOR_READ)
|
|
{
|
|
TRACEMSG(("ProcessGopher: in switch with state: #%d\n",CD_NEXT_STATE));
|
|
|
|
switch(CD_NEXT_STATE) {
|
|
|
|
case GOPHER_BEGIN_CONNECT:
|
|
/* Set up a socket to the server for the data:
|
|
*/
|
|
TRACEMSG(("MKGopher: Setting up net connection\n"));
|
|
|
|
CE_STATUS = NET_BeginConnect(CE_URL_S->address,
|
|
CE_URL_S->IPAddressString,
|
|
"Gopher",
|
|
70,
|
|
&CE_SOCK,
|
|
HG10300
|
|
&CD_TCP_CON_DATA,
|
|
CE_WINDOW_ID,
|
|
&CE_URL_S->error_msg,
|
|
cur_entry->socks_host,
|
|
cur_entry->socks_port,
|
|
cur_entry->URL_s->localIP);
|
|
|
|
if(CE_SOCK != NULL)
|
|
NET_TotalNumberOfOpenConnections++;
|
|
|
|
if(CE_STATUS == MK_CONNECTED)
|
|
{
|
|
CD_NEXT_STATE = GOPHER_SEND_REQUEST;
|
|
NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
}
|
|
else if(CE_STATUS > -1)
|
|
{
|
|
CD_NEXT_STATE = GOPHER_FINISH_CONNECT;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
CE_CON_SOCK = CE_SOCK; /* set so we select on it */
|
|
NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
}
|
|
break;
|
|
|
|
case GOPHER_FINISH_CONNECT:
|
|
CE_STATUS = NET_FinishConnect(CE_URL_S->address,
|
|
"Gopher",
|
|
70,
|
|
&CE_SOCK,
|
|
&CD_TCP_CON_DATA,
|
|
CE_WINDOW_ID,
|
|
&CE_URL_S->error_msg,
|
|
cur_entry->URL_s->localIP);
|
|
if(CE_STATUS == MK_CONNECTED)
|
|
{
|
|
CD_NEXT_STATE = GOPHER_SEND_REQUEST;
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
CE_CON_SOCK = NULL; /* reset so we don't select on it */
|
|
NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* unregister the old CE_SOCK from the select list
|
|
* and register the new value in the case that it changes
|
|
*/
|
|
if(CE_CON_SOCK != CE_SOCK)
|
|
{
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
CE_CON_SOCK = CE_SOCK;
|
|
NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
}
|
|
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
}
|
|
break;
|
|
|
|
case GOPHER_SEND_REQUEST:
|
|
CE_STATUS = net_send_gopher_request(cur_entry);
|
|
break;
|
|
|
|
case GOPHER_BEGIN_TRANSFER:
|
|
if(CD_GOPHER_TYPE == GTYPE_MENU || CD_GOPHER_TYPE == GTYPE_INDEX)
|
|
CE_STATUS = net_begin_gopher_menu(connection_data);
|
|
else if(CD_GOPHER_TYPE == GTYPE_CSO)
|
|
CE_STATUS = net_begin_gopher_cso(connection_data);
|
|
else
|
|
CD_NEXT_STATE = GOPHER_TRANSFER_BINARY;
|
|
break;
|
|
|
|
case GOPHER_TRANSFER_MENU:
|
|
CE_STATUS = net_parse_menu(cur_entry);
|
|
break;
|
|
|
|
case GOPHER_TRANSFER_CSO:
|
|
CE_STATUS = net_parse_cso(cur_entry);
|
|
break;
|
|
|
|
case GOPHER_TRANSFER_BINARY:
|
|
CE_STATUS = net_pull_gopher_data(cur_entry);
|
|
break;
|
|
|
|
case GOPHER_DONE:
|
|
NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
PR_Close(CE_SOCK);
|
|
NET_TotalNumberOfOpenConnections--;
|
|
COMPLETE_STREAM;
|
|
CD_NEXT_STATE = GOPHER_FREE;
|
|
break;
|
|
|
|
case GOPHER_ERROR_DONE:
|
|
if(CE_SOCK != NULL)
|
|
{
|
|
NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_SOCK);
|
|
NET_ClearDNSSelect(CE_WINDOW_ID, CE_SOCK);
|
|
PR_Close(CE_SOCK);
|
|
NET_TotalNumberOfOpenConnections--;
|
|
}
|
|
if(CD_STREAM)
|
|
ABORT_STREAM(CE_STATUS);
|
|
CD_NEXT_STATE = GOPHER_FREE;
|
|
break;
|
|
|
|
case GOPHER_FREE:
|
|
if(CD_DESTROY_GRAPH_PROGRESS)
|
|
FE_GraphProgressDestroy(CE_WINDOW_ID,
|
|
CE_URL_S,
|
|
CD_ORIGINAL_CONTENT_LENGTH,
|
|
CE_BYTES_RECEIVED);
|
|
PR_FREEIF(CD_COMMAND);
|
|
PR_FREEIF(CD_STREAM); /* don't forget the stream */
|
|
PR_FREEIF(CD_OUTPUT_BUF);
|
|
PR_FREEIF(CD_DATA_BUF);
|
|
if(CD_TCP_CON_DATA)
|
|
NET_FreeTCPConData(CD_TCP_CON_DATA);
|
|
|
|
PR_Free(connection_data);
|
|
return(-1); /* all done */
|
|
|
|
} /* end switch(NEXT_STATE) */
|
|
|
|
|
|
if(CE_STATUS < 0 && CD_NEXT_STATE != GOPHER_DONE &&
|
|
CD_NEXT_STATE != GOPHER_ERROR_DONE &&
|
|
CD_NEXT_STATE != GOPHER_FREE)
|
|
{
|
|
CD_NEXT_STATE = GOPHER_ERROR_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
}
|
|
|
|
} /* end while */
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
/* abort the connection in progress
|
|
*/
|
|
PRIVATE int32
|
|
net_InterruptGopher(ActiveEntry * cur_entry)
|
|
{
|
|
GopherConData * connection_data = (GopherConData *)cur_entry->con_data;
|
|
|
|
CD_NEXT_STATE = GOPHER_ERROR_DONE;
|
|
CE_STATUS = MK_INTERRUPTED;
|
|
|
|
return(net_ProcessGopher(cur_entry));
|
|
}
|
|
|
|
/* Free any memory
|
|
*/
|
|
PRIVATE void
|
|
net_CleanupGopher(void)
|
|
{
|
|
/* nothing to free */
|
|
return;
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
NET_InitGopherProtocol(void)
|
|
{
|
|
static NET_ProtoImpl gopher_proto_impl;
|
|
|
|
gopher_proto_impl.init = net_GopherLoad;
|
|
gopher_proto_impl.process = net_ProcessGopher;
|
|
gopher_proto_impl.interrupt = net_InterruptGopher;
|
|
gopher_proto_impl.resume = NULL;
|
|
gopher_proto_impl.cleanup = net_CleanupGopher;
|
|
|
|
NET_RegisterProtocolImplementation(&gopher_proto_impl, GOPHER_TYPE_URL);
|
|
}
|