about summary refs log tree commit diff stats
path: root/WWW/Library/Implementation/HTFTP.c
diff options
context:
space:
mode:
Diffstat (limited to 'WWW/Library/Implementation/HTFTP.c')
-rw-r--r--WWW/Library/Implementation/HTFTP.c229
1 files changed, 166 insertions, 63 deletions
diff --git a/WWW/Library/Implementation/HTFTP.c b/WWW/Library/Implementation/HTFTP.c
index 4ae5d9b6..2c7593ce 100644
--- a/WWW/Library/Implementation/HTFTP.c
+++ b/WWW/Library/Implementation/HTFTP.c
@@ -78,10 +78,9 @@ BUGS:	@@@	Limit connection cache size!
 #include <HTUtils.h>
 
 #include <HTAlert.h>
-#include <HTTCP.h>
-#include <HTTP.h>
 
 #include <HTFTP.h>	/* Implemented here */
+#include <HTTCP.h>
 
 /* this define should be in HTFont.h :( */
 #define HT_NON_BREAK_SPACE ((char)1)   /* For now */
@@ -101,7 +100,6 @@ BUGS:	@@@	Limit connection cache size!
 #define INFINITY 512
 
 #include <HTParse.h>
-#include <HTTCP.h>
 #include <HTAnchor.h>
 #include <HTFile.h>	/* For HTFileFormat() */
 #include <HTBTree.h>
