ftp.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:24k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/ftp.c 1.37 2000/03/20 18:47:14 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5e.
  4.   Functions for getting URLs using FTP.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1997,98,99,2000 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <sys/time.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <time.h>
  20. #include "wwwoffle.h"
  21. #include "misc.h"
  22. #include "config.h"
  23. #include "errors.h"
  24. #include "sockets.h"
  25. #include "proto.h"
  26. /*+ Set this to 1 to see the full dialog with the FTP server. +*/
  27. #define DEBUG_FTP 0
  28. /*+ Set to the name of the proxy if there is one. +*/
  29. static char *proxy=NULL;
  30. /*+ The file descriptor of the socket +*/
  31. static int server_ctrl=-1,      /*+ for the control connection to the server. +*/
  32.            server_data=-1;      /*+ for the data connection to the server. +*/
  33. /*+ A buffer to contain the reply +*/
  34. static char *bufferhead=NULL,   /*+ head. +*/
  35.             *buffer=NULL,       /*+ body. +*/
  36.             *buffertail=NULL;   /*+ tail. +*/
  37. /*+ The number of characters in the buffer +*/
  38. static int nbufferhead=0,       /*+ in total for the head . +*/
  39.            nreadhead=0,         /*+ that have been read from the head. +*/
  40.            nbuffer=0,           /*+ in total for the body part. +*/
  41.            nread=0,             /*+ that have been read for the body. +*/
  42.            nbuffertail=0,       /*+ in total for the tail . +*/
  43.            nreadtail=0;         /*+ that have been read from the tail. +*/
  44. static char *htmlise_dir_entry(char *line);
  45. /*++++++++++++++++++++++++++++++++++++++
  46.   Open a connection to get a URL using FTP.
  47.   char *FTP_Open Returns NULL on success, a useful message on error.
  48.   URL *Url The URL to open.
  49.   ++++++++++++++++++++++++++++++++++++++*/
  50. char *FTP_Open(URL *Url)
  51. {
  52.  char *msg=NULL;
  53.  char *colon;
  54.  char *server_host=NULL;
  55.  int server_port=Protocols[Protocol_FTP].defport;
  56.  /* Sort out the host. */
  57.  proxy=WhichProxy(Url->proto,Url->host);
  58.  if(IsLocalNetHost(Url->host))
  59.     proxy=NULL;
  60.  if(proxy)
  61.    {
  62.     server_host=(char*)malloc(strlen(proxy)+1);
  63.     strcpy(server_host,proxy);
  64.    }
  65.  else
  66.    {
  67.     server_host=(char*)malloc(strlen(Url->host)+1);
  68.     strcpy(server_host,Url->host);
  69.    }
  70.  if((colon=strchr(server_host,':')))
  71.    {
  72.     *colon++=0;
  73.     if(*colon)
  74.        server_port=atoi(colon);
  75.    }
  76.  /* Open the connection. */
  77.  server_ctrl=OpenClientSocket(server_host,server_port,ConnectTimeout);
  78.  init_buffer(server_ctrl);
  79.  if(server_ctrl==-1)
  80.     msg=PrintMessage(Warning,"Cannot open the FTP control connection to %s port %d; [%!s].",server_host,server_port);
  81.  free(server_host);
  82.  return(msg);
  83. }
  84. /*++++++++++++++++++++++++++++++++++++++
  85.   Write to the server to request the URL.
  86.   char *FTP_Request Returns NULL on success, a useful message on error.
  87.   URL *Url The URL to get.
  88.   Header *request_head The head of the HTTP request for the URL.
  89.   Body *request_body The body of the HTTP request for the URL.
  90.   ++++++++++++++++++++++++++++++++++++++*/
  91. char *FTP_Request(URL *Url,Header *request_head,Body *request_body)
  92. {
  93.  char *msg=NULL,*str=NULL;
  94.  char *path,*file=NULL;
  95.  char *host,*mimetype=NULL;
  96.  char *msg_reply=NULL;
  97.  char *timestamp,sizebuf[32];
  98.  int i,l,port_l,port_h;
  99.  struct tm modtime;
  100.  time_t mtime;
  101.  char *user,*pass;
  102.  /* Initial setting up. */
  103.  sizebuf[0]=0;
  104.  time(&mtime);
  105.  modtime=*gmtime(&mtime);
  106.  /* Take a simple route if it is proxied. */
  107.  if(proxy)
  108.    {
  109.     char *head;
  110.     MakeRequestAuthorised(proxy,request_head);
  111.     head=HeaderString(request_head);
  112.     PrintMessage(ExtraDebug,"Outgoing Request Head (to proxy)n%s",head);
  113.     if(write_string(server_ctrl,head)==-1)
  114.        msg=PrintMessage(Warning,"Failed to write to remote FTP proxy [%!s].");
  115.     if(request_body && write_data(server_ctrl,request_body->content,request_body->length)==-1)
  116.        msg=PrintMessage(Warning,"Failed to write to remote FTP proxy [%!s].");
  117.     free(head);
  118.     return(msg);
  119.    }
  120.  /* Else Sort out the path. */
  121.  path=URLDecode(Url->path,0);
  122.  if(path[strlen(path)-1]=='/')
  123.    {
  124.     path[strlen(path)-1]=0;
  125.     file=NULL;
  126.    }
  127.  else
  128.     for(i=strlen(path)-1;i>=0;i--)
  129.        if(path[i]=='/')
  130.          {
  131.           path[i]=0;
  132.           file=&path[i+1];
  133.           break;
  134.          }
  135.  if(Url->user)
  136.    {
  137.     user=Url->user;
  138.     pass=Url->pass;
  139.    }
  140.  else
  141.     WhatFTPUserPass(Url->host,&user,&pass);
  142.  /* send all the RFC959 commands. */
  143.  server_data=-1;
  144.  do
  145.    {
  146.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  147.     PrintMessage(ExtraDebug,"FTP: connected; got: %s",str);
  148.     if(!file && !*path && str && isdigit(str[0]) && isdigit(str[1]) && isdigit(str[2]) && str[3]=='-')
  149.       {
  150.        if(msg_reply)
  151.          {
  152.           msg_reply=(char*)realloc((void*)msg_reply,strlen(msg_reply)+strlen(str));
  153.           strcat(msg_reply,str+4);
  154.          }
  155.        else
  156.          {
  157.           msg_reply=(char*)malloc(strlen(str));
  158.           strcpy(msg_reply,str+4);
  159.          }
  160.       }
  161.    }
  162.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  163.  if(!str || atoi(str)!=220)
  164.    {
  165.     if(str)
  166.       {
  167.        char *p=str+strlen(str)-1;
  168.        while(*p=='n' || *p=='r') *p--=0;
  169.        msg=PrintMessage(Warning,"Got '%s' message when connected to FTP server.",str);
  170.       }
  171.     else
  172.        msg=PrintMessage(Warning,"No reply from FTP server when connected; timed out?");
  173.     return(msg);
  174.    }
  175.  /* Login */
  176.  if(write_formatted(server_ctrl,"USER %srn",user)==-1)
  177.    {
  178.     msg=PrintMessage(Warning,"Failed to write 'USER' command to remote FTP host [%!s].");
  179.     return(msg);
  180.    }
  181.  do
  182.    {
  183.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  184.     PrintMessage(ExtraDebug,"FTP: sent 'USER %s'; got: %s",user,str);
  185.    }
  186.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  187.  if(!str || (atoi(str)!=230 && atoi(str)!=331))
  188.    {
  189.     if(str)
  190.       {
  191.        char *p=str+strlen(str)-1;
  192.        while(*p=='n' || *p=='r') *p--=0;
  193.        msg=PrintMessage(Warning,"Got '%s' message after sending 'USER' command to FTP server.",str);
  194.       }
  195.     else
  196.        msg=PrintMessage(Warning,"No reply from FTP server to 'USER' command; timed out?");
  197.     return(msg);
  198.    }
  199.  if(atoi(str)==331)
  200.    {
  201.     if(write_formatted(server_ctrl,"PASS %srn",pass)==-1)
  202.       {
  203.        msg=PrintMessage(Warning,"Failed to write 'PASS' command to remote FTP host [%!s].");
  204.        return(msg);
  205.       }
  206.     do
  207.       {
  208.        str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  209.        PrintMessage(ExtraDebug,"FTP: sent 'PASS %s'; got: %s",pass,str);
  210.        if(!file && !*path && str && isdigit(str[0]) && isdigit(str[1]) && isdigit(str[2]) && str[3]=='-')
  211.          {
  212.           if(msg_reply)
  213.             {
  214.              msg_reply=(char*)realloc((void*)msg_reply,strlen(msg_reply)+strlen(str));
  215.              strcat(msg_reply,str+4);
  216.             }
  217.           else
  218.             {
  219.              msg_reply=(char*)malloc(strlen(str));
  220.              strcpy(msg_reply,str+4);
  221.             }
  222.          }
  223.       }
  224.     while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  225.     if(!str || (atoi(str)!=202 && atoi(str)!=230))
  226.       {
  227.        if(str)
  228.          {
  229.           char *p=str+strlen(str)-1;
  230.           while(*p=='n' || *p=='r') *p--=0;
  231.           msg=PrintMessage(Warning,"Got '%s' message after sending 'PASS' command to FTP server.",str);
  232.          }
  233.        else
  234.           msg=PrintMessage(Warning,"No reply from FTP server to 'PASS' command; timed out?");
  235.        return(msg);
  236.       }
  237.    }
  238.  /* Change directory */
  239.  if(write_formatted(server_ctrl,"CWD %srn",*path?path:"/")==-1)
  240.    {
  241.     msg=PrintMessage(Warning,"Failed to write 'CWD' command to remote FTP host [%!s].");
  242.     return(msg);
  243.    }
  244.  do
  245.    {
  246.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  247.     PrintMessage(ExtraDebug,"FTP: sent 'CWD %s' got: %s",*path?path:"/",str);
  248.     if(!file && str && isdigit(str[0]) && isdigit(str[1]) && isdigit(str[2]) && str[3]=='-')
  249.       {
  250.        if(msg_reply)
  251.          {
  252.           msg_reply=(char*)realloc((void*)msg_reply,strlen(msg_reply)+strlen(str));
  253.           strcat(msg_reply,str+4);
  254.          }
  255.        else
  256.          {
  257.           msg_reply=(char*)malloc(strlen(str));
  258.           strcpy(msg_reply,str+4);
  259.          }
  260.       }
  261.    }
  262.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  263.  if(!str || atoi(str)!=250)
  264.    {
  265.     if(str)
  266.       {
  267.        char *p=str+strlen(str)-1;
  268.        while(*p=='n' || *p=='r') *p--=0;
  269.        msg=PrintMessage(Warning,"Got '%s' message after sending 'CWD' command to FTP server.",str);
  270.       }
  271.     else
  272.        msg=PrintMessage(Warning,"No reply from FTP server to 'CWD' command; timed out?");
  273.     return(msg);
  274.    }
  275.  /* Change directory again to see if file is a dir. */
  276.  if(file)
  277.    {
  278.     if(write_formatted(server_ctrl,"CWD %srn",file)==-1)
  279.       {
  280.        msg=PrintMessage(Warning,"Failed to write 'CWD' command to remote FTP host [%!s].");
  281.        return(msg);
  282.       }
  283.     do
  284.       {
  285.        str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  286.        PrintMessage(ExtraDebug,"FTP: sent 'CWD %s' got: %s",file,str);
  287.       }
  288.     while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  289.     if(!str || (atoi(str)!=250 && atoi(str)!=501 && atoi(str)!=530 && atoi(str)!=550))
  290.       {
  291.        if(str)
  292.          {
  293.           char *p=str+strlen(str)-1;
  294.           while(*p=='n' || *p=='r') *p--=0;
  295.           msg=PrintMessage(Warning,"Got '%s' message after sending 'CWD' command to FTP server.",str);
  296.          }
  297.        else
  298.           msg=PrintMessage(Warning,"No reply from FTP server to 'CWD' command; timed out?");
  299.        return(msg);
  300.       }
  301.     if(atoi(str)==250)
  302.       {
  303.        char *loc=(char*)malloc(strlen(Url->link)+2);
  304.        strcpy(loc,Url->link);
  305.        strcat(loc,"/");
  306.        bufferhead=HTMLMessageHead(-1,302,"Is a directory",
  307.                                   "Location",loc,
  308.                                   NULL);
  309.        buffer=HTMLMessageBody(-1,"FTPDirRedirect",
  310.                               "url",Url->link,
  311.                               NULL);
  312.        free(loc);
  313.        goto near_end;
  314.       }
  315.    }
  316.  /* Set mode to binary or ASCII */
  317.  if(write_formatted(server_ctrl,"TYPE %crn",file?'I':'A')==-1)
  318.    {
  319.     msg=PrintMessage(Warning,"Failed to write 'TYPE' command to remote FTP host [%!s].");
  320.     return(msg);
  321.    }
  322.  do
  323.    {
  324.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  325.     PrintMessage(ExtraDebug,"FTP: sent 'TYPE %c'; got: %s",file?'I':'A',str);
  326.    }
  327.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  328.  if(!str || atoi(str)!=200)
  329.    {
  330.     if(str)
  331.       {
  332.        char *p=str+strlen(str)-1;
  333.        while(*p=='n' || *p=='r') *p--=0;
  334.        msg=PrintMessage(Warning,"Got '%s' message after sending 'TYPE' command to FTP server.",str);
  335.       }
  336.     else
  337.        msg=PrintMessage(Warning,"No reply from FTP server to 'TYPE' command; timed out?");
  338.     return(msg);
  339.    }
  340.  if(!strcmp(request_head->method,"GET"))
  341.    {
  342.     /* Try and get the size and modification time. */
  343.     if(file)
  344.       {
  345.        if(write_formatted(server_ctrl,"SIZE %srn",file)==-1)
  346.          {
  347.           msg=PrintMessage(Warning,"Failed to write 'SIZE' command to remote FTP host [%!s].");
  348.           return(msg);
  349.          }
  350.        do
  351.          {
  352.           str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  353.           PrintMessage(ExtraDebug,"FTP: sent 'SIZE %s'; got: %s",file,str);
  354.          }
  355.        while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  356.        if (atoi(str) == 213)
  357.           if (str[4])
  358.              sprintf(sizebuf, "%ld", (long)atoi(str+4));
  359.        if(write_formatted(server_ctrl,"MDTM %srn",file)==-1)
  360.          {
  361.           msg=PrintMessage(Warning,"Failed to write 'MDTM' command to remote FTP host [%!s].");
  362.           return(msg);
  363.          }
  364.        do
  365.          {
  366.           str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  367.           PrintMessage(ExtraDebug,"FTP: sent 'MDTM %s'; got: %s",file,str);
  368.          }
  369.        while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  370.        if (atoi(str) == 213)
  371.          {
  372.           int year, mon, mday, hour, min, sec;
  373.           if (sscanf(str, "%*d %4d%2d%2d%2d%2d%2d", &year, &mon, &mday, &hour, &min, &sec) == 6)
  374.             {
  375.              memset(&modtime, 0, sizeof(modtime));
  376.              modtime.tm_year = year - 1900;
  377.              modtime.tm_mon = mon - 1;
  378.              modtime.tm_mday = mday;
  379.              modtime.tm_hour = hour;
  380.              modtime.tm_min = min;
  381.              modtime.tm_sec = sec;
  382.             }
  383.          }
  384.       }
  385.    }
  386.  /* Create the data connection. */
  387.  if(write_string(server_ctrl,"PASVrn")==-1)
  388.    {
  389.     msg=PrintMessage(Warning,"Failed to write 'PASV' command to remote FTP host [%!s].");
  390.     return(msg);
  391.    }
  392.  do
  393.    {
  394.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  395.     PrintMessage(ExtraDebug,"FTP: sent 'PASV'; got: %s",str);
  396.    }
  397.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  398.  if(!str || atoi(str)!=227)
  399.    {
  400.     if(str)
  401.       {
  402.        char *p=str+strlen(str)-1;
  403.        while(*p=='n' || *p=='r') *p--=0;
  404.        msg=PrintMessage(Warning,"Got '%s' message after sending 'PASV' command",str);
  405.       }
  406.     else
  407.        msg=PrintMessage(Warning,"No reply from FTP server to 'PASV' command; timed out?");
  408.     return(msg);
  409.    }
  410.  if((host=strchr(str,',')))
  411.    {
  412.     while(isdigit(*--host));
  413.     host++;
  414.    }
  415.  if(!host || sscanf(host,"%*d,%*d,%*d,%*d%n,%d,%d",&l,&port_h,&port_l)!=2)
  416.    {
  417.     char *p=str+strlen(str)-1;
  418.     while(*p=='n' || *p=='r') *p--=0;
  419.     msg=PrintMessage(Warning,"Got '%s' message after sending 'PASV' command, cannot parse.",str);
  420.     return(msg);
  421.    }
  422.  host[l]=0;
  423.  for(;l>0;l--)
  424.     if(host[l]==',')
  425.        host[l]='.';
  426.  server_data=OpenClientSocket(host,port_l+256*port_h,ConnectTimeout);
  427.  init_buffer(server_data);
  428.  if(server_data==-1)
  429.    {
  430.     msg=PrintMessage(Warning,"Cannot open the FTP data connection [%!s].");
  431.     return(msg);
  432.    }
  433.  /* Make the request */
  434.  if(!strcmp(request_head->method,"GET"))
  435.    {
  436.     if(file)
  437.       {
  438.        if(write_formatted(server_ctrl,"RETR %srn",file)==-1)
  439.          {
  440.           msg=PrintMessage(Warning,"Failed to write 'RETR' command to remote FTP host [%!s].");
  441.           return(msg);
  442.          }
  443.        do
  444.          {
  445.           str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  446.           PrintMessage(ExtraDebug,"FTP: sent 'RETR %s'; got: %s",file,str);
  447.          }
  448.        while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  449.        mimetype=WhatMIMEType(file);
  450.       }
  451.     else
  452.       {
  453.        if(write_string(server_ctrl,"LIST -arn")==-1)
  454.          {
  455.           msg=PrintMessage(Warning,"Failed to write 'LIST -a' command to remote FTP host [%!s].");
  456.           return(msg);
  457.          }
  458.        do
  459.          {
  460.           str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  461.           PrintMessage(ExtraDebug,"FTP: sent 'LIST -a'; got: %s",str);
  462.          }
  463.        while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  464.        mimetype="text/html";
  465.       }
  466.     if(str && (atoi(str)==150 || atoi(str)==125))
  467.       {
  468.        char *p=str;
  469.        while(*p!='r' && *p!='n')
  470.           p++;
  471.        *p=0;
  472.       }
  473.     else
  474.       {
  475.        if(str)
  476.          {
  477.           char *p=str+strlen(str)-1;
  478.           while(*p=='n' || *p=='r') *p--=0;
  479.           msg=PrintMessage(Warning,"Got '%s' message after sending '%s' command to FTP server.",str,file?"RETR":"LIST -a");
  480.          }
  481.        else
  482.           msg=PrintMessage(Warning,"No reply from FTP server to '%s' command; timed out?",file?"RETR":"LIST -a");
  483.        return(msg);
  484.       }
  485.    }
  486.  else if(file) /* PUT */
  487.    {
  488.     if(file)
  489.       {
  490.        if(write_formatted(server_ctrl,"STOR %srn",file)==-1)
  491.          {
  492.           msg=PrintMessage(Warning,"Failed to write 'STOR' command to remote FTP host [%!s].");
  493.           return(msg);
  494.          }
  495.        do
  496.          {
  497.           str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  498.           PrintMessage(ExtraDebug,"FTP: sent 'STOR %s'; got: %s",file,str);
  499.          }
  500.        while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  501.        mimetype="text/html";
  502.       }
  503.     else
  504.       {
  505.        msg=PrintMessage(Warning,"Cannot use the PUT method on a directory name");
  506.        return(msg);
  507.       }
  508.     if(str && (atoi(str)==150 || atoi(str)==125))
  509.       {
  510.        char *p=str;
  511.        while(*p!='r' && *p!='n')
  512.           p++;
  513.        *p=0;
  514.       }
  515.     else
  516.       {
  517.        if(str)
  518.          {
  519.           char *p=str+strlen(str)-1;
  520.           while(*p=='n' || *p=='r') *p--=0;
  521.           msg=PrintMessage(Warning,"Got '%s' message after sending 'STOR' command to FTP server.",str);
  522.          }
  523.        else
  524.           msg=PrintMessage(Warning,"No reply from FTP server to 'STOR' command; timed out?");
  525.        return(msg);
  526.       }
  527.     write_data(server_data,request_body->content,request_body->length);
  528.    }
  529.  /* Prepare the HTTP header. */
  530.  if(!strcmp(request_head->method,"GET"))
  531.    {
  532.     mtime=mktime(&modtime);
  533.     if(mtime!=-1)
  534.        timestamp=RFC822Date(mtime,1);
  535.     else
  536.        timestamp=RFC822Date(time(NULL),1);
  537.  
  538.     if(*sizebuf)
  539.        bufferhead=HTMLMessageHead(-1,200,str+4,
  540.                                   "Content-Type",mimetype,
  541.                                   "Last-Modified",timestamp,
  542.                                   "Content-Length",sizebuf,
  543.                                   NULL);
  544.     else
  545.        bufferhead=HTMLMessageHead(-1,200,str+4,
  546.                                   "Content-Type",mimetype,
  547.                                   "Last-Modified",timestamp,
  548.                                   NULL);
  549.    }
  550.  else
  551.    {
  552.     bufferhead=HTMLMessageHead(-1,200,str+4,
  553.                                "Content-Type",mimetype,
  554.                                NULL);
  555.    }
  556.  buffer=NULL;
  557.  buffertail=NULL;
  558.  if(!strcmp(request_head->method,"GET"))
  559.    {
  560.     if(!file)
  561.       {
  562.        if(msg_reply)
  563.          {
  564.           char *old_msg_reply=msg_reply;
  565.           msg_reply=HTMLString(msg_reply);
  566.           free(old_msg_reply);
  567.          }
  568.        buffer=HTMLMessageBody(-1,"FTPDir-Head",
  569.                               "url",URLDecode(Url->name,0),
  570.                               "message",msg_reply,
  571.                               NULL);
  572.        buffertail=HTMLMessageBody(-1,"FTPDir-Tail",
  573.                                   NULL);
  574.       }
  575.    }
  576.  else
  577.    {
  578.     buffer=HTMLMessageBody(-1,"FTPPut",
  579.                            "url",URLDecode(Url->name,0),
  580.                            NULL);
  581.    }
  582. near_end:
  583.  if(msg_reply)
  584.     free(msg_reply);
  585.  nbufferhead=strlen(bufferhead); nreadhead=0;
  586.  nbuffer=buffer?strlen(buffer):0; nread=0;
  587.  nbuffertail=buffertail?strlen(buffertail):0; nreadtail=0;
  588.  free(str);
  589.  free(path);
  590.  return(msg);
  591. }
  592. /*++++++++++++++++++++++++++++++++++++++
  593.   Read a line from the header of the reply for the URL.
  594.   char *FTP_ReadHead Returns the next line of data, NULL on EOF.
  595.   char *line The previous line read.
  596.   ++++++++++++++++++++++++++++++++++++++*/
  597. char *FTP_ReadHead(char *line)
  598. {
  599.  char *l=line;
  600.  int m;
  601.  /* Take a simple route if it is proxied. */
  602.  if(proxy)
  603.     return(read_line_or_timeout(server_ctrl,line,SocketTimeout));
  604.  
  605.  /* Else send the header. */
  606.  if(nreadhead==nbufferhead)
  607.     return(NULL);
  608.  for(m=nreadhead;m<nbufferhead;m++)
  609.     if(bufferhead[m]=='n')
  610.        break;
  611.  m++;
  612.  l=(char*)realloc((void*)l,m-nreadhead+1);
  613.  strncpy(l,&bufferhead[nreadhead],m-nreadhead);
  614.  l[m-nreadhead]=0;
  615.  nreadhead=m;
  616.  return(l);
  617. }
  618. /*++++++++++++++++++++++++++++++++++++++
  619.   Read bytes from the body of the reply for the URL.
  620.   int FTP_ReadBody Returns the number of bytes read on success, -1 on error.
  621.   char *s A string to fill in with the information.
  622.   int n The number of bytes to read.
  623.   ++++++++++++++++++++++++++++++++++++++*/
  624. int FTP_ReadBody(char *s,int n)
  625. {
  626.  int m=0;
  627.  /* Take a simple route if it is proxied. */
  628.  if(proxy)
  629.     return(read_data_or_timeout(server_ctrl,s,n,SocketTimeout));
  630.  
  631.  /* Else send the data then the tail. */
  632.  if(server_data==-1)            /* Redirection */
  633.    {
  634.     for(;nread<nbuffer && m<n;nread++,m++)
  635.        s[m]=buffer[nread];
  636.     for(;nreadtail<nbuffertail && m<n;nreadtail++,m++)
  637.        s[m]=buffertail[nreadtail];
  638.    }
  639.  else if(!buffer && !buffertail) /* File not dir entry. */
  640.     m=read_data_or_timeout(server_data,s,n,SocketTimeout);
  641.  else if(buffer && buffertail)  /* Middle of dir entry */
  642.    {
  643.     for(;nread<nbuffer && m<n;nread++,m++)
  644.        s[m]=buffer[nread];
  645.     if(nread==nbuffer)
  646.       {
  647.        buffer=htmlise_dir_entry(buffer);
  648.        if(buffer)
  649.           nbuffer=strlen(buffer),nread=0;
  650.       }
  651.     if(!buffer)
  652.        for(;nreadtail<nbuffertail && m<n;nreadtail++,m++)
  653.           s[m]=buffertail[nreadtail];
  654.    }
  655.  else if(!buffer && buffertail) /* End of dir entry. */
  656.    {
  657.     for(;nreadtail<nbuffertail && m<n;nreadtail++,m++)
  658.        s[m]=buffertail[nreadtail];
  659.    }
  660.  else /* if(buffer && !buffertail) */ /* Done a PUT */
  661.    {
  662.     for(;nread<nbuffer && m<n;nread++,m++)
  663.        s[m]=buffer[nread];
  664.    }
  665.  return(m);
  666. }
  667. /*++++++++++++++++++++++++++++++++++++++
  668.   Close a connection opened using FTP.
  669.   int FTP_Close Return 0 on success, -1 on error.
  670.   ++++++++++++++++++++++++++++++++++++++*/
  671. int FTP_Close(void)
  672. {
  673.  int err=0;
  674.  char *str=NULL;
  675.  /* Take a simple route if it is proxied. */
  676.  if(proxy)
  677.     return(CloseSocket(server_ctrl));
  678.  /* Else say goodbye and close all of the sockets, */
  679.  if(server_data!=-1)
  680.     CloseSocket(server_data);
  681.  write_string(server_ctrl,"QUITrn");
  682.  do
  683.    {
  684.     str=read_line_or_timeout(server_ctrl,str,SocketTimeout);
  685.     PrintMessage(ExtraDebug,"FTP: sent 'QUIT'; got: %s",str);
  686.    }
  687.  while(str && (!isdigit(str[0]) || !isdigit(str[1]) || !isdigit(str[2]) || str[3]!=' '));
  688.  err=CloseSocket(server_ctrl);
  689.  if(bufferhead)
  690.     free(bufferhead);
  691.  if(buffer)
  692.     free(buffer);
  693.  if(buffertail)
  694.     free(buffertail);
  695.  return(err);
  696. }
  697. /*++++++++++++++++++++++++++++++++++++++
  698.   Convert a line from the ftp server dir listing into a pretty listing.
  699.   char *htmlise_dir_entry Returns the next line.
  700.   char *line The previous line.
  701.   ++++++++++++++++++++++++++++++++++++++*/
  702. static char *htmlise_dir_entry(char *line)
  703. {
  704.  int i,isdir=0,islink=0;
  705.  char *q,*p[16],*l,*file=NULL,*link=NULL;
  706.  l=read_line_or_timeout(server_data,line,SocketTimeout);
  707.  if(!l)
  708.     return(l);
  709.  for(q=l,i=0;*q && i<16;i++)
  710.    {
  711.     while(*q==' ' || *q=='t')
  712.        q++;
  713.     if(*q=='n' || *q=='r')
  714.        break;
  715.     if(*q)
  716.        p[i]=q;
  717.     while(*q && *q!=' ' && *q!='t' && *q!='r' && *q!='n')
  718.        q++;
  719.    }
  720.  if((*p[0]=='-' || *p[0]=='d' || *p[0]=='l') && i>=8) /* A UNIX 'ls -l' listing. */
  721.    {
  722.     if(i==8)
  723.       {file=p[7]; link=file;}
  724.     else if(i==10 && (*p[8]=='-' && *(p[8]+1)=='>'))
  725.       {file=p[7]; link=p[9];}
  726.     else if(i==9)
  727.       {file=p[8]; link=file;}
  728.     else if(i==11 && (*p[9]=='-' && *(p[9]+1)=='>'))
  729.       {file=p[8]; link=p[10];}
  730.     if(*p[0]=='d')
  731.        isdir=1;
  732.     if(*p[0]=='l')
  733.        islink=1;
  734.    }
  735.  if(file)
  736.    {
  737.     char *endf,endfc,*endl,endlc,*ll,*fileurlenc,*linkurlenc;
  738.     endf=file;
  739.     while(*endf && *endf!=' ' && *endf!='t' && *endf!='r' && *endf!='n')
  740.        endf++;
  741.     endfc=*endf;
  742.     endl=link;
  743.     while(*endl && *endl!=' ' && *endl!='t' && *endl!='r' && *endl!='n')
  744.        endl++;
  745.     endlc=*endl;
  746.     *endf=0;
  747.     fileurlenc=URLEncode(file);
  748.     *endf=endfc;
  749.     *endl=0;
  750.     linkurlenc=URLEncode(link);
  751.     *endl=endlc;
  752.     ll=(char*)malloc(strlen(l)+strlen(fileurlenc)+strlen(linkurlenc)+40);
  753.     strncpy(ll,l,file-l);
  754.     strcpy(ll+(file-l),"<a href="");
  755.     strcat(ll,"./");
  756.     strcat(ll,fileurlenc);
  757.     if(isdir && *(endl-1)!='/')
  758.        strcat(ll,"/");
  759.     strcat(ll,"">");
  760.     *endf=0;
  761.     strcat(ll,file);
  762.     *endf=endfc;
  763.     strcat(ll,"</a>");
  764.     if(islink)
  765.       {
  766.        strncat(ll,endf,link-endf);
  767.        strcat(ll,"<a href="");
  768.        if(strncmp(linkurlenc,"../",3) && strncmp(linkurlenc,"./",2) && strncmp(linkurlenc,"/",1))
  769.           strcat(ll,"./");
  770.        strcat(ll,linkurlenc);
  771.        strcat(ll,"">");
  772.        *endl=0;
  773.        strcat(ll,link);
  774.        *endl=endlc;
  775.        strcat(ll,"</a>");
  776.        strcat(ll,endl);
  777.       }
  778.     else
  779.       {
  780.        strcat(ll,endf);
  781.       }
  782.     free(fileurlenc);
  783.     free(linkurlenc);
  784.     if(l)
  785.        free(l);
  786.     l=ll;
  787.    }
  788.  return(l);
  789. }