/********************************************************************
 * lindner
 * 3.17
 * 1993/09/27 20:05:13
 * /home/mudhoney/GopherSrc/CVS/gopher+/gopherd/ftp.c,v
 * Exp
 *
 * Paul Lindner, University of Minnesota CIS.
 *
 * Copyright 1991, 1992 by the Regents of the University of Minnesota
 * see the file "Copyright" in the distribution for conditions of use.
 *********************************************************************
 * MODULE: ftp.c
 * Routines to translate gopher protocol to ftp protocol.
 *********************************************************************
 * Revision History:
 * ftp.c,v
 * Revision 3.17  1993/09/27  20:05:13  lindner
 * Fix for broken Unix list
 *
 * Revision 3.16  1993/09/20  16:52:16  lindner
 * Fix for big ftp directories with lots of links
 *
 * Revision 3.15  1993/09/18  03:25:18  lindner
 * Fix for Mac FTPd and ftp gateway
 *
 * Revision 3.14  1993/09/18  02:21:58  lindner
 * Fix for Novell ftp servers
 *
 * Revision 3.13  1993/09/17  14:47:42  lindner
 * Totally new ftp code, eliminates tmp files
 *
 * Revision 3.12  1993/08/23  21:43:21  lindner
 * Fix for bug with symlinks
 *
 * Revision 3.11  1993/08/23  20:51:48  lindner
 * Multiple fixes from Matti Aarnio
 *
 * Revision 3.10  1993/08/11  14:41:48  lindner
 * Fix for error logging and uninitialized gs
 *
 * Revision 3.9  1993/08/11  14:08:39  lindner
 * Fix for hanging ftp gateway connections
 *
 * Revision 3.8  1993/08/03  20:43:54  lindner
 * Fix for sites that have @ -> for symbolic links
 *
 * Revision 3.7  1993/08/03  06:40:11  lindner
 * none
 *
 * Revision 3.6  1993/08/03  06:14:12  lindner
 * Fix for extra slashes
 *
 * Revision 3.5  1993/07/30  19:21:03  lindner
 * Removed debug stuff, fix for extra slashes
 *
 * Revision 3.4  1993/07/30  18:38:59  lindner
 * Move 3.3.1 to main trunk
 *
 * Revision 3.3.1.7  1993/07/29  21:42:21  lindner
 * Fixes for Symbolic links, plus removed excess variables
 *
 * Revision 3.3.1.6  1993/07/27  05:27:42  lindner
 * Mondo Debug overhaul from Mitra
 *
 * Revision 3.3.1.5  1993/07/26  17:18:55  lindner
 * Removed extraneous abort printf
 *
 * Revision 3.3.1.4  1993/07/26  15:34:21  lindner
 * Use tmpnam() and bzero(), plus ugly fixes..
 *
 * Revision 3.3.1.3  1993/07/23  03:12:29  lindner
 * Small fix for getreply, reformatting..
 *
 * Revision 3.3.1.2  1993/07/07  19:39:48  lindner
 * Much prettification, unproto-ed, and use Sockets.c routines
 *
 * Revision 3.3.1.1  1993/06/22  20:53:21  lindner
 * Bob's ftp stuff
 *
 * Revision 3.3  1993/04/15  04:48:09  lindner
 * Debug code from Mitra
 *
 * Revision 3.2  1993/03/24  20:15:06  lindner
 * FTP gateway now gets filetypes from gopherd.conf
 *
 * Revision 3.1.1.1  1993/02/11  18:02:51  lindner
 * Gopher+1.2beta release
 *
 * Revision 1.2.1 1993/04/02 12:00:01  alberti
 * Robert Alberti, alberti@boombox.micro.umn.edu, 02. Apr 93
 * Extensively rewritten tell different server types apart
 *
 * Andi Karrer, karrer@bernina.ethz.ch, 21. Feb 93
 * Added support for VMS FTP servers that do not understand the FTP PASV
 * command (Wollongong, Multinet). Also present these servers output
 * in a Unix fashion.
 * Also works with Ultrix 4.2 FTP servers whose PASV command is broken.
 *
 * Revision 1.2  1993/01/11  23:18:09  lindner
 * Changed password to be the host of the remote client, not the gateway.
 *
 * Revision 1.1  1992/12/10  23:13:27  lindner
 * gopher 1.1 release
 *
 *
 *********************************************************************/