@@ -338,12 +336,15 @@ PRIVATE int close_connection ARGS1(
 	connection *,	con)
 {
     connection * scan;
-    int status = NETCLOSE(con->socket);
-    if (TRACE) {
-	CTRACE((tfp, "HTFTP: Closing control socket %d\n", con->socket));
+    int status;
+    CTRACE((tfp, "HTFTP: Closing control socket %d\n", con->socket));
+    status = NETCLOSE(con->socket);
+    if (TRACE && status != 0) {
 #ifdef UNIX
-	if (status != 0)
-	    perror("HTFTP:close_connection");
+	CTRACE((tfp, "HTFTP:close_connection: %s", LYStrerror(errno)));
+#else
+	if (con->socket != INVSOC)
+	    HTInetStatus("HTFTP:close_connection");
 #endif
     }
     con->socket = -1;
@@ -389,32 +390,26 @@ PRIVATE char *help_message_cache_contents NOARGS
    return(help_message_buffer);
 }
 
-/*	Execute Command and get Response
-**	--------------------------------
-**
-**	See the state machine illustrated in RFC959, p57. This implements
-**	one command/reply sequence.  It also interprets lines which are to
-**	be continued, which are marked with a "-" immediately after the
-**	status code.
+/*	Send One Command
+**	----------------
 **
-**	Continuation then goes on until a line with a matching reply code
-**	an a space after it.
+**	This function checks whether we have a control connection, and sends
+**	one command if given.
 **
 ** On entry,
-**	con	points to the connection which is established.
+**	control	points to the connection which is established.
 **	cmd	points to a command, or is NIL to just get the response.
 **
-**	The command is terminated with the CRLF pair.
+**	The command should already be terminated with the CRLF pair.
 **
 ** On exit,
-**	returns:  The first digit of the reply type,
-**		  or negative for communication failure.
+**	returns:  1 for success,
+**		  or negative for communication failure (in which case
+**		  the control connection will be closed).
 */
-PRIVATE int response ARGS1(
+PRIVATE int write_cmd ARGS1(
 	char *,		cmd)
 {
-    int result;				/* Three-digit decimal code */
-    int continuation_response = -1;
     int status;
 
     if (!control) {
@@ -440,6 +435,39 @@ PRIVATE int response ARGS1(
 	    return status;
 	}
     }
+    return 1;
+}
+
+/*	Execute Command and get Response
+**	--------------------------------
+**
+**	See the state machine illustrated in RFC959, p57. This implements
+**	one command/reply sequence.  It also interprets lines which are to
+**	be continued, which are marked with a "-" immediately after the
+**	status code.
+**
+**	Continuation then goes on until a line with a matching reply code
+**	an a space after it.
+**
+** On entry,
+**	control	points to the connection which is established.
+**	cmd	points to a command, or is NIL to just get the response.
+**
+**	The command must already be terminated with the CRLF pair.
+**
+** On exit,
+**	returns:  The first digit of the reply type,
+**		  or negative for communication failure.
+*/
+PRIVATE int response ARGS1(
+	char *,		cmd)
+{
+    int result;				/* Three-digit decimal code */
+    int continuation_response = -1;
+    int status;
+
+    if ((status = write_cmd(cmd)) < 0)
+	return status;
 
     do {
 	char *p = response_text;
@@ -513,6 +541,14 @@ PRIVATE int response ARGS1(
     return result/100;
 }
 
+PRIVATE int send_cmd_nowait ARGS1(char *, verb)
+{
+    char command[20];
+
+    sprintf(command, "%.*s%c%c", (int) sizeof(command)-4, verb, CR, LF);
+    return write_cmd(command);
+}
+
 PRIVATE int send_cmd_1 ARGS1(char *, verb)
 {
     char command[80];
@@ -1029,7 +1065,7 @@ PRIVATE int close_master_socket NOARGS
     int status;
 
     if (master_socket != -1)
-	FD_CLR( (unsigned) master_socket, &open_sockets);
+	FD_CLR(master_socket, &open_sockets);
     status = NETCLOSE(master_socket);
     CTRACE((tfp, "HTFTP: Closed master socket %d\n", master_socket));
     master_socket = -1;
@@ -1207,7 +1243,7 @@ PRIVATE int get_listen_socket NOARGS
     }
   }
     CTRACE((tfp, "TCP: Master socket(), bind() and listen() all OK\n"));
-    FD_SET( (unsigned) master_socket, &open_sockets);
+    FD_SET(master_socket, &open_sockets);
     if ((master_socket+1) > num_sockets)
 	num_sockets = master_socket+1;
 
@@ -1447,9 +1483,9 @@ PRIVATE void parse_ls_line ARGS2(
 } /* parse_ls_line() */
 
 /*
- * parse_sls_line() --
+ * parse_dls_line() --
  *	Extract the name and size info and whether it refers to a
- *      directory from a LIST line in OS/2 "dls" format.
+ *      directory from a LIST line in "dls" format.
  */
 PRIVATE void parse_dls_line ARGS3(
 	char *,		line,
@@ -2056,8 +2092,8 @@ PRIVATE EntryInfo * parse_dir_entry ARGS3(
 	case DLS_SERVER:
 
 	    /*
-	    **	Interpret and edit LIST output from OS/2 server in
-	    **  "dls" format.
+	    **	Interpret and edit LIST output from a Unix server
+	    **  in "dls" format.
 	    **  This one must have claimed to be Unix in order to
 	    **  get here; if the first line looks fishy, we revert
 	    **  to Unix and hope that fits better (this recovery is
@@ -2565,6 +2601,9 @@ PRIVATE int read_directory ARGS4(
 	    HTChunkClear(chunk);
 
 	    if (HTCheckForInterrupt()) {
+		CTRACE((tfp,
+		       "read_directory: interrupted after %d bytes\n",
+		       BytesReceived));
 		WasInterrupted = TRUE;
 		if (BytesReceived) {
 		    goto unload_btree;	/* unload btree */
@@ -2578,10 +2617,14 @@ PRIVATE int read_directory ARGS4(
 
 	    /*	 read directory entry
 	     */
+	    interrupted_in_next_data_char = FALSE;
 	    for (;;) {			/* Read in one line as filename */
 		ic = NEXT_DATA_CHAR;
 AgainForMultiNet:
 		if (interrupted_in_next_data_char) {
+		    CTRACE((tfp,
+			   "read_directory: interrupted_in_next_data_char after %d bytes\n",
+			   BytesReceived));
 		    WasInterrupted = TRUE;
 		    if (BytesReceived) {
 			goto unload_btree;  /* unload btree */
@@ -2775,26 +2818,24 @@ unload_btree:
 
     FREE(lastpath);
 
-    if (server_type == APPLESHARE_SERVER ||
-	server_type == NETPRESENZ_SERVER ||
-	WasInterrupted)			    {
+    if (WasInterrupted || data_soc != -1) { /* should always be true */
 	/*
 	 *  Without closing the data socket first,
-	 *  the response(NIL) below hangs. - KW
-	 *  Seems to also be needed if the xfer
-	 *  was interrupted ("z" or ^G).  - KED
+	 *  the response(NIL) later may hang.
+	 *  Some servers expect the client to fin/ack the close
+	 *  of the data connection before proceeding with the
+	 *  conversation on the control connection. - kw
 	 */
-	NETCLOSE(data_soc);
+	CTRACE((tfp, "HTFTP: Closing data socket %d\n", data_soc));
+	status = NETCLOSE(data_soc);
+	if (status == -1)
+	    HTInetStatus("close");	/* Comment only */
+	data_soc = -1;
     }
 
     if (WasInterrupted || HTCheckForInterrupt()) {
-	if (server_type != CMS_SERVER)
-	    response(NIL);
 	_HTProgress(TRANSFER_INTERRUPTED);
-	return HT_LOADED;
     }
-    if (server_type != CMS_SERVER)
-	response(NIL);
     return HT_LOADED;
 #ifdef NOTDEFINED
     return response(NIL) == 2 ? HT_LOADED : -1;
@@ -2818,8 +2859,11 @@ PUBLIC int HTFTPLoad ARGS4(
 {
     BOOL isDirectory = NO;
     HTAtom * encoding = NULL;
-    int status;
+    int status, final_status;
     int retry;			/* How many times tried? */
+    int outstanding = 1;	/* outstanding control connection responses
+				   that we are willing to wait for, if we
+				   get to the point of reading data - kw */
     HTFormat format;
 
     /* set use_list to NOT since we don't know what kind of server
@@ -3429,20 +3473,38 @@ listen:
 #else
 /* @@ */
 #endif /* LISTEN */
+    if ((status = send_cmd_nowait("QUIT")) == 1)
+	outstanding++;
     if (isDirectory) {
 	if (server_type == UNIX_SERVER && !unsure_type &&
 	    !strcmp(response_text,
 		    "150 Opening ASCII mode data connection for /bin/dl.\n")) {
-	    CTRACE((tfp, "HTFTP: Treating as OS/2 \"dls\" server.\n"));
+	    CTRACE((tfp, "HTFTP: Treating as \"dls\" server.\n"));
 	    server_type = DLS_SERVER;
 	}
-	status = read_directory (anchor, name, format_out, sink);
-	NETCLOSE(data_soc);
-	NETCLOSE(control->socket);
-	control->socket = -1;
-	init_help_message_cache();  /* to free memory */
-	return status;
-      /* returns HT_LOADED or error */
+	final_status = read_directory (anchor, name, format_out, sink);
+	if (final_status > 0) {
+	    if (server_type != CMS_SERVER)
+		if (outstanding-- > 0) {
+		    status = response(NIL);
+		    if (status < 0 ||
+			(status == 2 && !strncmp(response_text, "221", 3)))
+			outstanding = 0;
+		}
+	} else {		/* HT_INTERRUPTED */
+	    /* User may have pressed 'z' to give up because no
+	       packets got through, so let's not make them wait
+	       any longer - kw */
+	    outstanding = 0;
+	}
+
+	if (data_soc != -1) { /* normally done in read_directory */
+	    CTRACE((tfp, "HTFTP: Closing data socket %d\n", data_soc));
+	    status = NETCLOSE(data_soc);
+	    if (status == -1)
+		HTInetStatus("close");	/* Comment only */
+	}
+	status = final_status;
     } else {
 	int rv;
 	int len;
@@ -3494,31 +3556,72 @@ listen:
 	_HTProgress (gettext("Receiving FTP file."));
 	rv = HTParseSocket(format, format_out, anchor, data_soc, sink);
 
+#if 0				/* already done in HTCopy - kw */
 	if (rv == HT_INTERRUPTED)
 	     _HTProgress(TRANSFER_INTERRUPTED);
+#endif
 
 	HTInitInput(control->socket);
 	/* Reset buffering to control connection DD 921208 */
 
-	status = NETCLOSE(data_soc);
-	CTRACE((tfp, "HTFTP: Closing data socket %d\n", data_soc));
+	if (rv < 0) {
+#if 0
+	    if (rv == HT_INTERRUPTED || rv == -501)
+		if (send_cmd_nowait("ABOR") == 1) {
+		    outstanding++;
+		    CTRACE((tfp, "HTFTP: outstanding responses: %d\n", outstanding));
+		}
+#endif
+	    if (rv == -2)	/* weird error, don't expect much response */
+		outstanding--;
+	    else if (rv == HT_INTERRUPTED || rv == -1)
+		/* User may have pressed 'z' to give up because no
+		   packets got through, so let's not make them wait
+		   longer - kw */
+		outstanding = 0;
+	    CTRACE((tfp, "HTFTP: Closing data socket %d\n", data_soc));
+	    status = NETCLOSE(data_soc);
+	} else
+	    status = 2;	/* data_soc already closed in HTCopy - kw */
+
 	if (status < 0 && rv != HT_INTERRUPTED && rv != -1) {
 	    (void) HTInetStatus("close");	/* Comment only */
 	    data_soc = -1;			/* invalidate it */
 	} else {
-	    data_soc = -1;			/* invalidate it */
-	    status = response(NIL);		/* Pick up final reply */
-	    if (status != 2 && rv != HT_INTERRUPTED && rv != -1) {
-		init_help_message_cache();  /* to free memory */
-		return HTLoadError(sink, 500, response_text);
+	    if (rv != HT_LOADED && outstanding--) {
+		status = response(NIL);		/* Pick up final reply */
+		if (status != 2 && rv != HT_INTERRUPTED && rv != -1) {
+		    data_soc = -1;		/* invalidate it */
+		    init_help_message_cache();  /* to free memory */
+		    return HTLoadError(sink, 500, response_text);
+		} else if (status <= 0) {
+		    outstanding = 0;
+		} else if (status == 2 && !strncmp(response_text, "221", 3))
+		    outstanding = 0;
 	    }
 	}
-
-	NETCLOSE(control->socket);
-	control->socket = -1;
-	init_help_message_cache();  /* to free memory */
-	return HT_LOADED;
+	final_status = HT_LOADED;
+    }
+    while (outstanding-- > 0 &&
+	   (status > 0)) {
+	status = response(NIL);
+	if (status == 2 && !strncmp(response_text, "221", 3))
+	    break;
     }
+    data_soc = -1;			/* invalidate it */
+    CTRACE((tfp, "HTFTPLoad: normal end; "));
+    if (control->socket < 0) {
+	CTRACE((tfp, "control socket is %d\n", control->socket));
+    } else {
+	CTRACE((tfp, "closing control socket %d\n", control->socket));
+	status = NETCLOSE(control->socket);
+	if (status == -1)
+	    HTInetStatus("control connection close");	/* Comment only */
+    }
+    control->socket = -1;
+    init_help_message_cache();  /* to free memory */
+      /* returns HT_LOADED (always for file if we get here) or error */
+    return final_status;
 } /* open_file_read */
 
 /*