rfc959.c
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:30k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*****************************************************************************/
  2. /*  rfc959.c - General purpose routines for the FTP protocol (RFC 959)       */
  3. /*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
  4. /*                                                                           */
  5. /*  This program is free software; you can redistribute it and/or modify     */
  6. /*  it under the terms of the GNU General Public License as published by     */
  7. /*  the Free Software Foundation; either version 2 of the License, or        */
  8. /*  (at your option) any later version.                                      */
  9. /*                                                                           */
  10. /*  This program is distributed in the hope that it will be useful,          */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  13. /*  GNU General Public License for more details.                             */
  14. /*                                                                           */
  15. /*  You should have received a copy of the GNU General Public License        */
  16. /*  along with this program; if not, write to the Free Software              */
  17. /*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
  18. /*****************************************************************************/
  19. #include "gftp.h"
  20. static const char cvsid[] = "$Id: rfc959.c,v 1.12 2002/11/23 13:45:04 masneyb Exp $";
  21. typedef struct rfc959_params_tag
  22. {
  23.   gftp_getline_buffer * sockfd_rbuf,
  24.                       * datafd_rbuf;
  25. } rfc959_parms;
  26. static int
  27. rfc959_read_response (gftp_request * request)
  28. {
  29.   char tempstr[255], code[4];
  30.   rfc959_parms * parms;
  31.   ssize_t num_read;
  32.   g_return_val_if_fail (request != NULL, -2);
  33.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  34.   g_return_val_if_fail (request->sockfd > 0, -2);
  35.   *code = '';
  36.   if (request->last_ftp_response)
  37.     {
  38.       g_free (request->last_ftp_response);
  39.       request->last_ftp_response = NULL;
  40.     }
  41.   parms = request->protocol_data;
  42.   do
  43.     {
  44.       if ((num_read = gftp_get_line (request, &parms->sockfd_rbuf, tempstr, 
  45.                                      sizeof (tempstr), request->sockfd)) <= 0)
  46. break;
  47.       if (isdigit ((int) *tempstr) && isdigit ((int) *(tempstr + 1))
  48.   && isdigit ((int) *(tempstr + 2)))
  49. {
  50.   strncpy (code, tempstr, 3);
  51.   code[3] = ' ';
  52. }
  53.       request->logging_function (gftp_logging_recv, request->user_data,
  54.  "%sn", tempstr);
  55.     }
  56.   while (strncmp (code, tempstr, 4) != 0);
  57.   if (num_read < 0)
  58.     return (-1);
  59.   request->last_ftp_response = g_malloc (strlen (tempstr) + 1);
  60.   strcpy (request->last_ftp_response, tempstr);
  61.   if (request->last_ftp_response[0] == '4' &&
  62.       request->last_ftp_response[1] == '2')
  63.     gftp_disconnect (request);
  64.   return (*request->last_ftp_response);
  65. }
  66. static int
  67. rfc959_send_command (gftp_request * request, const char *command)
  68. {
  69.   g_return_val_if_fail (request != NULL, -2);
  70.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  71.   g_return_val_if_fail (command != NULL, -2);
  72.   g_return_val_if_fail (request->sockfd > 0, -2);
  73.   if (strncmp (command, "PASS", 4) == 0)
  74.     {
  75.       request->logging_function (gftp_logging_send, request->user_data, 
  76.                                  "PASS xxxxn");
  77.     }
  78.   else if (strncmp (command, "ACCT", 4) == 0)
  79.     {
  80.       request->logging_function (gftp_logging_send, request->user_data, 
  81.                                  "ACCT xxxxn");
  82.     }
  83.   else
  84.     {
  85.       request->logging_function (gftp_logging_send, request->user_data, "%s",
  86.                                  command);
  87.     }
  88.   if (gftp_write (request, command, strlen (command), 
  89.                    request->sockfd) < 0)
  90.     return (-1);
  91.   return (rfc959_read_response (request));
  92. }
  93. static char *
  94. parse_ftp_proxy_string (gftp_request * request)
  95. {
  96.   char *startpos, *endpos, *oldstr, *newstr, *newval, *tempport;
  97.   g_return_val_if_fail (request != NULL, NULL);
  98.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, NULL);
  99.   newstr = g_malloc (1);
  100.   *newstr = '';
  101.   startpos = endpos = request->proxy_config;
  102.   while (*endpos != '')
  103.     {
  104.       tempport = NULL;
  105.       if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'p')
  106. {
  107.   switch (tolower ((int) *(endpos + 2)))
  108.     {
  109.     case 'u':
  110.       newval = request->proxy_username;
  111.       break;
  112.     case 'p':
  113.       newval = request->proxy_password;
  114.       break;
  115.     case 'h':
  116.       newval = request->proxy_hostname;
  117.       break;
  118.     case 'o':
  119.       tempport = g_strdup_printf ("%d", request->proxy_port);
  120.       newval = tempport;
  121.       break;
  122.     case 'a':
  123.       newval = request->proxy_account;
  124.       break;
  125.     default:
  126.       endpos++;
  127.       continue;
  128.     }
  129. }
  130.       else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'h')
  131. {
  132.   switch (tolower ((int) *(endpos + 2)))
  133.     {
  134.     case 'u':
  135.       newval = request->username;
  136.       break;
  137.     case 'p':
  138.       newval = request->password;
  139.       break;
  140.     case 'h':
  141.       newval = request->hostname;
  142.       break;
  143.     case 'o':
  144.       tempport = g_strdup_printf ("%d", request->port);
  145.       newval = tempport;
  146.       break;
  147.     case 'a':
  148.       newval = request->account;
  149.       break;
  150.     default:
  151.       endpos++;
  152.       continue;
  153.     }
  154. }
  155.       else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'n')
  156. {
  157.   *endpos = '';
  158.   oldstr = newstr;
  159.   newstr = g_strconcat (oldstr, startpos, "rn", NULL);
  160.   g_free (oldstr);
  161.   endpos += 2;
  162.   startpos = endpos;
  163.   continue;
  164. }
  165.       else
  166. {
  167.   endpos++;
  168.   continue;
  169. }
  170.       *endpos = '';
  171.       oldstr = newstr;
  172.       if (!newval)
  173. newstr = g_strconcat (oldstr, startpos, NULL);
  174.       else
  175. newstr = g_strconcat (oldstr, startpos, newval, NULL);
  176.       if (tempport)
  177. {
  178.   g_free (tempport);
  179.   tempport = NULL;
  180. }
  181.       g_free (oldstr);
  182.       endpos += 3;
  183.       startpos = endpos;
  184.     }
  185.   return (newstr);
  186. }
  187. static int
  188. rfc959_getcwd (gftp_request * request)
  189. {
  190.   char *pos, *dir;
  191.   int ret;
  192.   ret = rfc959_send_command (request, "PWDrn");
  193.   if (ret < 0)
  194.     return (-1);
  195.   else if (ret != '2')
  196.     {
  197.       request->logging_function (gftp_logging_error, request->user_data,
  198.  _("Received invalid response to PWD command: '%s'n"),
  199.                                  request->last_ftp_response);
  200.       gftp_disconnect (request);
  201.       return (-2);
  202.     }
  203.   if ((pos = strchr (request->last_ftp_response, '"')) == NULL)
  204.     {
  205.       request->logging_function (gftp_logging_error, request->user_data,
  206.  _("Received invalid response to PWD command: '%s'n"),
  207.                                  request->last_ftp_response);
  208.       gftp_disconnect (request);
  209.       return (-2);
  210.     }
  211.   dir = pos + 1;
  212.   if ((pos = strchr (dir, '"')) == NULL)
  213.     {
  214.       request->logging_function (gftp_logging_error, request->user_data,
  215.  _("Received invalid response to PWD command: '%s'n"),
  216.                                  request->last_ftp_response);
  217.       gftp_disconnect (request);
  218.       return (-2);
  219.     }
  220.   *pos = '';
  221.   if (request->directory)
  222.     g_free (request->directory);
  223.   request->directory = g_malloc (strlen (dir) + 1);
  224.   strcpy (request->directory, dir);
  225.   return (0);
  226. }
  227. static int
  228. rfc959_chdir (gftp_request * request, const char *directory)
  229. {
  230.   char ret, *tempstr;
  231.   g_return_val_if_fail (request != NULL, -2);
  232.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  233.   g_return_val_if_fail (directory != NULL, -2);
  234.   if (strcmp (directory, "..") == 0)
  235.     ret = rfc959_send_command (request, "CDUPrn");
  236.   else
  237.     {
  238.       tempstr = g_strconcat ("CWD ", directory, "rn", NULL);
  239.       ret = rfc959_send_command (request, tempstr);
  240.       g_free (tempstr);
  241.     }
  242.   if (ret != '2')
  243.     return (-2);
  244.   if (directory != request->directory)
  245.     {
  246.       if (rfc959_getcwd (request) < 0)
  247.         return (-1);
  248.     }
  249.   return (0);
  250. }
  251. static int
  252. rfc959_connect (gftp_request * request)
  253. {
  254.   char tempchar, *startpos, *endpos, *tempstr;
  255.   int ret, resp;
  256.   g_return_val_if_fail (request != NULL, -2);
  257.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  258.   g_return_val_if_fail (request->hostname != NULL, -2);
  259.   if (request->sockfd > 0)
  260.     return (0);
  261.   if (request->username == NULL || *request->username == '')
  262.     {
  263.       gftp_set_username (request, "anonymous");
  264.       gftp_set_password (request, emailaddr);
  265.     }
  266.   else if (strcasecmp (request->username, "anonymous") == 0)
  267.     gftp_set_password (request, emailaddr);
  268.     
  269.   if ((request->sockfd = gftp_connect_server (request, "ftp")) < 0)
  270.     return (-1);
  271.   /* Get the banner */
  272.   if (rfc959_read_response (request) != '2')
  273.     {
  274.       gftp_disconnect (request);
  275.       return (-2);
  276.     }
  277.   /* Login the proxy server if available */
  278.   if (request->use_proxy)
  279.     {
  280.       resp = '3';
  281.       startpos = endpos = tempstr = parse_ftp_proxy_string (request);
  282.       while ((resp == '3' || resp == '2') && *startpos != '')
  283. {
  284.   if (*endpos == 'n' || *endpos == '')
  285.     {
  286.       tempchar = *(endpos + 1);
  287.       if (*endpos != '')
  288. *(endpos + 1) = '';
  289.       if ((resp = rfc959_send_command (request, startpos)) < 0)
  290.                 return (-2);
  291.       if (*endpos != '')
  292. *(endpos + 1) = tempchar;
  293.       else
  294. break;
  295.       startpos = endpos + 1;
  296.     }
  297.   endpos++;
  298. }
  299.       g_free (tempstr);
  300.     }
  301.   else
  302.     {
  303.       tempstr = g_strconcat ("USER ", request->username, "rn", NULL);
  304.       resp = rfc959_send_command (request, tempstr);
  305.       g_free (tempstr);
  306.       if (resp < 0)
  307.         return (-2);
  308.       if (resp == '3')
  309. {
  310.   tempstr = g_strconcat ("PASS ", request->password, "rn", NULL);
  311.   resp = rfc959_send_command (request, tempstr);
  312.   g_free (tempstr);
  313.           if (resp < 0)
  314.             return (-2);
  315.         }
  316.       if (resp == '3' && request->account)
  317. {
  318.   tempstr = g_strconcat ("ACCT ", request->account, "rn", NULL);
  319.   resp = rfc959_send_command (request, tempstr);
  320.   g_free (tempstr);
  321.           if (resp < 0)
  322.             return (-2);
  323. }
  324.     }
  325.   if (resp != '2')
  326.     {
  327.       gftp_disconnect (request);
  328.       return (-2);
  329.     }
  330.   if (request->data_type == GFTP_TYPE_BINARY)
  331.     tempstr = "TYPE Irn";
  332.   else
  333.     tempstr = "TYPE Arn";
  334.   if (rfc959_send_command (request, tempstr) < 0)
  335.     return (-2);
  336.   ret = -1;
  337.   if (request->directory != NULL && *request->directory != '')
  338.     {
  339.       ret = rfc959_chdir (request, request->directory);
  340.       if (request->sockfd < 0)
  341.         return (-2);
  342.     }
  343.   if (ret != 0)
  344.     {
  345.       if (rfc959_getcwd (request) < 0)
  346.         return (-1);
  347.     }
  348.   if (request->sockfd < 0)
  349.     return (-2);
  350.   return (0);
  351. }
  352. static void
  353. rfc959_disconnect (gftp_request * request)
  354. {
  355.   g_return_if_fail (request != NULL);
  356.   g_return_if_fail (request->protonum == GFTP_FTP_NUM);
  357.   if (request->sockfd > 0)
  358.     {
  359.       request->logging_function (gftp_logging_misc, request->user_data,
  360.  _("Disconnecting from site %sn"),
  361.  request->hostname);
  362.       close (request->sockfd);
  363.       request->sockfd = -1;
  364.       if (request->datafd > 0)
  365. {
  366.   close (request->datafd);
  367.   request->datafd = -1;
  368. }
  369.     }
  370. }
  371. static int
  372. rfc959_data_connection_new (gftp_request * request)
  373. {
  374.   char *pos, *pos1, resp, *command;
  375.   struct sockaddr_in data_addr;
  376.   size_t data_addr_len;
  377.   unsigned int temp[6];
  378.   unsigned char ad[6];
  379.   int i;
  380.   g_return_val_if_fail (request != NULL, -2);
  381.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  382.   g_return_val_if_fail (request->sockfd > 0, -2);
  383.   if ((request->datafd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  384.     {
  385.       request->logging_function (gftp_logging_error, request->user_data,
  386.  _("Failed to create a socket: %sn"),
  387.  g_strerror (errno));
  388.       gftp_disconnect (request);
  389.       return (-1);
  390.     }
  391.   data_addr_len = sizeof (data_addr);
  392.   memset (&data_addr, 0, data_addr_len);
  393.   data_addr.sin_family = AF_INET;
  394.   if (request->transfer_type == gftp_transfer_passive)
  395.     {
  396.       if ((resp = rfc959_send_command (request, "PASVrn")) != '2')
  397. {
  398.           if (request->sockfd < 0)
  399.             return (-2);
  400.   request->transfer_type = gftp_transfer_active;
  401.   return (rfc959_data_connection_new (request));
  402. }
  403.       pos = request->last_ftp_response + 4;
  404.       while (!isdigit ((int) *pos) && *pos != '')
  405.         pos++;
  406.       if (*pos == '')
  407.         {
  408.           request->logging_function (gftp_logging_error, request->user_data,
  409.                       _("Cannot find an IP address in PASV response '%s'n"),
  410.                       request->last_ftp_response);
  411.           gftp_disconnect (request);
  412.           return (-2);
  413.         }
  414.       if (sscanf (pos, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
  415.                   &temp[3], &temp[4], &temp[5]) != 6)
  416.         {
  417.           request->logging_function (gftp_logging_error, request->user_data,
  418.                       _("Cannot find an IP address in PASV response '%s'n"),
  419.                       request->last_ftp_response);
  420.           gftp_disconnect (request);
  421.           return (-2);
  422.         }
  423.       for (i = 0; i < 6; i++)
  424.         ad[i] = (unsigned char) (temp[i] & 0xff);
  425.       memcpy (&data_addr.sin_addr, &ad[0], 4);
  426.       memcpy (&data_addr.sin_port, &ad[4], 2);
  427.       if (connect (request->datafd, (struct sockaddr *) &data_addr, 
  428.                    data_addr_len) == -1)
  429.         {
  430.           request->logging_function (gftp_logging_error, request->user_data,
  431.                                     _("Cannot create a data connection: %sn"),
  432.                                     g_strerror (errno));
  433.           gftp_disconnect (request);
  434.           return (-1);
  435. }
  436.     }
  437.   else
  438.     {
  439.       if (getsockname (request->sockfd, (struct sockaddr *) &data_addr,
  440.                        &data_addr_len) == -1)
  441.         {
  442.   request->logging_function (gftp_logging_error, request->user_data,
  443.      _("Cannot get socket name: %sn"),
  444.      g_strerror (errno));
  445.           gftp_disconnect (request);
  446.   return (-1);
  447.         }
  448.       data_addr.sin_port = 0;
  449.       if (bind (request->datafd, (struct sockaddr *) &data_addr, 
  450.                 data_addr_len) == -1)
  451. {
  452.   request->logging_function (gftp_logging_error, request->user_data,
  453.      _("Cannot bind a port: %sn"),
  454.      g_strerror (errno));
  455.           gftp_disconnect (request);
  456.   return (-1);
  457. }
  458.       if (getsockname (request->datafd, (struct sockaddr *) &data_addr, 
  459.                        &data_addr_len) == -1)
  460.         {
  461.   request->logging_function (gftp_logging_error, request->user_data,
  462.      _("Cannot get socket name: %sn"),
  463.      g_strerror (errno));
  464.           gftp_disconnect (request);
  465.   return (-1);
  466.         }
  467.       if (listen (request->datafd, 1) == -1)
  468. {
  469.   request->logging_function (gftp_logging_error, request->user_data,
  470.      _("Cannot listen on port %d: %sn"),
  471.      ntohs (data_addr.sin_port),
  472.      g_strerror (errno));
  473.           gftp_disconnect (request);
  474.   return (-1);
  475. }
  476.       pos = (char *) &data_addr.sin_addr;
  477.       pos1 = (char *) &data_addr.sin_port;
  478.       command = g_strdup_printf ("PORT %u,%u,%u,%u,%u,%urn",
  479.  pos[0] & 0xff, pos[1] & 0xff, pos[2] & 0xff,
  480.  pos[3] & 0xff, pos1[0] & 0xff,
  481.  pos1[1] & 0xff);
  482.       resp = rfc959_send_command (request, command);
  483.       g_free (command);
  484.       if (resp != '2')
  485. {
  486.           gftp_disconnect (request);
  487.   return (-2);
  488. }
  489.     }
  490.   return (0);
  491. }
  492. static int
  493. rfc959_accept_active_connection (gftp_request * request)
  494. {
  495.   struct sockaddr_in cli_addr;
  496.   size_t cli_addr_len;
  497.   int infd;
  498.   g_return_val_if_fail (request != NULL, -2);
  499.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  500.   g_return_val_if_fail (request->datafd > 0, -2);
  501.   g_return_val_if_fail (request->transfer_type == gftp_transfer_active, -2);
  502.   cli_addr_len = sizeof (cli_addr);
  503.   if (gftp_set_sockblocking (request, request->datafd, 0) == -1)
  504.     return (-1);
  505.   if ((infd = accept (request->datafd, (struct sockaddr *) &cli_addr,
  506.        &cli_addr_len)) == -1)
  507.     {
  508.       request->logging_function (gftp_logging_error, request->user_data,
  509.                                 _("Cannot accept connection from server: %sn"),
  510.                                 g_strerror (errno));
  511.       gftp_disconnect (request);
  512.       return (-1);
  513.     }
  514.   close (request->datafd);
  515.   request->datafd = infd;
  516.   if (gftp_set_sockblocking (request, request->datafd, 1) == -1)
  517.     return (-1);
  518.   return (0);
  519. }
  520. static off_t
  521. rfc959_get_file (gftp_request * request, const char *filename, int fd,
  522.                  off_t startsize)
  523. {
  524.   char *command, *tempstr, resp;
  525.   int ret;
  526.   g_return_val_if_fail (request != NULL, -2);
  527.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  528.   g_return_val_if_fail (filename != NULL, -2);
  529.   g_return_val_if_fail (request->sockfd > 0, -2);
  530.   if (fd > 0)
  531.     request->datafd = fd;
  532.   if (request->datafd < 0 && 
  533.       (ret = rfc959_data_connection_new (request)) < 0)
  534.     return (ret);
  535.   if (gftp_set_sockblocking (request, request->datafd, 1) == -1)
  536.     return (-1);
  537.   if (startsize > 0)
  538.     {
  539. #if defined (_LARGEFILE_SOURCE)
  540.       command = g_strdup_printf ("REST %lldrn", startsize); 
  541. #else
  542.       command = g_strdup_printf ("REST %ldrn", startsize); 
  543. #endif
  544.       resp = rfc959_send_command (request, command);
  545.       g_free (command);
  546.       if (resp != '3')
  547.         {
  548.           close (request->datafd);
  549.           request->datafd = -1;
  550.   return (-2);
  551.         }
  552.     }
  553.   tempstr = g_strconcat ("RETR ", filename, "rn", NULL);
  554.   ret = rfc959_send_command (request, tempstr);
  555.   g_free (tempstr);
  556.   if (ret != '1')
  557.     {
  558.       close (request->datafd);
  559.       request->datafd = -1;
  560.       return (-2);
  561.     }
  562.   if (request->transfer_type == gftp_transfer_active &&
  563.       (ret = rfc959_accept_active_connection (request)) < 0)
  564.     return (ret);
  565.   if ((tempstr = strrchr (request->last_ftp_response, '(')) == NULL)
  566.     {
  567.       tempstr = request->last_ftp_response + 4;
  568.       while (!isdigit ((int) *tempstr) && *tempstr != '')
  569. tempstr++;
  570.     }
  571.   else
  572.     tempstr++;
  573.   return (strtol (tempstr, NULL, 10) + startsize);
  574. }
  575. static int
  576. rfc959_put_file (gftp_request * request, const char *filename, int fd,
  577.                  off_t startsize, off_t totalsize)
  578. {
  579.   char *command, *tempstr, resp;
  580.   int ret;
  581.   g_return_val_if_fail (request != NULL, -2);
  582.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  583.   g_return_val_if_fail (filename != NULL, -2);
  584.   g_return_val_if_fail (request->sockfd > 0, -2);
  585.   if (fd > 0)
  586.     fd = request->datafd;
  587.   if (request->datafd < 0 && 
  588.       (ret = rfc959_data_connection_new (request)) < 0)
  589.     return (ret);
  590.   if (gftp_set_sockblocking (request, request->datafd, 1) == -1)
  591.     return (-1);
  592.   if (startsize > 0)
  593.     {
  594. #if defined (_LARGEFILE_SOURCE)
  595.       command = g_strdup_printf ("REST %lldrn", startsize); 
  596. #else
  597.       command = g_strdup_printf ("REST %ldrn", startsize); 
  598. #endif
  599.       resp = rfc959_send_command (request, command);
  600.       g_free (command);
  601.       if (resp != '3')
  602.         {
  603.           close (request->datafd);
  604.           request->datafd = -1;
  605.   return (-2);
  606.         }
  607.     }
  608.   tempstr = g_strconcat ("STOR ", filename, "rn", NULL);
  609.   ret = rfc959_send_command (request, tempstr);
  610.   g_free (tempstr);
  611.   if (ret != '1')
  612.     {
  613.       close (request->datafd);
  614.       request->datafd = -1;
  615.       return (-2);
  616.     }
  617.   if (request->transfer_type == gftp_transfer_active && 
  618.       (ret = rfc959_accept_active_connection (request)) < 0)
  619.     return (ret);
  620.   return (0);
  621. }
  622. static long 
  623. rfc959_transfer_file (gftp_request *fromreq, const char *fromfile, 
  624.                       off_t fromsize, gftp_request *toreq, 
  625.                       const char *tofile, off_t tosize)
  626. {
  627.   char *tempstr, *pos, *endpos;
  628.   g_return_val_if_fail (fromreq != NULL, -2);
  629.   g_return_val_if_fail (fromfile != NULL, -2);
  630.   g_return_val_if_fail (toreq != NULL, -2);
  631.   g_return_val_if_fail (tofile != NULL, -2);
  632.   g_return_val_if_fail (fromreq->sockfd > 0, -2);
  633.   g_return_val_if_fail (toreq->sockfd > 0, -2);
  634.   fromreq->transfer_type = gftp_transfer_passive;
  635.   toreq->transfer_type = gftp_transfer_active;
  636.   if (rfc959_send_command (fromreq, "PASVrn") != '2')
  637.     return (-2);
  638.   pos = fromreq->last_ftp_response + 4;
  639.   while (!isdigit ((int) *pos) && *pos != '') 
  640.     pos++;
  641.   if (*pos == '') 
  642.     return (-2);
  643.   endpos = pos;
  644.   while (*endpos != ')' && *endpos != '') 
  645.     endpos++;
  646.   if (*endpos == ')') 
  647.     *endpos = '';
  648.   tempstr = g_strconcat ("PORT ", pos, "rn", NULL);
  649.   if (rfc959_send_command (toreq, tempstr) != '2')
  650.      {
  651.        g_free (tempstr);
  652.        return (-2);
  653.      }
  654.   g_free (tempstr);
  655.   tempstr = g_strconcat ("RETR ", fromfile, "rn", NULL);
  656.   if (gftp_write (fromreq, tempstr, strlen (tempstr), 
  657.                    fromreq->sockfd) < 0)
  658.     {
  659.       g_free (tempstr);
  660.       return (-2);
  661.     }
  662.   g_free (tempstr);
  663.   tempstr = g_strconcat ("STOR ", tofile, "rn", NULL);
  664.   if (gftp_write (toreq, tempstr, strlen (tempstr), toreq->sockfd) < 0)
  665.     {
  666.       g_free (tempstr);
  667.       return (-2);
  668.     }
  669.   g_free (tempstr);
  670.   if (rfc959_read_response (fromreq) < 0)
  671.     return (-2);
  672.   if (rfc959_read_response (toreq) < 0)
  673.     return (-2);
  674.   return (0);
  675. }
  676. static int
  677. rfc959_end_transfer (gftp_request * request)
  678. {
  679.   g_return_val_if_fail (request != NULL, -2);
  680.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  681.   g_return_val_if_fail (request->sockfd > 0, -2);
  682.   if (request->datafd > 0)
  683.     {
  684.       close (request->datafd);
  685.       request->datafd = -1;
  686.     }
  687.   return (rfc959_read_response (request) == '2' ? 0 : -2);
  688. }
  689. static int
  690. rfc959_abort_transfer (gftp_request * request)
  691. {
  692.   int ret;
  693.   g_return_val_if_fail (request != NULL, -2);
  694.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  695.   g_return_val_if_fail (request->sockfd > 0, -2);
  696.   if (request->datafd > 0)
  697.     {
  698.       close (request->datafd);
  699.       request->datafd = -1;
  700.     }
  701.   /* We need to read two lines of output. The first one is acknowleging
  702.      the transfer and the second line acknowleges the ABOR command */
  703.   if (rfc959_send_command (request, "ABORrn") < 0)
  704.     return (-2);
  705.   if (request->sockfd > 0)
  706.     {
  707.       if ((ret = rfc959_read_response (request)) < 0)
  708.         gftp_disconnect (request);
  709.     }
  710.   
  711.   return (0);
  712. }
  713. static int
  714. rfc959_list_files (gftp_request * request)
  715. {
  716.   char *tempstr, parms[3];
  717.   int ret;
  718.   g_return_val_if_fail (request != NULL, -2);
  719.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  720.   g_return_val_if_fail (request->sockfd > 0, -2);
  721.   if ((ret = rfc959_data_connection_new (request)) < 0)
  722.     return (ret);
  723.   *parms = '';
  724.   strcat (parms, show_hidden_files ? "a" : "");
  725.   strcat (parms, resolve_symlinks ? "L" : "");
  726.   tempstr = g_strconcat ("LIST", *parms != '' ? " -" : "", parms, "rn", 
  727.                          NULL); 
  728.   ret = rfc959_send_command (request, tempstr);
  729.   g_free (tempstr);
  730.   if (ret != '1')
  731.     return (-2);
  732.   ret = 0;
  733.   if (request->transfer_type == gftp_transfer_active)
  734.     ret = rfc959_accept_active_connection (request);
  735.   return (ret);
  736. }
  737. int
  738. rfc959_get_next_file (gftp_request * request, gftp_file * fle, int fd)
  739. {
  740.   rfc959_parms * parms;
  741.   char tempstr[255];
  742.   ssize_t len;
  743.   g_return_val_if_fail (request != NULL, -2);
  744.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  745.   g_return_val_if_fail (fle != NULL, -2);
  746.   g_return_val_if_fail (fd > 0, -2);
  747.   if (request->last_dir_entry)
  748.     {
  749.       g_free (request->last_dir_entry);
  750.       request->last_dir_entry = NULL;
  751.     }
  752.   parms = request->protocol_data;
  753.   do
  754.     {
  755.       if ((len = gftp_get_line (request, &parms->datafd_rbuf,
  756.                                 tempstr, sizeof (tempstr), fd)) <= 0)
  757. {
  758.           gftp_file_destroy (fle);
  759.   return ((int) len);
  760.       if (gftp_parse_ls (tempstr, fle) != 0)
  761. {
  762.   if (strncmp (tempstr, "total", strlen ("total")) != 0 &&
  763.       strncmp (tempstr, _("total"), strlen (_("total"))) != 0)
  764.     request->logging_function (gftp_logging_error, request->user_data,
  765.        _("Warning: Cannot parse listing %sn"),
  766.        tempstr);
  767.   gftp_file_destroy (fle);
  768.   continue;
  769. }
  770.       else
  771. break;
  772.     }
  773.   while (1);
  774.   len = strlen (tempstr);
  775.   if (!request->cached)
  776.     {
  777.       request->last_dir_entry = g_strdup_printf ("%sn", tempstr);
  778.       request->last_dir_entry_len = len + 1;
  779.     }
  780.   return (len);
  781. }
  782. static int
  783. rfc959_set_data_type (gftp_request * request, int data_type)
  784. {
  785.   char *tempstr;
  786.   g_return_val_if_fail (request != NULL, -2);
  787.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  788.   if (request->sockfd > 0 && request->data_type != data_type)
  789.     {
  790.       if (data_type == GFTP_TYPE_BINARY)
  791. tempstr = "TYPE Irn";
  792.       else
  793. tempstr = "TYPE Arn";
  794.       if (rfc959_send_command (request, tempstr) != '2')
  795. return (-2);
  796.     }
  797.   request->data_type = data_type;
  798.   return (0);
  799. }
  800. static off_t
  801. rfc959_get_file_size (gftp_request * request, const char *filename)
  802. {
  803.   char *tempstr;
  804.   int ret;
  805.   g_return_val_if_fail (request != NULL, 0);
  806.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  807.   g_return_val_if_fail (filename != NULL, 0);
  808.   g_return_val_if_fail (request->sockfd > 0, 0);
  809.   tempstr = g_strconcat ("SIZE ", filename, "rn", NULL);
  810.   ret = rfc959_send_command (request, tempstr);
  811.   g_free (tempstr);
  812.   if (ret < 0)
  813.     return (-2);
  814.   if (*request->last_ftp_response != '2')
  815.     return (0);
  816.   return (strtol (request->last_ftp_response + 4, NULL, 10));
  817. }
  818. static int
  819. rfc959_rmdir (gftp_request * request, const char *directory)
  820. {
  821.   char *tempstr, ret;
  822.   g_return_val_if_fail (request != NULL, -2);
  823.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  824.   g_return_val_if_fail (directory != NULL, -2);
  825.   g_return_val_if_fail (request->sockfd > 0, -2);
  826.   tempstr = g_strconcat ("RMD ", directory, "rn", NULL);
  827.   ret = rfc959_send_command (request, tempstr);
  828.   g_free (tempstr);
  829.   return (ret == '2' ? 0 : -2);
  830. }
  831. static int
  832. rfc959_rmfile (gftp_request * request, const char *file)
  833. {
  834.   char *tempstr, ret;
  835.   g_return_val_if_fail (request != NULL, -2);
  836.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  837.   g_return_val_if_fail (file != NULL, -2);
  838.   g_return_val_if_fail (request->sockfd > 0, -2);
  839.   tempstr = g_strconcat ("DELE ", file, "rn", NULL);
  840.   ret = rfc959_send_command (request, tempstr);
  841.   g_free (tempstr);
  842.   return (ret == '2' ? 0 : -2);
  843. }
  844. static int
  845. rfc959_mkdir (gftp_request * request, const char *directory)
  846. {
  847.   char *tempstr, ret;
  848.   g_return_val_if_fail (request != NULL, -2);
  849.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  850.   g_return_val_if_fail (directory != NULL, -2);
  851.   g_return_val_if_fail (request->sockfd > 0, -2);
  852.   tempstr = g_strconcat ("MKD ", directory, "rn", NULL);
  853.   ret = rfc959_send_command (request, tempstr);
  854.   g_free (tempstr);
  855.   return (ret == '2' ? 0 : -2);
  856. }
  857. static int
  858. rfc959_rename (gftp_request * request, const char *oldname,
  859.        const char *newname)
  860. {
  861.   char *tempstr, ret;
  862.   g_return_val_if_fail (request != NULL, -2);
  863.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  864.   g_return_val_if_fail (oldname != NULL, -2);
  865.   g_return_val_if_fail (newname != NULL, -2);
  866.   g_return_val_if_fail (request->sockfd > 0, -2);
  867.   tempstr = g_strconcat ("RNFR ", oldname, "rn", NULL);
  868.   ret = rfc959_send_command (request, tempstr);
  869.   g_free (tempstr);
  870.   if (ret != '3')
  871.     return (-2);
  872.   tempstr = g_strconcat ("RNTO ", newname, "rn", NULL);
  873.   ret = rfc959_send_command (request, tempstr);
  874.   g_free (tempstr);
  875.   return (ret == '2' ? 0 : -2);
  876. }
  877. static int
  878. rfc959_chmod (gftp_request * request, const char *file, int mode)
  879. {
  880.   char *tempstr, ret;
  881.   g_return_val_if_fail (request != NULL, -2);
  882.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  883.   g_return_val_if_fail (file != NULL, -2);
  884.   g_return_val_if_fail (request->sockfd > 0, -2);
  885.   tempstr = g_malloc (strlen (file) + (mode / 10) + 16);
  886.   sprintf (tempstr, "SITE CHMOD %d %srn", mode, file);
  887.   ret = rfc959_send_command (request, tempstr);
  888.   g_free (tempstr);
  889.   return (ret == '2' ? 0 : -2);
  890. }
  891. static int
  892. rfc959_site (gftp_request * request, const char *command)
  893. {
  894.   char *tempstr, ret;
  895.   g_return_val_if_fail (request != NULL, -2);
  896.   g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
  897.   g_return_val_if_fail (command != NULL, -2);
  898.   g_return_val_if_fail (request->sockfd > 0, -2);
  899.   tempstr = g_strconcat ("SITE ", command, "rn", NULL);
  900.   ret = rfc959_send_command (request, tempstr);
  901.   g_free (tempstr);
  902.   return (request->sockfd > 0 ? ret : -2);
  903. }
  904. static void
  905. rfc959_set_config_options (gftp_request * request)
  906. {
  907.   request->transfer_type = passive_transfer ? gftp_transfer_passive : gftp_transfer_active;
  908.   if (strcmp (proxy_config, "http") != 0)
  909.     {
  910.       gftp_set_proxy_hostname (request, firewall_host);
  911.       gftp_set_proxy_port (request, firewall_port);
  912.       gftp_set_proxy_username (request, firewall_username);
  913.       gftp_set_proxy_password (request, firewall_password);
  914.       gftp_set_proxy_account (request, firewall_account);
  915.       gftp_set_proxy_config (request, proxy_config);
  916.     }
  917.   else
  918.     {
  919.       gftp_set_proxy_hostname (request, http_proxy_host);
  920.       gftp_set_proxy_port (request, http_proxy_port);
  921.       gftp_set_proxy_username (request, http_proxy_username);
  922.       gftp_set_proxy_password (request, http_proxy_password);
  923.       if (request->proxy_config == NULL)
  924.         {
  925.           gftp_protocols[GFTP_HTTP_NUM].init (request);
  926.           request->proxy_config = g_strdup ("ftp");
  927.         }
  928.     }
  929. }
  930. void
  931. rfc959_init (gftp_request * request)
  932. {
  933.   g_return_if_fail (request != NULL);
  934.   request->protonum = GFTP_FTP_NUM;
  935.   request->init = rfc959_init;
  936.   request->destroy = NULL; 
  937.   request->connect = rfc959_connect;
  938.   request->disconnect = rfc959_disconnect;
  939.   request->get_file = rfc959_get_file;
  940.   request->put_file = rfc959_put_file;
  941.   request->transfer_file = rfc959_transfer_file;
  942.   request->get_next_file_chunk = NULL;
  943.   request->put_next_file_chunk = NULL;
  944.   request->end_transfer = rfc959_end_transfer;
  945.   request->abort_transfer = rfc959_abort_transfer;
  946.   request->list_files = rfc959_list_files;
  947.   request->get_next_file = rfc959_get_next_file;
  948.   request->set_data_type = rfc959_set_data_type;
  949.   request->get_file_size = rfc959_get_file_size;
  950.   request->chdir = rfc959_chdir;
  951.   request->rmdir = rfc959_rmdir;
  952.   request->rmfile = rfc959_rmfile;
  953.   request->mkdir = rfc959_mkdir;
  954.   request->rename = rfc959_rename;
  955.   request->chmod = rfc959_chmod;
  956.   request->set_file_time = NULL;
  957.   request->site = rfc959_site;
  958.   request->parse_url = NULL;
  959.   request->swap_socks = NULL;
  960.   request->set_config_options = rfc959_set_config_options;
  961.   request->url_prefix = "ftp";
  962.   request->protocol_name = "FTP";
  963.   request->need_hostport = 1;
  964.   request->need_userpass = 1;
  965.   request->use_cache = 1;
  966.   request->use_threads = 1;
  967.   request->always_connected = 0;
  968.   request->protocol_data = g_malloc0 (sizeof (rfc959_parms));
  969.   gftp_set_config_options (request);
  970. }