/* -------------------------------------------------
 *     g2fd.c          Gopher to FTP gateway daemon.
 *     Version 0.3 Hacked up: April 1992.  Farhad Anklesaria.
 *     Based on a Perl story by John Ladwig.
 *     Based on a Perl story by Farhad Anklesaria.
 *
 *      Modified by Greg Smith, Bucknell University, 24 Nov 1992
 *      to handle multiline status replies.
 *
 ---------------------------------------------------- */

#include "gopherd.h"
#include "ftp.h"
#include <signal.h>

#include <stdio.h>
#include "ext.h"
#include "Debug.h"

#define SLEN 256


/** Global socket value **/
static int Gsockfd;  

boolean GETDIR = FALSE;

/*** Some forward declarations ***/
boolean NotText();
boolean IsBinaryType();
void    Cleanup();
void    FailErr();
char    *WalkDirs();


FTP *
FTPnew(host)
  char *host;
{
     FTP *temp;

     temp = (FTP*)malloc(sizeof(FTP));

     temp->control_sock = -1;
     temp->data_sock    = -1;
     temp->mode         = 'A';
     temp->Ftptype      = FTP_UNKNOWN;
     FTPconnect(temp, host);

     return(temp);
}


/*
 * Close connection, destroy data structures..
 */

FTPdestroy(ftp)
  FTP *ftp;
{
     FTPcloseData(ftp);

     if (FTPgetControl(ftp) != -1) {
	  FTPbyebye(ftp);
	  close(FTPgetControl(ftp));
     }

     free(ftp);
}


/* 
  Establish connection, validate DNS name,
  connect and return control pointer
*/

boolean
FTPconnect(ftp, host)
  FTP  *ftp;
  char *host;
{
     int newcontrol;
     char message[256];
     
     /** Get ready for some cleanup action **/
     signal(SIGPIPE, FTPcleanup);
     signal(SIGINT, FTPcleanup);
     signal(SIGALRM, FTPcleanup);
     
     newcontrol = SOCKconnect(host,21);

     if (newcontrol < 0)
	  return(newcontrol);

     FTPsetControl(ftp,newcontrol);

     FTPgetReply(ftp, 299, message, sizeof(message));

     if (strcasestr(message, "NetWare"))
	  FTPsetType(ftp, FTP_NOVELL);
     else if (strcasestr(message, "SunOS"))
	  FTPsetType(ftp, FTP_UNIX);
     else if (strcasestr(message, "MultiNet FTP"))
	  FTPsetType(ftp, FTP_VMS);
     else if (strcasestr(message, "Windows NT FTP"))
	  FTPsetType(ftp, FTP_WINNT);
     else if (strcasestr(message, "Peter's Macintosh FTP daemon"))
	  FTPsetType(ftp, FTP_MACOS);


     FTPfindType(ftp);

     return(0);
}


char *
FTPpwd(ftp)
  FTP *ftp;
{
     static char pwd[256];
     char message[256];
     int ftpnum;

     FTPsend(ftp, "PWD");
     ftpnum = FTPgetReply(ftp, 999, message, sizeof(message));
     
     if (ftpnum != 257)
	  return(NULL);
     
     sscanf(message,"%*[^\"]%*c%[^\"]%*s",pwd);
     
     return(pwd);
}


