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

Ftp客户端

开发平台:

Visual C++

  1. /*****************************************************************************/
  2. /*  ssh.c - functions that will use the ssh protocol                         */
  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. /* This will use Brian Wellington <bwelling@xbill.org>'s sftpserv program */
  20. /* on the remote. Some of this code is derived from the sftp client */
  21. /* 11/5/2002 - This protocol is now obsolete by the SSH2 protocol. I'm not 
  22.    going to be adding any new features to it, but I'll keep it inside the code 
  23.    for a little bit. I do plan on removing it completely though */
  24. #include "gftp.h"
  25. static const char cvsid[] = "$Id: ssh.c,v 1.10 2002/11/23 13:45:04 masneyb Exp $";
  26. #define CHDIR 10
  27. #define GETDIR 11
  28. #define TELLDIR 12
  29. #define SENDFILE 15
  30. #define NOFILEMATCH 16
  31. #define FILESIZE 20
  32. #define FILEMODE 21
  33. #define DATA 22
  34. #define ENDDATA 23
  35. #define FILEOK 24
  36. #define STREAM 25
  37. #define REQUEST 26
  38. #define FILENAME 27
  39. #define EXEC 28
  40. #define SKIPBYTES 29
  41. #define ERROR 30
  42. #define SUCCESS   31
  43. #define CLOSE 32
  44. #define SSH_VERSION  33
  45. #define CANCEL 34
  46. #define FILETIME 40
  47. typedef struct ssh_parms_tag
  48. {
  49.     char *buffer, /* The buffer we are reading the data from */
  50.          *pos; /* Our position in this buffer */
  51.     int enddata; /* Are we done reading the data */
  52.     char channel; /* Data channel we are writing to */
  53. } ssh_parms;
  54. typedef struct ssh_message_tag
  55. {
  56.   char channel,
  57.        command;
  58.   gint32 len;
  59.   void *data;
  60. } ssh_message;
  61. static void
  62. ssh_log_command (gftp_request * request, int channel, int cmdnum, 
  63.                  const char *command, size_t len, int direction)
  64. {
  65.   const char *pos;
  66.   char *tempstr;
  67.   int ok;
  68.   switch (cmdnum)
  69.     {
  70.       case CHDIR:
  71.         tempstr = "CHDIR ";
  72.         break;
  73.       case GETDIR:
  74.         tempstr = "GETDIR ";
  75.         break;
  76.       case TELLDIR:
  77.         tempstr = "TELLDIR ";
  78.         break;
  79.       case SENDFILE:
  80.         tempstr = "SENDFILE ";
  81.         break;
  82.       case FILESIZE:
  83.         tempstr = "FILESIZE ";
  84.         break;
  85.       case FILEMODE:
  86.         tempstr = "FILEMODE ";
  87.         break;
  88.       case ENDDATA:
  89.         tempstr = "ENDDATA ";
  90.         break;
  91.       case FILEOK:
  92.         tempstr = "FILEOK ";
  93.         break;
  94.       case STREAM:
  95.         tempstr = "STREAM ";
  96.         break;
  97.       case REQUEST:
  98.         tempstr = "REQUEST ";
  99.         break;
  100.       case FILENAME:
  101.         tempstr = "FILENAME ";
  102.         break;
  103.       case EXEC:
  104.         tempstr = "EXEC ";
  105.         break;
  106.       case SKIPBYTES:
  107.         tempstr = "SKIPBYTES ";
  108.         break;
  109.       case ERROR:
  110.         tempstr = "ERROR: ";
  111.         break;
  112.       case SUCCESS:
  113.         tempstr = "SUCCESS ";
  114.         break;
  115.       case CLOSE:
  116.         tempstr = "CLOSE ";
  117.         break;
  118.       case SSH_VERSION:
  119.         tempstr = "VERSION ";
  120.         break;
  121.       case CANCEL:
  122.         tempstr = "CANCEL ";
  123.         break;
  124.       case FILETIME:
  125.         tempstr = "FILETIME ";
  126.         break;
  127.       default:
  128.         return;
  129.     }
  130.   ok = 0;
  131.   if (command)
  132.     {
  133.       for (pos = command; pos < command + len; pos++)
  134.         {
  135.           if (*pos == '')
  136.             {
  137.               ok = 1;
  138.               break;
  139.             }
  140.         }
  141.     }
  142.   request->logging_function (direction == GFTP_DIRECTION_DOWNLOAD ? 
  143.                                  gftp_logging_send : gftp_logging_recv,
  144.                              request->user_data, "%d: %s %sn", channel, 
  145.                              tempstr, ok ? command : "");
  146. }
  147. static int
  148. ssh_send_command (gftp_request * request, int cmdnum, const char *command, 
  149.                   size_t len)
  150. {
  151.   ssh_parms * params;
  152.   char *buf;
  153.   int clen;
  154.   params = request->protocol_data;
  155.   clen = htonl (len);
  156.   buf = g_malloc (len + 6);
  157.   buf[0] = params->channel;
  158.   buf[1] = cmdnum;
  159.   memcpy (&buf[2], &clen, 4);
  160.   if (command)
  161.     memcpy (&buf[6], command, len);
  162.   ssh_log_command (request, params->channel, cmdnum, command, len, 1);
  163.   if (gftp_write (request, buf, len + 6, request->sockfd) < 0)
  164.     return (-2);
  165.   return 0;
  166. }
  167. static char *
  168. ssh_read_message (gftp_request * request, char *buf, size_t len, int fd)
  169. {
  170.   if (fd <= 0)
  171.     fd = request->sockfd;
  172.   if (gftp_read (request, buf, len, fd) < 0)
  173.     return (NULL);
  174.   return (buf);
  175. }
  176. static int
  177. ssh_read_response (gftp_request * request, ssh_message *message, int fd)
  178. {
  179.   char buf[6];
  180.   if (ssh_read_message (request, buf, 6, fd) == NULL)
  181.     return (-1);
  182.   message->channel = buf[0];
  183.   message->command = buf[1];
  184.   memcpy (&message->len, buf + 2, 4);
  185.   message->len = ntohl (message->len);
  186.   if (message->len > 8192)
  187.     {
  188.       request->logging_function (gftp_logging_error, request->user_data,
  189.                              _("Error: Message size %d too big from servern"),
  190.                              message->len);
  191.       memset (message, 0, sizeof (*message));
  192.       gftp_disconnect (request);
  193.       return (-1);
  194.     }
  195.   
  196.   message->data = g_malloc (message->len + 1); 
  197.   if (message->len > 0 && ssh_read_message (request, 
  198.                            (char *) message->data, message->len, fd) == NULL)
  199.     return (-1);
  200.   ((char *) message->data)[message->len] = ''; 
  201.   ssh_log_command (request, message->channel, message->command, message->data,
  202.                    message->len, 0);
  203.   return (message->command);
  204. }
  205. static char *
  206. ssh_read_line (gftp_request * request)
  207. {
  208.   char *retstr, *pos, tempchar;
  209.   ssh_parms *buffer;
  210.   pos = NULL;
  211.   buffer = request->protocol_data;
  212.   if (!buffer->enddata && (pos = strchr (buffer->pos, 'n')) == NULL)
  213.     return (NULL);
  214.   if (pos == NULL)
  215.     {
  216.       pos = buffer->pos + strlen (buffer->pos) - 1;
  217.       tempchar = '';
  218.     }
  219.   else
  220.     tempchar = pos + 1 == '' ? '' : '1';
  221.   if (*(pos-1) == 'r') 
  222.     *(pos-1) = '';
  223.   else 
  224.     *pos = '';
  225.   retstr = g_malloc (strlen (buffer->pos) + 1);
  226.   strcpy (retstr, buffer->pos);
  227.   if (tempchar != '' && *buffer->pos != '')
  228.     {
  229.       buffer->pos = pos + 1;
  230.       while (*buffer->pos == 'r' || *buffer->pos == 'n')
  231.         buffer->pos++;
  232.     }
  233.   else
  234.     {
  235.       g_free (buffer->buffer);
  236.       buffer->buffer = buffer->pos = NULL;
  237.     }
  238.   return (retstr);
  239. }
  240. static void
  241. ssh_destroy (gftp_request * request)
  242. {
  243.   ssh_parms *params;
  244.   g_return_if_fail (request != NULL);
  245.   g_return_if_fail (request->protonum == GFTP_SSH_NUM);
  246.   params = request->protocol_data;
  247.   if (params->buffer)
  248.     {
  249.       g_free (params->buffer);
  250.       params->buffer = params->pos = NULL;
  251.     }
  252. }
  253. static int
  254. ssh_chdir (gftp_request * request, const char *directory)
  255. {
  256.   ssh_message message;
  257.   int ret;
  258.   g_return_val_if_fail (request != NULL, -2);
  259.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  260.   if (directory != NULL && *directory != '')
  261.     {  
  262.       if (ssh_send_command (request, CHDIR, directory, 
  263.                             strlen (directory) + 1) < 0) 
  264.         return (-1);
  265.       if ((ret = ssh_read_response (request, &message, -1)) != SUCCESS)
  266.         {
  267.           request->logging_function (gftp_logging_error, request->user_data,
  268.     _("Could not change remote directory to %s: %sn"),
  269.                directory, (char *) message.data);
  270.           g_free (message.data);
  271.           return (-1);
  272.         }
  273.       g_free (message.data);
  274.     }
  275.   if (directory != request->directory)
  276.     {
  277.       if (ssh_send_command (request, GETDIR, NULL, 0) < 0)
  278.         return (-1);
  279.       if (ssh_read_response (request, &message, -1) != TELLDIR)
  280.         {
  281.           request->logging_function (gftp_logging_error, request->user_data,
  282.                             _("Could not get current working directory: %sn"),
  283.        (char *) message.data);
  284.           g_free (message.data);
  285.           return (-1);
  286.         }
  287.       if (request->directory)
  288.         g_free (request->directory);
  289.       request->directory = message.data;
  290.     }
  291.   return (0);
  292. }
  293. static int
  294. ssh_connect (gftp_request * request)
  295. {
  296.   char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6];
  297.   int version, fdm, fds, s[2];
  298.   ssh_message message;
  299.   ssh_parms *params;
  300.   pid_t child;
  301.   g_return_val_if_fail (request != NULL, -2);
  302.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  303.   g_return_val_if_fail (request->hostname != NULL, -2);
  304.   
  305.   params = request->protocol_data;
  306.   if (request->sockfd > 0)
  307.     return (0);
  308.   request->logging_function (gftp_logging_misc, request->user_data,
  309.      _("Opening SSH connection to %sn"),
  310.                              request->hostname);
  311.   if (request->sftpserv_path == NULL ||
  312.       *request->sftpserv_path == '') 
  313.     {
  314.       p1 = "";
  315.       p2 = ' ';
  316.     }
  317.   else
  318.     {
  319.       p1 = request->sftpserv_path;
  320.       p2 = '/';
  321.     }
  322.   *port = '';
  323.   exepath = g_strdup_printf ("%s%csftpserv", p1, p2);
  324.   args = make_ssh_exec_args (request, exepath, 0, port);
  325.    if (ssh_use_askpass)
  326.     {
  327.       fdm = fds = 0;
  328.       if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
  329.         {
  330.           request->logging_function (gftp_logging_error, request->user_data,
  331.                                      _("Cannot create a socket pair: %sn"),
  332.                                      g_strerror (errno));
  333.           return (-2);
  334.         }
  335.     }
  336.   else
  337.     {
  338.       s[0] = s[1] = 0;
  339.       if ((fdm = ptym_open (pts_name)) < 0)
  340.         {
  341.           request->logging_function (gftp_logging_error, request->user_data,
  342.                                 _("Cannot open master pty %s: %sn"), pts_name,
  343.                                 g_strerror (errno));
  344.           return (-2);
  345.         }
  346.     }
  347.   if ((child = fork ()) == 0)
  348.     {
  349.       setsid ();
  350.       if (ssh_use_askpass)
  351.         {
  352.           close (s[0]);
  353.           fds = s[1];
  354.         }
  355.       else
  356.         {
  357.           if ((fds = ptys_open (fdm, pts_name)) < 0)
  358.             {
  359.               printf ("Cannot open slave pts %s: %sn", pts_name,
  360.                       g_strerror (errno));
  361.               return (-1);
  362.             }
  363.           close (fdm);
  364.         }
  365.       dup2 (fds, 0);
  366.       dup2 (fds, 1);
  367.       dup2 (fds, 2);
  368.       if (!ssh_use_askpass && fds > 2)
  369.         close (fds);
  370.       execvp (ssh_prog_name != NULL && *ssh_prog_name != '' ?
  371.               ssh_prog_name : "ssh", args);  
  372.       printf (_("Error: Cannot execute ssh: %sn"), g_strerror (errno));
  373.       return (-1);
  374.     }
  375.   else if (child > 0)
  376.     {
  377.       if (ssh_use_askpass)
  378.         {
  379.           close (s[1]);
  380.           fdm = s[0];
  381.         }
  382.       tty_raw (fdm);
  383.       tempstr = ssh_start_login_sequence (request, fdm);
  384.       if (!tempstr || 
  385.           !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5, 
  386.                                             "xsftp") == 0))
  387.         {
  388.           g_free (args);
  389.           g_free (exepath);
  390.           return (-2);
  391.         }
  392.       g_free (args);
  393.       g_free (exepath);
  394.       g_free (tempstr);
  395.       request->sockfd = fdm;
  396.       params->channel = 0;
  397.       version = htonl (7 << 4);
  398.       if (ssh_send_command (request, SSH_VERSION, (char *) &version, 4) < 0)
  399.         return (-2);
  400.       if (ssh_read_response (request, &message, -1) != SSH_VERSION)
  401.         return (-2);
  402.       g_free (message.data);
  403.       request->logging_function (gftp_logging_misc, request->user_data,
  404.          _("Successfully logged into SSH server %sn"),
  405.                                  request->hostname);
  406.     }
  407.   else
  408.     {
  409.       request->logging_function (gftp_logging_error, request->user_data,
  410.                                  _("Cannot fork another process: %sn"),
  411.                                  g_strerror (errno));
  412.       g_free (args);
  413.       return (-1);
  414.     }
  415.   ssh_chdir (request, request->directory);
  416.   if (ssh_send_command (request, GETDIR, NULL, 0) < 0)
  417.     return (-1);
  418.   if (ssh_read_response (request, &message, -1) != TELLDIR)
  419.     {
  420.       request->logging_function (gftp_logging_error, request->user_data,
  421.                             _("Could not get current working directory: %sn"),
  422.                             (char *) message.data);
  423.       g_free (message.data);
  424.       return (-1);
  425.     }
  426.   if (request->directory)
  427.     g_free (request->directory);
  428.   request->directory = message.data;
  429.   return (0);
  430. }
  431. static void
  432. ssh_disconnect (gftp_request * request)
  433. {
  434.   g_return_if_fail (request != NULL);
  435.   g_return_if_fail (request->protonum == GFTP_SSH_NUM);
  436.   if (request->sockfd > 0)
  437.     {
  438.       request->logging_function (gftp_logging_misc, request->user_data,
  439.          _("Disconnecting from site %sn"),
  440.                                  request->hostname);
  441.       if (close (request->sockfd) < 0)
  442.         request->logging_function (gftp_logging_error, request->user_data,
  443.                                    _("Error closing file descriptor: %sn"),
  444.                                    g_strerror (errno));
  445.       request->sockfd = -1;
  446.     }
  447. }
  448. static off_t 
  449. ssh_get_file (gftp_request * request, const char *filename, int fd,
  450.               off_t startsize)
  451. {
  452.   ssh_message message;
  453.   ssh_parms *params;
  454.   off_t retsize;
  455.   int ret;
  456.   g_return_val_if_fail (request != NULL, -2);
  457.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  458.   g_return_val_if_fail (filename != NULL, -2);
  459.   /* fd ignored for this protocol */
  460.   params = request->protocol_data;
  461.   params->channel = 0; 
  462.   if (ssh_send_command (request, REQUEST, filename, strlen (filename) + 1) < 0)
  463.     return (-1);
  464.   retsize = 0;
  465.   while (1)
  466.     {
  467.       ret = ssh_read_response (request, &message, -1);
  468.       switch (ret)
  469.         {
  470.           case FILESIZE:
  471.             retsize = strtol ((char *) message.data, NULL, 10);
  472.             break;
  473.           case NOFILEMATCH:
  474.             request->logging_function (gftp_logging_misc, request->user_data,
  475.               _("Remote host could not find file %sn"),
  476.                                       filename);
  477.             g_free (message.data);
  478.             return (-1);
  479.           case FILENAME:
  480.             params->channel = message.channel;
  481.             startsize = htonl (startsize);
  482.             if (ssh_send_command (request, SKIPBYTES, (char *) &startsize, 4) < 0)
  483.               {
  484.                 g_free (message.data);
  485.                 return (-1);
  486.               }
  487.             break;
  488.           case -1:
  489.             g_free (message.data);
  490.             return (-2);
  491.         }
  492.       g_free (message.data);
  493.       if (ret == FILETIME)
  494.         break;
  495.     }
  496.   return (retsize);
  497. }
  498. static int
  499. ssh_put_file (gftp_request * request, const char *filename, int fd,
  500.               off_t startsize, off_t totalsize)
  501. {
  502.   ssh_message message;
  503.   ssh_parms *params;
  504.   char tempchar;
  505.   g_return_val_if_fail (request != NULL, -2);
  506.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  507.   g_return_val_if_fail (filename != NULL, -2);
  508.   /* fd ignored for this protocol */
  509.   params = request->protocol_data;
  510.   params->channel = 0;
  511.   tempchar = 1;
  512.   if (ssh_send_command (request, SENDFILE, &tempchar, 1) < 0) 
  513.     return (-1);
  514.   params->channel = tempchar;
  515.   if (ssh_send_command (request, FILENAME, filename, strlen (filename) + 1) < 0)
  516.     return (-1);
  517.   if (ssh_read_response (request, &message, -1) < 0)
  518.     {
  519.       g_free (message.data);
  520.       return (-1);
  521.     }
  522.   if (!(message.command == FILEOK && message.len == 1 
  523.        && *(char *) message.data != 0))
  524.     {
  525.       g_free (message.data);
  526.       return (-1);
  527.     }
  528.   g_free (message.data);
  529.   if (ssh_send_command (request, FILESIZE, (void *) &totalsize, 4) < 0)
  530.     return (-1);
  531.   if (ssh_send_command (request, FILEMODE, "rw-r--r--", 9) < 0)
  532.     return (-1);
  533.   if (ssh_send_command (request, FILETIME, (char *) 0, 4) < 0)
  534.     return (-1);
  535.   if (startsize > 0)
  536.     {
  537.       startsize = htonl (startsize);
  538.       /* This protocol only supports files up to 2 gig in size. I truncate
  539.          the file size here just to suppress compiler warnings  */
  540.       if (ssh_send_command (request, SKIPBYTES, 
  541.                             GINT_TO_POINTER ((gint32) startsize), 4) < 0)
  542.         return (-1);
  543.     }
  544.   return (0);
  545. }
  546. static ssize_t 
  547. ssh_get_next_file_chunk (gftp_request * request, char *buf, size_t size)
  548. {
  549.   ssh_message message;
  550.   size_t len;
  551.   switch (ssh_read_response (request, &message, -1))
  552.     {
  553.       case DATA:
  554.         len = size > message.len ? message.len : size;
  555.         memcpy (buf, message.data, len);
  556.         g_free (message.data);
  557.         return (len);
  558.       case ENDDATA:
  559.         g_free (message.data);
  560.         if (ssh_read_response (request, &message, -1) < 0)
  561.           {
  562.             g_free (message.data);
  563.             return (-1);
  564.           }
  565.         g_free (message.data);
  566.         return (0);
  567.       case -1:
  568.         g_free (message.data);
  569.         return (-1);
  570.       default:
  571.         g_free (message.data);
  572.         request->logging_function (gftp_logging_misc, request->user_data,
  573.       _("Received unexpected response from servern"));
  574.         gftp_disconnect (request);
  575.         return (0);
  576.     }
  577. }
  578. static ssize_t 
  579. ssh_put_next_file_chunk (gftp_request * request, char *buf, size_t size)
  580. {
  581.   if (size == 0)
  582.     {
  583.       if (ssh_send_command (request, ENDDATA, NULL, 0) < 0)
  584.         return (-2);
  585.       if (ssh_send_command (request, NOFILEMATCH, NULL, 0) < 0)
  586.         return (-2);
  587.       return (0);
  588.     }
  589.   return (ssh_send_command (request, DATA, buf, size) == 0 ? size : 0);
  590. }
  591. static int
  592. ssh_end_transfer (gftp_request * request)
  593. {
  594.   ssh_parms *params;
  595.   g_return_val_if_fail (request != NULL, -2);
  596.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  597.   params = request->protocol_data;
  598.   if (params->buffer)
  599.     g_free (params->buffer);
  600.   params->buffer = params->pos = NULL;
  601.   params->enddata = 0;
  602.   return (0);
  603. }
  604. static size_t 
  605. ssh_remove_spaces ( char *string )
  606. {
  607.   size_t len;
  608.   char *pos;
  609.   for (pos = string, len = 0; *pos != ''; len++, pos++)
  610.     {
  611.       if (*pos == ' ')
  612.         *pos = '';
  613.     }
  614.   return (len);
  615. }
  616. static int
  617. ssh_list_files (gftp_request * request)
  618. {
  619.   ssh_message message;
  620.   ssh_parms *params;
  621.   char *tempstr;
  622.   size_t len;
  623.   g_return_val_if_fail (request != NULL, -2);
  624.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  625.   params = request->protocol_data;
  626.   params->enddata = 0;
  627.   params->channel = 0;
  628.   request->logging_function (gftp_logging_misc, request->user_data,
  629.      _("Retrieving directory listing...n"));
  630.   tempstr = g_strdup ("/bin/ls -al");
  631.   len = ssh_remove_spaces (tempstr);
  632.   if (ssh_send_command (request, EXEC, tempstr, len) < 0) 
  633.     {
  634.       g_free (tempstr);
  635.       return (-1);
  636.     }
  637.   g_free (tempstr);
  638.   if (ssh_read_response (request, &message, -1) != STREAM)
  639.     {
  640.       g_free (message.data);
  641.       request->logging_function (gftp_logging_misc, request->user_data,
  642.       _("Received unexpected response from servern"));
  643.       gftp_disconnect (request);
  644.       return (-2);
  645.     }
  646.   g_free (message.data);
  647.   return (0);
  648. }
  649. static int
  650. ssh_get_next_file (gftp_request * request, gftp_file * fle, int fd)
  651. {
  652.   char *tempstr, *pos;
  653.   ssh_message message;
  654.   ssh_parms *params;
  655.   int ret, len;
  656.   g_return_val_if_fail (request != NULL, -2);
  657.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  658.   g_return_val_if_fail (fle != NULL, -2);
  659.   params = request->protocol_data;
  660.   if (request->last_dir_entry)
  661.     {
  662.       g_free (request->last_dir_entry);
  663.       request->last_dir_entry = NULL;
  664.       request->last_dir_entry_len = 0;
  665.     }
  666.   len = 0;
  667.   while (1)
  668.     {
  669.       if (params->enddata && params->buffer == NULL)
  670.         {
  671.           request->logging_function (gftp_logging_misc, request->user_data,
  672.          _("Finished retrieving directory listingn"));
  673.           params->enddata = 0;
  674.           return (0);
  675.         }
  676.       if (!params->enddata && 
  677.           (!params->pos || strchr (params->pos, 'n') == NULL)) 
  678.         {
  679.           if ((ret = ssh_read_response (request, &message, fd)) < 0)
  680.             {
  681.               if (message.data)
  682.                 g_free (message.data);
  683.               return (-2);
  684.             }
  685.           if (!request->cached)
  686.             {
  687.               request->last_dir_entry_len = message.len + 6;
  688.               request->last_dir_entry = g_malloc (request->last_dir_entry_len + 1);
  689.               request->last_dir_entry[0] = message.channel;
  690.               request->last_dir_entry[1] = message.command;
  691.               len = htonl (message.len);
  692.               memcpy (&request->last_dir_entry[2], &len, 4);
  693.               memcpy (&request->last_dir_entry[6], message.data, message.len);
  694.             }
  695.           if (ret == DATA)
  696.             {
  697.               if (params->pos == NULL || *params->pos == '')
  698.                 {
  699.                   if (params->buffer)
  700.                     g_free (params->buffer);
  701.                   params->buffer = params->pos = message.data;
  702.                 }
  703.               else
  704.                 {
  705.                   tempstr = params->buffer;
  706.                   params->buffer = g_malloc (strlen (params->pos) + 
  707.                                      strlen ((char *) message.data) + 1);
  708.                   strcpy (params->buffer, params->pos);
  709.                   strcat (params->buffer, (char *) message.data);
  710.                   g_free (tempstr);
  711.                   g_free (message.data);
  712.                   params->pos = params->buffer;
  713.                 } 
  714.             }
  715.           else
  716.             g_free (message.data);
  717.         }
  718.       else
  719.         ret = DATA;
  720.       switch (ret)
  721.         {
  722.           case DATA:
  723.             if ((tempstr = ssh_read_line (request)) == NULL)
  724.               continue;
  725.             pos = tempstr;
  726.             while (*pos == ' ' || *pos == 't')
  727.               pos++;
  728.             if (*pos == '')
  729.               {
  730.                 g_free (tempstr);
  731.                 break;
  732.               }
  733.             if (gftp_parse_ls (tempstr, fle) != 0)
  734.       {
  735.         if (strncmp (tempstr, "total", strlen ("total")) &&
  736.     strncmp (tempstr, _("total"), strlen (_("total"))))
  737.           request->logging_function (gftp_logging_misc, 
  738.                                        request->user_data,
  739.        _("Warning: Cannot parse listing %sn"),
  740.        tempstr);
  741.         gftp_file_destroy (fle);
  742.                 g_free (tempstr);
  743.                 tempstr = NULL;
  744.         continue;
  745.               }
  746.             len = strlen (tempstr);
  747.             g_free (tempstr);
  748.             break;
  749.           case ENDDATA:
  750.             params->enddata = 1;
  751.             break;
  752.           default:
  753.             request->logging_function (gftp_logging_misc, request->user_data,
  754.       _("Received unexpected response from servern"));
  755.             gftp_disconnect (request);
  756.             return (-2);
  757. }
  758.       if (ret == DATA)
  759.         break;
  760.     }
  761.   return (len);
  762. }
  763. static char *
  764. ssh_exec (gftp_request * request, const char *command, size_t len)
  765. {
  766.   ssh_message message;
  767.   char *err, *pos;
  768.   int ret;
  769.   g_return_val_if_fail (request != NULL, NULL);
  770.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, NULL);
  771.   g_return_val_if_fail (command != NULL, NULL);
  772.   err = NULL;
  773.   if (ssh_send_command (request, EXEC, command, len) < 0)
  774.     return (NULL);
  775.   while (1)
  776.     {
  777.       ret = ssh_read_response (request, &message, -1);
  778.       switch (ret)
  779.         {
  780.           case -1: 
  781.             g_free (message.data);
  782.             gftp_disconnect (request);
  783.             return (message.data);
  784.           case DATA:
  785.           case ERROR:
  786.             pos = (char *) message.data+message.len-1;
  787.             if (*pos == 'n')
  788.               *pos = '';
  789.             if (err != NULL)
  790.               {
  791.                 err = g_realloc (err, strlen (message.data) + strlen (err) + 1);
  792.                 strcat (err, message.data);
  793.               }
  794.             else
  795.               {
  796.                 err = g_malloc (strlen (message.data) + 1);
  797.                 strcpy (err, message.data);
  798.               }
  799.             if (ret == ERROR)
  800.               {
  801.                 g_free (message.data);
  802.                 return (err);
  803.               }
  804.             break;
  805.           case SUCCESS:
  806.             g_free (message.data);
  807.             return (err);
  808.           case STREAM:
  809.             break;
  810.           case ENDDATA:
  811.             g_free (message.data);
  812.             return (err);
  813.         }
  814.       g_free (message.data);
  815.     }
  816. }
  817. static int 
  818. ssh_rmdir (gftp_request * request, const char *directory)
  819.   char *tempstr, *pos, *ret;
  820.   size_t len;
  821.   g_return_val_if_fail (request != NULL, -2);
  822.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  823.   g_return_val_if_fail (directory != NULL, -2);
  824.   tempstr = g_strconcat ("/bin/rmdir ", directory, NULL);
  825.   len = strlen (tempstr);
  826.   pos = tempstr;
  827.   while ((pos = strchr (pos, ' ')) != NULL)
  828.     *pos++ = '';
  829.   if ((ret = ssh_exec (request, tempstr, len)) != NULL)
  830.     {
  831.       request->logging_function (gftp_logging_error, request->user_data,
  832. _("Error: Could not remove directory %s: %sn"),
  833. directory, ret);
  834.       g_free (tempstr);
  835.       g_free (ret);
  836.       return (-2);
  837.     }
  838.   else 
  839.     request->logging_function (gftp_logging_misc, request->user_data,
  840.        _("Successfully removed %sn"), directory);
  841.   g_free (tempstr);
  842.   return (0);
  843. }
  844. static int 
  845. ssh_rmfile (gftp_request * request, const char *file)
  846.   char *tempstr, *pos, *ret;
  847.   size_t len;
  848.   g_return_val_if_fail (request != NULL, -2);
  849.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  850.   g_return_val_if_fail (file != NULL, -2);
  851.   tempstr = g_strconcat ("/bin/rm -f ", file, NULL);
  852.   len = strlen (tempstr);
  853.   pos = tempstr;
  854.   while ((pos = strchr (pos, ' ')) != NULL)
  855.     *pos++ = '';
  856.   if ((ret = ssh_exec (request, tempstr, len)) != NULL)
  857.     {
  858.       request->logging_function (gftp_logging_error, request->user_data,
  859.  _("Error: Could not remove file %s: %sn"),
  860.  file, ret);
  861.       g_free (tempstr);
  862.       g_free (ret);
  863.       return (-2);
  864.     }
  865.   else
  866.     request->logging_function (gftp_logging_misc, request->user_data,
  867.        _("Successfully removed %sn"), file);
  868.   g_free (tempstr);
  869.   return (0);
  870. }
  871. static int 
  872. ssh_mkdir (gftp_request * request, const char *newdir)
  873. {
  874.   char *tempstr, *pos, *ret;
  875.   size_t len;
  876.   g_return_val_if_fail (request != NULL, -2);
  877.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  878.   g_return_val_if_fail (newdir != NULL, -2);
  879.   tempstr = g_strconcat ("/bin/mkdir ", newdir, NULL);
  880.   len = strlen (tempstr);
  881.   pos = tempstr;
  882.   while ((pos = strchr (pos, ' ')) != NULL)
  883.     *pos++ = '';
  884.   if ((ret = ssh_exec (request, tempstr, len)) != NULL)
  885.     {
  886.       request->logging_function (gftp_logging_error, request->user_data,
  887.  _("Error: Could not make directory %s: %sn"),
  888.  newdir, ret);
  889.       g_free (tempstr);
  890.       g_free (ret);
  891.       return (-2);
  892.     }
  893.   else
  894.     request->logging_function (gftp_logging_misc, request->user_data,
  895.                                _("Successfully made directory %sn"),
  896.                                newdir);
  897.   g_free (tempstr);
  898.   return (0);
  899. }
  900. static int 
  901. ssh_rename (gftp_request * request, const char *oldname, const char *newname )
  902. {
  903.   char *tempstr, *pos, *ret;
  904.   size_t len;
  905.   g_return_val_if_fail (request != NULL, -2);
  906.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  907.   g_return_val_if_fail (oldname != NULL, -2);
  908.   g_return_val_if_fail (newname != NULL, -2);
  909.   tempstr = g_strconcat ("/bin/mv ", oldname, " ", newname, NULL);
  910.   len = strlen (tempstr);
  911.   pos = tempstr;
  912.   while ((pos = strchr (pos, ' ')) != NULL)
  913.     *pos++ = '';
  914.   if ((ret = ssh_exec (request, tempstr, len)) != NULL)
  915.     {
  916.       request->logging_function (gftp_logging_misc, request->user_data,
  917.  _("Error: Could not rename %s to %s: %sn"),
  918.  oldname, newname, ret);
  919.       g_free (tempstr);
  920.       g_free (ret);
  921.       return (-2);
  922.     }
  923.   else
  924.     request->logging_function (gftp_logging_misc, request->user_data,
  925.        _("Successfully renamed %s to %sn"),
  926.                                oldname, newname);
  927.   g_free (tempstr);
  928.   return (0);
  929. }
  930. static int 
  931. ssh_chmod (gftp_request * request, const char *file, int mode)
  932. {
  933.   char *tempstr, *pos, *ret;
  934.   size_t len;
  935.   g_return_val_if_fail (request != NULL, -2);
  936.   g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
  937.   g_return_val_if_fail (file != NULL, -2);
  938.   tempstr = g_malloc (strlen (file) + (mode / 10) + 14);
  939.   sprintf (tempstr, "/bin/chmod %d %s", mode, file);
  940.   len = strlen (tempstr);
  941.   pos = tempstr;
  942.   while ((pos = strchr (pos, ' ')) != NULL)
  943.     *pos++ = '';
  944.   if ((ret = ssh_exec (request, tempstr, len)) != NULL)
  945.     {
  946.       request->logging_function (gftp_logging_misc, request->user_data,
  947. _("Error: Could not change mode of %s to %d: %sn"),
  948. file, mode, ret);
  949.       g_free (tempstr);
  950.       g_free (ret);
  951.       return (-2);
  952.     }
  953.   else
  954.     request->logging_function (gftp_logging_misc, request->user_data,
  955.        _("Successfully changed mode of %s to %dn"),
  956.                                file, mode);
  957.   g_free (tempstr);
  958.   return (0);
  959. }
  960. static void
  961. ssh_set_config_options (gftp_request * request)
  962. {
  963.   if (request->sftpserv_path != NULL)
  964.     {
  965.       if (ssh1_sftp_path != NULL &&
  966.           strcmp (ssh1_sftp_path, request->sftpserv_path) == 0)
  967.         return;
  968.       g_free (request->sftpserv_path);
  969.       request->sftpserv_path = NULL;
  970.     }
  971.   if (ssh1_sftp_path != NULL)
  972.     request->sftpserv_path = g_strdup (ssh1_sftp_path);
  973.   request->need_userpass = ssh_need_userpass;
  974. }
  975. void
  976. ssh_init (gftp_request * request)
  977. {
  978.   g_return_if_fail (request != NULL);
  979.   request->protonum = GFTP_SSH_NUM;
  980.   request->init = ssh_init;
  981.   request->destroy = ssh_destroy;
  982.   request->connect = ssh_connect;
  983.   request->disconnect = ssh_disconnect;
  984.   request->get_file = ssh_get_file;
  985.   request->put_file = ssh_put_file;
  986.   request->transfer_file = NULL;
  987.   request->get_next_file_chunk = ssh_get_next_file_chunk;
  988.   request->put_next_file_chunk = ssh_put_next_file_chunk;
  989.   request->end_transfer = ssh_end_transfer;
  990.   request->abort_transfer = NULL; /* FIXME */
  991.   request->list_files = ssh_list_files;
  992.   request->get_next_file = ssh_get_next_file;
  993.   request->set_data_type = NULL;
  994.   request->get_file_size = NULL;
  995.   request->chdir = ssh_chdir;
  996.   request->rmdir = ssh_rmdir;
  997.   request->rmfile = ssh_rmfile;
  998.   request->mkdir = ssh_mkdir;
  999.   request->rename = ssh_rename;
  1000.   request->chmod = ssh_chmod;
  1001.   request->set_file_time = NULL;
  1002.   request->site = NULL;
  1003.   request->parse_url = NULL;
  1004.   request->set_config_options = ssh_set_config_options;
  1005.   request->swap_socks = NULL;
  1006.   request->url_prefix = "ssh";
  1007.   request->protocol_name = "SSH";
  1008.   request->need_hostport = 1;
  1009.   request->need_userpass = ssh_need_userpass;
  1010.   request->use_cache = 1;
  1011.   request->use_threads = 1;
  1012.   request->always_connected = 0;
  1013.   request->protocol_data = g_malloc0 (sizeof (ssh_parms));
  1014.   gftp_set_config_options (request);
  1015. }