FTPfindType(ftp)
  FTP *ftp;
{
     int ftpnum;
     char message[256];

     if (FTPgetType(ftp) != FTP_UNKNOWN)
	  return;

     FTPsend(ftp, "SYST");
     ftpnum = FTPgetReply(ftp, 999, message, sizeof(message));
     
     if (ftpnum == 215) {
	  Debug("Analyzing ftp syst output\n", NULL);
	  if (strncmp(message+4, "MTS", 3) == 0 ||
	      strncmp(message+4, "VMS", 3) == 0) {
	       FTPsetType(ftp, FTP_VMS);
	  }
	  else if (strncmp(message+4, "UNIX", 4)==0)
	       FTPsetType(ftp, FTP_UNIX);
	  else if (strncmp(message+4, "MACOS", 5)==0)
	       FTPsetType(ftp, FTP_MACOS);
     }
}

/* Send a string across the control channel 
   Returns true if an error, false otherwise
*/
boolean
FTPsend(ftp, command)
  FTP  *ftp;
  char *command;
{
     Debug("--> %s\n", command);

     if (writestring(FTPgetControl(ftp), command) <0)
	  return(TRUE);

     if (writestring(FTPgetControl(ftp), "\r\n") <0)
	  return(TRUE);

     return(FALSE);
}


/* Find the numeric value of the message */

int
FTPfindNum(ftp, message)
  FTP  *ftp;
  char *message;
{
     int ftpnum;

     ftpnum = (message[0] - '0') * 100 +
	      (message[1] - '0') * 10 +
	      (message[2] - '0');

     return(ftpnum);
}


boolean
FTPisContinuation(ftp, message)
  FTP  *ftp;
  char *message;
{
     return(message[3] == '-');
}


/*
 * Get a reply from the FTP control channel.
 */

int
FTPgetReply(ftp, errorlevel, message, maxlen)
  FTP  *ftp;
  int  errorlevel;
  char *message;
  int  maxlen;
{
     int ftpnum;

     ftpnum = FTPgetReplyline(ftp, message, maxlen);

     if (ftpnum > errorlevel) {
	  /*** Had an error ***/
	  FTPerrorMessage(ftp, message);

	  while (FTPisContinuation(ftp, message)) {
	       ftpnum = FTPgetReplyline(ftp, message, maxlen);
	       FTPerrorMessage(ftp, message);
	  }

	  FTPabort(ftp);
	  return(ftpnum);
     }

     while (FTPisContinuation(ftp, message)) {
	  FTPinfoMessage(ftp, message);

	  ftpnum = FTPgetReplyline(ftp, message, maxlen);
     }
     return(ftpnum);
}

/*
 * Gets a reply on the control socket.. fills message with what it
 * got back and returns the integer value of the return code.
 */

int
FTPgetReplyline(ftp, message, maxlen)
  FTP  *ftp;
  char *message;
  int  maxlen;
{
     int ftpnum, i;

     i = readline(FTPgetControl(ftp), message, maxlen);
     
     Debug("<-- %s\n",message);

     if (i < 0)
	  return(-1);
     
     ftpnum = FTPfindNum(ftp, message);
     
     return(ftpnum);
}


/*
 * Execute a specific ftp command (an sprintf style thing)
 *    replace %s with parameter
 *    fail when above errorlevel
 */

int
FTPcommand(ftp, command, parameter, errorlevel)
  FTP  *ftp;
  char *command;
  char *parameter;
  int  errorlevel;
{
     char commandline[512];
     char message[256];
     int  val;
     
     sprintf(commandline, command, parameter);
     if (FTPsend(ftp, commandline))
	  return(-1); /** Error condition **/

     FTPgetReply(ftp, errorlevel, message, sizeof(message));
}
    

/*
 * Send USER and PASS
 */

void
FTPlogin(ftp, username, password)
  FTP  *ftp;
  char *username;
  char *password;
{
     /*** Send username ***/
     FTPcommand(ftp, "USER %s", username, 399);

     /** Send password ***/
     FTPcommand(ftp, "PASS %s", password, 399);
     
}



FTPbyebye(ftp)
  FTP *ftp;
{
     FTPcommand(ftp, "QUIT", NULL, 399);
}


/** Open a data connection **/
FTPopenData(ftp, command, file, errorlevel)
  FTP *ftp;
  char *command;
  char *file;
  int errorlevel;
{
     struct sockaddr_in we;
     char   theline[512];
     int ftp_dataport, ftp_data;

     if ((ftp_dataport = SOCKlisten(&we)) < 0)
	  ;
     
     sprintf(theline, "PORT %d,%d,%d,%d,%d,%d",
	     (htonl(we.sin_addr.s_addr) >> 24) & 0xFF,
	     (htonl(we.sin_addr.s_addr) >> 16) & 0xFF,
	     (htonl(we.sin_addr.s_addr) >>  8) & 0xFF,
	     (htonl(we.sin_addr.s_addr)      ) & 0xFF,
	     (htons(we.sin_port)        >>  8) & 0xFF,
	     (htons(we.sin_port)             ) & 0xFF);
     
     FTPsend(ftp, theline);
     FTPgetReply(ftp, 201, theline, sizeof(theline));
     

     FTPcommand(ftp, command, file, errorlevel);

     ftp_data = SOCKaccept(ftp_dataport, we);

     if (ftp_data < -1)
	  return(-1);

     FTPsetData(ftp, ftp_data);

}


void
FTPcloseData(ftp)
  FTP *ftp;
{
     if (FTPgetData(ftp) != -1)
	  close(FTPgetData(ftp));
}

int
FTPread(ftp, buf, bufsize)
  FTP *ftp;
  char *buf;
  int bufsize;
{
     int len;

     len = read(FTPgetData(ftp), buf, bufsize);

     return(len);
}


/*--------------------------------*/
/* Used in xLateText below --------*/
boolean
NotText(buf)
  char * buf;
{
     int max;   char *c;
     
     if ((max = strlen(buf)) >= (BUFSIZ - 50)) max = BUFSIZ - 50;
     for (c = buf; c < (buf + max); c++) {
	  if (*c > '~') return(TRUE);
     }
     return(FALSE);
}



/*--------------------------------*/

boolean
IsBinaryType(path)
  char *path;
{
     char Gtype;
     Extobj *ext;
     
     if (GDCViewExtension(Config, path, &ext)) {
	  Gtype = EXgetObjtype(ext);
	  
	  if(Gtype == A_FILE || Gtype == A_MACHEX) 
	       return FALSE;
	  else
	       return TRUE;
     } else
	  return(FALSE);
     
}


/*--------------------------------*/
void
TrimEnd(bufptr)
  char *bufptr;
{
     int last;
     for (last = strlen(bufptr) - 1; isspace(bufptr[last]) ; bufptr[last--] = '\0')
	  ;
}

int
Vaxinate(bufptr)
  char *bufptr;
{
     int last;
     
     /* strip ugly VMS version numbers */
     for (last = strlen(bufptr) - 1; (last>1) && (isdigit(bufptr[last]) || bufptr[last] == ';') ; last--)
          bufptr[last] = '\0';
     
     /* if bufptr ends in ".dir", it's a directory, replace ".dir" with "/" */
     if((last > 3) && (strncmp(bufptr + last - 3, ".dir", 4) == 0))
     {
	  last -= 3;
	  bufptr[last] = '/';
	  bufptr[last+1]  = '\0';
     }
     return(last);
}


char *
FTPwalkchdir(ftp, path)
  FTP  *ftp;
  char *path;
{
     char *beg, *end;
     char vmspath[256], inputline[512];
     
     /* path looks like '/dir/dir.../dir/' now. Because Wollongong
      * wants "CWD dir/dir/dir" and Multinet wants "CWD dir.dir.dir"
      * so we do the CWD in a stepwise fashion. Oh well...
      */
     
     beg = path+1;
     for (end = beg; (*end != '\0') && (*end != '/'); ++end); 
     
     while (*end != '\0')
     {
	  bzero(vmspath, 256);
	  strncpy(vmspath, beg, end-beg);
	  
	  FTPchdir(ftp, vmspath);

	  beg=end+1; /* Skip slash */
	  for (end = beg; (*end != '\0') && (*end != '/'); ++end); 
     }
     
     return(beg);
}


/*--------------------------------*/

void
FTPcleanup()
{
     ;
}


void
FTPerrorMessage(ftp, message)
  FTP *ftp;
  char *message;
{
     char errmsg[256];
     
     sprintf(errmsg, "3%s\t\terror.host\t1\r\n", message);
     writestring(Gsockfd, errmsg);

}

void
FTPinfoMessage(ftp, message)
  FTP *ftp;
  char *message;
{
     char errmsg[256];
     
     if (GETDIR) {
	  sprintf(errmsg, "i%s\t\terror.host\t1\r\n", message);
	  writestring(Gsockfd, errmsg);
     }

}

FTPabort(ftp)
  FTP *ftp;
{
     writestring(Gsockfd, ".\r\n");
     FTPdestroy(ftp);
     exit(-1);
}


/*
 * Implement ftp--> gopher gateway
 */

GopherFTPgw(sockfd, ftpstr)
  int  sockfd;
  char *ftpstr;
{
     FTP  *ftp;
     char *cp;
     char *ftphost, *ftpuser, ftppass[256], *ftppath;
     char hostname[256];
     char buf[8192];
     int blen;
     char lastchar;
     
     /* Find @ and parse out */
     cp = strchr(ftpstr, '@');
     if (cp == NULL)
	  return(NULL);

     *cp = '\0';
     
     ftppath = cp+1;
     ftphost = ftpstr;
     ftpuser = "anonymous";
     SOCKnetnames(sockfd, hostname, NULL);
     sprintf(ftppass, "-gopher@%s", hostname);

     /** find the last character **/
     lastchar = ftppath[strlen(ftppath)-1];
     if (lastchar == '/')
	  GETDIR = TRUE;
     else
	  GETDIR = FALSE;

     /***  here we go...!***/

     ftp = FTPnew(ftphost);
     if (ftp == NULL)
	  return(NULL);

     FTPlogin(ftp, ftpuser, ftppass);


     if (lastchar == '/') {
	  char thename[256];
	  char outputline[512];

	  /*** Do the directory ***/
	  ftppath[strlen(ftppath)-1] = '\0';

	  if (strlen(ftppath) > 1) {	  
	       if (FTPgetType(ftp) == FTP_VMS 
		   || FTPgetType(ftp) == FTP_NOVELL
		   || FTPgetType(ftp) == FTP_MACOS) {
		    int len = strlen(ftppath);
		    
		    ftppath[len] =  '/'; /*** Ick!***/
		    ftppath[len+1] = '\0';
		    
		    FTPwalkchdir(ftp, ftppath);
		    ftppath[len] = '\0';
	       }
	       else 
		    FTPchdir(ftp, ftppath);
	  }

	  switch(FTPgetType(ftp)) {

	  case FTP_UNKNOWN:
	  case FTP_UNIX:
	  case FTP_WINNT:
	       FTPopenData(ftp, "LIST -LF", NULL, 299);
	       break;

	  case FTP_NOVELL:
	       FTPopenData(ftp, "LIST", NULL, 299);
	       break;

	  case FTP_MACOS:
	       FTPopenData(ftp, "NLST -LF", NULL, 299);
	       break;

	  default:
	  case FTP_VMS:
	       FTPopenData(ftp, "NLST", NULL, 299);
	       break;
	  }

	  while (readline(FTPgetData(ftp), buf, sizeof(buf))) {
	       ZapCRLF(buf);

	       switch (FTPgetType(ftp)) {
	       case FTP_NOVELL:
		    if (GopherList(ftp, buf, thename) == -1)
			 continue;
		    
		    sprintf(outputline, "%s\tftp:%s@%s/%s\t%s\t%d\r\n",
			    thename,ftphost, ftppath, buf, Zehostname, 
			    GopherPort);
		    break;

	       case FTP_MACOS:
	       case FTP_VMS:
		    GopherType(ftp, buf, thename);
		    sprintf(outputline, "%s\tftp:%s@%s/%s\t%s\t%d\r\n",
			    thename, ftphost, ftppath, buf, Zehostname, 
			    GopherPort);
		    break;
		    
	       default:
	       case FTP_WINNT:
	       case FTP_UNKNOWN:
	       case FTP_UNIX:
		    if (GopherList(ftp, buf, thename) == -1)
			 continue;

		    sprintf(outputline, "%s\tftp:%s@%s/%s\t%s\t%d\r\n",
			    thename,ftphost, ftppath, buf, Zehostname, 
			    GopherPort);
	       }
	       writestring(sockfd, outputline);
	  }
	  writestring(sockfd, ".\r\n");
     }
     else {
	  char *fname;
	  if (FTPgetType(ftp) == FTP_VMS 
	      || FTPgetType(ftp) == FTP_NOVELL
	      || FTPgetType(ftp) == FTP_MACOS)
	       fname = FTPwalkchdir(ftp, ftppath);
	  else
	       fname = ftppath;

	  if (IsBinaryType(ftppath)) {
	       Debug("Getting binary %s\n", ftppath);

	       FTPbinary(ftp);
	       FTPopenData(ftp, "RETR %s", fname, 299);

	       while ((blen = FTPread(ftp, buf, sizeof(buf)))>0)
		      writen(sockfd, buf, blen);
	  }
	  else {
	       Debug("Getting ascii %s\n", ftppath);

	       FTPascii(ftp);
	       FTPopenData(ftp, "RETR %s", fname, 199);

	       blen = FTPread(ftp, buf, sizeof(buf));
	       while (blen > 0) {
		    writen(sockfd, buf, blen);
		    blen = FTPread(ftp, buf, sizeof(buf));
	       }
	       writestring(sockfd, ".\r\n");
	  }

     }
     FTPcloseData(ftp);
     FTPdestroy(ftp);
}


/*************************************************************
 Takes the LIST output and 
 truncates it to just the name
 Handles special cases for different
 formats of LIST output
******************************/

int
GopherList(ftp, bufptr, theName) 
  FTP  *ftp;
  char *bufptr;
  char *theName;
{
     char Gzerotype;
     char *IntName = NULL;
     
     if (IntName == NULL)
	  IntName = (char *)malloc(BUFSIZ);
     
     *IntName = '\0';

     /* Skip 'total' line */
     if (strncmp(bufptr, "total", 5) == 0)
	  return (-1); 

     /* Trim whitespaces */
     TrimEnd(bufptr); 
     
     switch (FTPgetType(ftp))
     {
     case FTP_NOVELL:
	  strcpy(IntName,&bufptr[61]);
	  
	  if (bufptr[0] == 'd')
	  {
	       sprintf(theName, "%c%s", A_DIRECTORY, IntName);
	       sprintf(bufptr, "%s/", IntName);
	       return(A_DIRECTORY);
	  }
	  else
	  {
	       Gzerotype = GopherType(ftp, IntName, theName);
	       sprintf(bufptr, "%s", IntName);
	  }
	  break;

     case FTP_UNIX:
     case FTP_WINNT:
	  Debug("Parsing Unix List\n", NULL);
	  Gzerotype = ParseUnixList(ftp, bufptr, IntName, theName, 8);
	  break;

     case FTP_UNKNOWN:
     default:
	  Debug("Parsing Unknown List\n", NULL);
	  Gzerotype = ParseUnixList(ftp, bufptr, IntName, theName, 7);
	  break;
     }
     return(Gzerotype);
}


int
ParseUnixList(ftp, bufptr, IntName, theName, cols)
  FTP  *ftp;
  char *bufptr;
  char *IntName;
  char *theName;
  int cols;
{
     char *cp;
     int i, end;
     int gap;
     char *dirname, *alias;
     
     end = strlen(bufptr);

     /*** Skip the permissions bits.. ***/
     i = 11;
     if (bufptr[i] == ' ')
	  i++;

     for (i= 10, gap=0; (gap < cols) && (i < end); gap++)
     {
	  /* Skip chars to white */
	  for (;(!isspace(bufptr[i])) && (i < end); i++);
	  
	  if (i >= end) 
	       FTPerrorMessage("said it was Unix but wasn't");
	  
	  /* Skip white to chars */
	  for (;isspace(bufptr[i]) && (i < end); i++);
	  
	  if (i >= end) 
	       FTPerrorMessage("said Unix but wasn't");
     }

     /* Point at supposed start-of-fileIntName */
     dirname = alias = &bufptr[i]; 
     
     if (dirname[strlen(dirname)-1] == '/')
	  dirname[strlen(dirname)-1] = '\0';

     switch(bufptr[0])
     {
     case 'l': /* Link? Skip to REAL IntName! */
	  /* [mea] Or do you ? Handle the symlink semantics ??
	     Is it really a directory, or a file ?       */

 	  /* Data is of   foobar@ -> barfoo format, that is, separator is
 	     5 characters "@ -> " */
	  

	  for (dirname = alias ; (*dirname != '\0') && (dirname != NULL);
	       ++dirname) {
	       if (strncmp(dirname, "@ -> ",5) == 0)
		    break;
	  }
	  if (dirname == NULL)
	       return(-1); /* No real DirName?  Hm.  Oh well */
	  
	  /*Internal name in 'IntName' */
 	  strncpy(IntName,alias,dirname-alias);
 	  IntName[dirname-alias] = 0; /* Make sure it terminates */

	  /* Display name in theName */
	  sprintf(theName, "%c%s", A_DIRECTORY, IntName );

	  if (IntName[strlen(IntName)-1] == '@')
	       IntName[strlen(IntName)-1] = '\0';

	  /* Tag slash on end */
	  sprintf(bufptr, "%s/", IntName);
	  
	  return(A_DIRECTORY);
	  break;
	  
     case 'd': /* Now treat as regular directory */
	  /* Display name in theName */
	  sprintf(theName, "%c%s", A_DIRECTORY, dirname);

	  /*Internal name in 'IntName' */
	  strcpy(IntName,dirname); 

	  /* Tag slash on end */
	  sprintf(bufptr, "%s/", IntName);
	  return(A_DIRECTORY);
	  break;
	  
     default: 
	  /* Determine type of file */
	  strcpy(IntName, dirname); 
	  GopherType(ftp, IntName, theName);
	  strcpy(bufptr, theName+1);
	  break;
     }
     return(i);
}


int
GopherType(ftp, bufptr, theName)
  FTP  *ftp;
  char *bufptr;
  char *theName;
{
     int last;
     
     if (FTPgetType(ftp) == FTP_VMS) 
	  last = Vaxinate(bufptr);
     else
	  last = strlen(bufptr)-1;
     
     
     if (bufptr[last] == '/')
     {
	  sprintf(theName, "%c%s", A_DIRECTORY, bufptr);
	  theName[strlen(theName)-1] = '\0';
	  return(A_DIRECTORY);
     }
     
     if ((bufptr[last] == '*') || (bufptr[last] == '@'))     /* Hack out * and @ */
	  bufptr[last] = '\0';
     
     
     return(GopherFile(ftp, bufptr, theName));
}



/* At this point we're looking at a file */

int
GopherFile(ftp, buf, theName)
  FTP  *ftp;
  char *buf;
  char *theName;
{
     char	Gtype;
     int	last;
     char	tmpName[SLEN];	
     Extobj     *ext;
     
     last = strlen(buf) -1;
     
     strcpy(tmpName, buf);
     if (buf[last] == '/') {
	  tmpName[last] = '\0';
	  sprintf(theName, "%c%s", A_DIRECTORY, tmpName);
	  return;
     }
     if ((buf[last] == '*') || (buf[last] == '@')) {	/* Hack out * and @ */
	  buf[last] = '\0';
	  tmpName[last] = '\0';
     }
     
     /* At this point we're looking at a file */
     if (GDCViewExtension(Config, buf, &ext)) {  
	  Gtype = EXgetObjtype(ext);
	  
	  sprintf(theName, "%c%s", Gtype, tmpName);
	  return;
     }
     
     sprintf(theName, "%c%s", A_FILE, tmpName);
     return(A_FILE);	/* Some other and hopefully text file */
     ;
}
