root/src/vfs/ftpfs/ftpfs.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. ftpfs_set_blksize
  2. ftpfs_default_stat
  3. ftpfs_translate_path
  4. ftpfs_correct_url_parameters
  5. ftpfs_get_reply
  6. ftpfs_reconnect
  7. G_GNUC_PRINTF
  8. ftpfs_new_archive
  9. ftpfs_free_archive
  10. ftpfs_changetype
  11. ftpfs_login_server
  12. ftpfs_load_no_proxy_list
  13. ftpfs_check_proxy
  14. ftpfs_get_proxy_host_and_port
  15. ftpfs_open_socket
  16. ftpfs_open_archive_int
  17. ftpfs_open_archive
  18. ftpfs_archive_same
  19. ftpfs_get_current_directory
  20. ftpfs_setup_passive_pasv
  21. ftpfs_setup_passive_epsv
  22. ftpfs_setup_passive
  23. ftpfs_setup_active
  24. ftpfs_init_data_socket
  25. ftpfs_initconn
  26. ftpfs_open_data_connection
  27. ftpfs_linear_abort
  28. resolve_symlink_without_ls_options
  29. resolve_symlink_with_ls_options
  30. resolve_symlink
  31. ftpfs_dir_load
  32. ftpfs_file_store
  33. ftpfs_linear_start
  34. ftpfs_linear_read
  35. ftpfs_linear_close
  36. ftpfs_ctl
  37. ftpfs_send_command
  38. ftpfs_stat
  39. ftpfs_lstat
  40. ftpfs_fstat
  41. ftpfs_chmod
  42. ftpfs_chown
  43. ftpfs_unlink
  44. ftpfs_is_same_dir
  45. ftpfs_chdir_internal
  46. ftpfs_rename
  47. ftpfs_mkdir
  48. ftpfs_rmdir
  49. ftpfs_fh_new
  50. ftpfs_fh_open
  51. ftpfs_fh_close
  52. ftpfs_done
  53. ftpfs_fill_names
  54. ftpfs_netrc_next
  55. ftpfs_netrc_bad_mode
  56. ftpfs_find_machine
  57. ftpfs_netrc_lookup
  58. ftpfs_init_passwd
  59. vfs_init_ftpfs

   1 /*
   2    Virtual File System: FTP file system.
   3 
   4    Copyright (C) 1995-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Ching Hui, 1995
   9    Jakub Jelinek, 1995
  10    Miguel de Icaza, 1995, 1996, 1997
  11    Norbert Warmuth, 1997
  12    Pavel Machek, 1998
  13    Yury V. Zaytsev, 2010
  14    Slava Zanko <slavazanko@gmail.com>, 2010, 2013
  15    Andrew Borodin <aborodin@vmail.ru>, 2010
  16 
  17    This file is part of the Midnight Commander.
  18 
  19    The Midnight Commander is free software: you can redistribute it
  20    and/or modify it under the terms of the GNU General Public License as
  21    published by the Free Software Foundation, either version 3 of the License,
  22    or (at your option) any later version.
  23 
  24    The Midnight Commander is distributed in the hope that it will be useful,
  25    but WITHOUT ANY WARRANTY; without even the implied warranty of
  26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27    GNU General Public License for more details.
  28 
  29    You should have received a copy of the GNU General Public License
  30    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  31  */
  32 
  33 /**
  34  * \file
  35  * \brief Source: Virtual File System: FTP file system
  36  * \author Ching Hui
  37  * \author Jakub Jelinek
  38  * \author Miguel de Icaza
  39  * \author Norbert Warmuth
  40  * \author Pavel Machek
  41  * \date 1995, 1997, 1998
  42  *
  43  * \todo
  44 - make it more robust - all the connects etc. should handle EADDRINUSE and
  45   ERETRY (have I spelled these names correctly?)
  46 - make the user able to flush a connection - all the caches will get empty
  47   etc., (tarfs as well), we should give there a user selectable timeout
  48   and assign a key sequence.
  49 - use hash table instead of linklist to cache ftpfs directory.
  50 
  51 What to do with this?
  52 
  53 
  54      * NOTE: Usage of tildes is deprecated, consider:
  55      * \verbatim
  56          cd ftp//:pavel@hobit
  57          cd ~
  58        \endverbatim
  59      * And now: what do I want to do? Do I want to go to /home/pavel or to
  60      * ftp://hobit/home/pavel? I think first has better sense...
  61      *
  62     \verbatim
  63     {
  64         int f = !strcmp( remote_path, "/~" );
  65         if (f || !strncmp( remote_path, "/~/", 3 )) {
  66             char *s;
  67             s = mc_build_filename ( qhome (*bucket), remote_path +3-f, (char *) NULL );
  68             g_free (remote_path);
  69             remote_path = s;
  70         }
  71     }
  72     \endverbatim
  73  */
  74 
  75 /* \todo Fix: Namespace pollution: horrible */
  76 
  77 #include <config.h>
  78 #include <stdio.h>              /* sscanf() */
  79 #include <stdlib.h>             /* atoi() */
  80 #include <sys/types.h>          /* POSIX-required by sys/socket.h and netdb.h */
  81 #include <netdb.h>              /* struct hostent */
  82 #include <sys/socket.h>         /* AF_INET */
  83 #include <netinet/in.h>         /* struct in_addr */
  84 #ifdef HAVE_ARPA_INET_H
  85 #include <arpa/inet.h>
  86 #endif
  87 #include <arpa/ftp.h>
  88 #include <arpa/telnet.h>
  89 #ifdef HAVE_SYS_PARAM_H
  90 #include <sys/param.h>
  91 #endif
  92 #include <errno.h>
  93 #include <ctype.h>
  94 #include <sys/time.h>           /* gettimeofday() */
  95 #include <inttypes.h>           /* uintmax_t */
  96 
  97 #include "lib/global.h"
  98 #include "lib/util.h"
  99 #include "lib/strutil.h"        /* str_move() */
 100 #include "lib/mcconfig.h"
 101 
 102 #include "lib/tty/tty.h"        /* enable/disable interrupt key */
 103 #include "lib/widget.h"         /* message() */
 104 
 105 #include "src/history.h"
 106 #include "src/setup.h"          /* for load_anon_passwd */
 107 
 108 #include "lib/vfs/vfs.h"
 109 #include "lib/vfs/utilvfs.h"
 110 #include "lib/vfs/netutil.h"
 111 #include "lib/vfs/xdirentry.h"
 112 #include "lib/vfs/gc.h"         /* vfs_stamp_create */
 113 
 114 #include "ftpfs.h"
 115 
 116 /*** global variables ****************************************************************************/
 117 
 118 /* Delay to retry a connection */
 119 int ftpfs_retry_seconds = 30;
 120 
 121 /* Method to use to connect to ftp sites */
 122 gboolean ftpfs_use_passive_connections = TRUE;
 123 gboolean ftpfs_use_passive_connections_over_proxy = FALSE;
 124 
 125 /* Method used to get directory listings:
 126  * 1: try 'LIST -la <path>', if it fails
 127  *    fall back to CWD <path>; LIST
 128  * 0: always use CWD <path>; LIST
 129  */
 130 gboolean ftpfs_use_unix_list_options = TRUE;
 131 
 132 /* First "CWD <path>", then "LIST -la ." */
 133 gboolean ftpfs_first_cd_then_ls = TRUE;
 134 
 135 /* Use the ~/.netrc */
 136 gboolean ftpfs_use_netrc = TRUE;
 137 
 138 /* Anonymous setup */
 139 char *ftpfs_anonymous_passwd = NULL;
 140 int ftpfs_directory_timeout = 900;
 141 
 142 /* Proxy host */
 143 char *ftpfs_proxy_host = NULL;
 144 
 145 /* whether we have to use proxy by default? */
 146 gboolean ftpfs_always_use_proxy = FALSE;
 147 
 148 gboolean ftpfs_ignore_chattr_errors = TRUE;
 149 
 150 /*** file scope macro definitions ****************************************************************/
 151 
 152 #ifndef MAXHOSTNAMELEN
 153 #define MAXHOSTNAMELEN 64
 154 #endif
 155 
 156 #define FTP_SUPER(super) ((ftp_super_t *) (super))
 157 #define FTP_FILE_HANDLER(fh) ((ftp_file_handler_t *) (fh))
 158 #define FH_SOCK FTP_FILE_HANDLER(fh)->sock
 159 
 160 #ifndef INADDR_NONE
 161 #define INADDR_NONE 0xffffffff
 162 #endif
 163 
 164 #define RFC_AUTODETECT 0
 165 #define RFC_DARING 1
 166 #define RFC_STRICT 2
 167 
 168 /* ftpfs_command wait_flag: */
 169 #define NONE        0x00
 170 #define WAIT_REPLY  0x01
 171 #define WANT_STRING 0x02
 172 
 173 #define FTP_COMMAND_PORT   21
 174 
 175 /* some defines only used by ftpfs_changetype */
 176 /* These two are valid values for the second parameter */
 177 #define TYPE_ASCII    0
 178 #define TYPE_BINARY   1
 179 
 180 /* This one is only used to initialize bucket->isbinary, don't use it as
 181    second parameter to ftpfs_changetype. */
 182 #define TYPE_UNKNOWN -1
 183 
 184 #define ABORT_TIMEOUT 5
 185 /*** file scope type declarations ****************************************************************/
 186 
 187 #ifndef HAVE_SOCKLEN_T
 188 typedef int socklen_t;
 189 #endif
 190 
 191 /* This should match the keywords[] array below */
 192 typedef enum
 193 {
 194     NETRC_NONE = 0,
 195     NETRC_DEFAULT,
 196     NETRC_MACHINE,
 197     NETRC_LOGIN,
 198     NETRC_PASSWORD,
 199     NETRC_PASSWD,
 200     NETRC_ACCOUNT,
 201     NETRC_MACDEF,
 202     NETRC_UNKNOWN
 203 } keyword_t;
 204 
 205 typedef struct
 206 {
 207     struct vfs_s_super base;    /* base class */
 208 
 209     int sock;
 210 
 211     char *proxy;                /* proxy server, NULL if no proxy */
 212     gboolean failed_on_login;   /* used to pass the failure reason to upper levels */
 213     gboolean use_passive_connection;
 214     gboolean remote_is_amiga;   /* No leading slash allowed for AmiTCP (Amiga) */
 215     int isbinary;
 216     gboolean cwd_deferred;      /* current_directory was changed but CWD command hasn't
 217                                    been sent yet */
 218     int strict;                 /* ftp server doesn't understand
 219                                  * "LIST -la <path>"; use "CWD <path>"/
 220                                  * "LIST" instead
 221                                  */
 222     gboolean ctl_connection_busy;
 223     char *current_dir;
 224 } ftp_super_t;
 225 
 226 typedef struct
 227 {
 228     vfs_file_handler_t base;    /* base class */
 229 
 230     int sock;
 231     gboolean append;
 232 } ftp_file_handler_t;
 233 
 234 /*** file scope variables ************************************************************************/
 235 
 236 static int ftpfs_errno;
 237 static int code;
 238 
 239 static char reply_str[80];
 240 
 241 static struct vfs_s_subclass ftpfs_subclass;
 242 static struct vfs_class *vfs_ftpfs_ops = VFS_CLASS (&ftpfs_subclass);
 243 
 244 static GSList *no_proxy = NULL;
 245 
 246 static char buffer[BUF_MEDIUM];
 247 static char *netrc = NULL;
 248 static const char *netrcp;
 249 
 250 /* --------------------------------------------------------------------------------------------- */
 251 /*** file scope functions ************************************************************************/
 252 /* --------------------------------------------------------------------------------------------- */
 253 
 254 /* char *ftpfs_translate_path (struct ftpfs_connection *bucket, char *remote_path)
 255    Translate a Unix path, i.e. MC's internal path representation (e.g.
 256    /somedir/somefile) to a path valid for the remote server. Every path
 257    transferred to the remote server has to be mangled by this function
 258    right prior to sending it.
 259    Currently only Amiga ftp servers are handled in a special manner.
 260 
 261    When the remote server is an amiga:
 262    a) strip leading slash if necesarry
 263    b) replace first occurrence of ":/" with ":"
 264    c) strip trailing "/."
 265  */
 266 
 267 static char *ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super);
 268 static int ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super,
 269                                  const char *remote_path);
 270 static int ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super);
 271 static gboolean ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super,
 272                                     const char *netrcpass);
 273 static gboolean ftpfs_netrc_lookup (const char *host, char **login, char **pass);
 274 
 275 /* --------------------------------------------------------------------------------------------- */
 276 
 277 static void
 278 ftpfs_set_blksize (struct stat *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 279 {
 280 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
 281     /* redefine block size */
 282     s->st_blksize = 64 * 1024;  /* FIXME */
 283 #endif
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */
 287 
 288 static struct stat *
 289 ftpfs_default_stat (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     struct stat *s;
 292 
 293     s = vfs_s_default_stat (me, S_IFDIR | 0755);
 294     ftpfs_set_blksize (s);
 295     vfs_adjust_stat (s);
 296 
 297     return s;
 298 }
 299 
 300 /* --------------------------------------------------------------------------------------------- */
 301 
 302 static char *
 303 ftpfs_translate_path (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 304 {
 305     char *ret, *p;
 306 
 307     if (!FTP_SUPER (super)->remote_is_amiga)
 308         return g_strdup (remote_path);
 309 
 310     if (me->logfile != NULL)
 311     {
 312         fprintf (me->logfile, "MC -- ftpfs_translate_path: %s\n", remote_path);
 313         fflush (me->logfile);
 314     }
 315 
 316     /* strip leading slash(es) */
 317     while (IS_PATH_SEP (*remote_path))
 318         remote_path++;
 319 
 320     /* Don't change "/" into "", e.g. "CWD " would be invalid. */
 321     if (*remote_path == '\0')
 322         return g_strdup (".");
 323 
 324     ret = g_strdup (remote_path);
 325 
 326     /* replace first occurrence of ":/" with ":" */
 327     p = strchr (ret, ':');
 328     if (p != NULL && IS_PATH_SEP (p[1]))
 329         str_move (p + 1, p + 2);
 330 
 331     /* strip trailing "/." */
 332     p = strrchr (ret, PATH_SEP);
 333     if ((p != NULL) && (*(p + 1) == '.') && (*(p + 2) == '\0'))
 334         *p = '\0';
 335 
 336     return ret;
 337 }
 338 
 339 /* --------------------------------------------------------------------------------------------- */
 340 /** Extract the hostname and username from the path */
 341 /*
 342  * path is in the form: [user@]hostname:port/remote-dir, e.g.:
 343  * ftp://sunsite.unc.edu/pub/linux
 344  * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
 345  * ftp://tsx-11.mit.edu:8192/
 346  * ftp://joe@foo.edu:11321/private
 347  * If the user is empty, e.g. ftp://@roxanne/private, then your login name
 348  * is supplied.
 349  */
 350 
 351 static vfs_path_element_t *
 352 ftpfs_correct_url_parameters (const vfs_path_element_t * velement)
     /* [previous][next][first][last][top][bottom][index][help]  */
 353 {
 354     vfs_path_element_t *path_element = vfs_path_element_clone (velement);
 355 
 356     if (path_element->port == 0)
 357         path_element->port = FTP_COMMAND_PORT;
 358 
 359     if (path_element->user == NULL)
 360     {
 361         /* Look up user and password in netrc */
 362         if (ftpfs_use_netrc)
 363             ftpfs_netrc_lookup (path_element->host, &path_element->user, &path_element->password);
 364     }
 365     if (path_element->user == NULL)
 366         path_element->user = g_strdup ("anonymous");
 367 
 368     /* Look up password in netrc for known user */
 369     if (ftpfs_use_netrc && path_element->password == NULL)
 370     {
 371         char *new_user = NULL;
 372         char *new_passwd = NULL;
 373 
 374         ftpfs_netrc_lookup (path_element->host, &new_user, &new_passwd);
 375 
 376         /* If user is different, remove password */
 377         if (new_user != NULL && strcmp (path_element->user, new_user) != 0)
 378             MC_PTR_FREE (path_element->password);
 379 
 380         g_free (new_user);
 381         g_free (new_passwd);
 382     }
 383 
 384     return path_element;
 385 }
 386 
 387 /* --------------------------------------------------------------------------------------------- */
 388 /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
 389 
 390 static int
 391 ftpfs_get_reply (struct vfs_class *me, int sock, char *string_buf, int string_len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 392 {
 393     while (TRUE)
 394     {
 395         char answer[BUF_1K];
 396 
 397         if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
 398         {
 399             if (string_buf != NULL)
 400                 *string_buf = '\0';
 401             code = 421;
 402             return 4;
 403         }
 404 
 405         /* cppcheck-suppress invalidscanf */
 406         switch (sscanf (answer, "%d", &code))
 407         {
 408         case 0:
 409             if (string_buf != NULL)
 410                 g_strlcpy (string_buf, answer, string_len);
 411             code = 500;
 412             return 5;
 413         case 1:
 414             if (answer[3] == '-')
 415             {
 416                 while (TRUE)
 417                 {
 418                     int i;
 419 
 420                     if (vfs_s_get_line (me, sock, answer, sizeof (answer), '\n') == 0)
 421                     {
 422                         if (string_buf != NULL)
 423                             *string_buf = '\0';
 424                         code = 421;
 425                         return 4;
 426                     }
 427                     /* cppcheck-suppress invalidscanf */
 428                     if ((sscanf (answer, "%d", &i) > 0) && (code == i) && (answer[3] == ' '))
 429                         break;
 430                 }
 431             }
 432             if (string_buf != NULL)
 433                 g_strlcpy (string_buf, answer, string_len);
 434             return code / 100;
 435         default:
 436             break;
 437         }
 438     }
 439 }
 440 
 441 /* --------------------------------------------------------------------------------------------- */
 442 
 443 static gboolean
 444 ftpfs_reconnect (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 445 {
 446     ftp_super_t *ftp_super = FTP_SUPER (super);
 447     int sock;
 448 
 449     sock = ftpfs_open_socket (me, super);
 450     if (sock != -1)
 451     {
 452         char *cwdir = ftp_super->current_dir;
 453 
 454         close (ftp_super->sock);
 455         ftp_super->sock = sock;
 456         ftp_super->current_dir = NULL;
 457 
 458         if (ftpfs_login_server (me, super, super->path_element->password))
 459         {
 460             if (cwdir == NULL)
 461                 return TRUE;
 462 
 463             sock = ftpfs_chdir_internal (me, super, cwdir);
 464             g_free (cwdir);
 465             return (sock == COMPLETE);
 466         }
 467 
 468         ftp_super->current_dir = cwdir;
 469     }
 470 
 471     return FALSE;
 472 }
 473 
 474 /* --------------------------------------------------------------------------------------------- */
 475 
 476 static int
 477 G_GNUC_PRINTF (4, 5)
     /* [previous][next][first][last][top][bottom][index][help]  */
 478 ftpfs_command (struct vfs_class *me, struct vfs_s_super *super, int wait_reply, const char *fmt,
 479                ...)
 480 {
 481     ftp_super_t *ftp_super = FTP_SUPER (super);
 482     va_list ap;
 483     GString *cmdstr;
 484     int status;
 485     static gboolean retry = FALSE;
 486     static int level = 0;       /* ftpfs_login_server() use ftpfs_command() */
 487 
 488     cmdstr = g_string_sized_new (32);
 489     va_start (ap, fmt);
 490     g_string_vprintf (cmdstr, fmt, ap);
 491     va_end (ap);
 492     g_string_append (cmdstr, "\r\n");
 493 
 494     if (me->logfile != NULL)
 495     {
 496         if (strncmp (cmdstr->str, "PASS ", 5) == 0)
 497             fputs ("PASS <Password not logged>\r\n", me->logfile);
 498         else
 499         {
 500             size_t ret;
 501 
 502             ret = fwrite (cmdstr->str, cmdstr->len, 1, me->logfile);
 503             (void) ret;
 504         }
 505 
 506         fflush (me->logfile);
 507     }
 508 
 509     got_sigpipe = 0;
 510     tty_enable_interrupt_key ();
 511     status = write (ftp_super->sock, cmdstr->str, cmdstr->len);
 512 
 513     if (status < 0)
 514     {
 515         code = 421;
 516 
 517         if (errno == EPIPE)
 518         {                       /* Remote server has closed connection */
 519             if (level == 0)
 520             {
 521                 level = 1;
 522                 status = ftpfs_reconnect (me, super) ? 1 : 0;
 523                 level = 0;
 524                 if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
 525                     goto ok;
 526 
 527             }
 528             got_sigpipe = 1;
 529         }
 530         g_string_free (cmdstr, TRUE);
 531         tty_disable_interrupt_key ();
 532         return TRANSIENT;
 533     }
 534 
 535     retry = FALSE;
 536 
 537   ok:
 538     tty_disable_interrupt_key ();
 539 
 540     if (wait_reply != NONE)
 541     {
 542         status = ftpfs_get_reply (me, ftp_super->sock,
 543                                   (wait_reply & WANT_STRING) != 0 ? reply_str : NULL,
 544                                   sizeof (reply_str) - 1);
 545         if ((wait_reply & WANT_STRING) != 0 && !retry && level == 0 && code == 421)
 546         {
 547             retry = TRUE;
 548             level = 1;
 549             status = ftpfs_reconnect (me, super) ? 1 : 0;
 550             level = 0;
 551             if (status != 0 && (write (ftp_super->sock, cmdstr->str, cmdstr->len) > 0))
 552                 goto ok;
 553         }
 554         retry = FALSE;
 555         g_string_free (cmdstr, TRUE);
 556         return status;
 557     }
 558 
 559     g_string_free (cmdstr, TRUE);
 560     return COMPLETE;
 561 }
 562 
 563 /* --------------------------------------------------------------------------------------------- */
 564 
 565 static struct vfs_s_super *
 566 ftpfs_new_archive (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 567 {
 568     ftp_super_t *arch;
 569 
 570     arch = g_new0 (ftp_super_t, 1);
 571     arch->base.me = me;
 572     arch->base.name = g_strdup (PATH_SEP_STR);
 573     arch->sock = -1;
 574     arch->use_passive_connection = ftpfs_use_passive_connections;
 575     arch->strict = ftpfs_use_unix_list_options ? RFC_AUTODETECT : RFC_STRICT;
 576     arch->isbinary = TYPE_UNKNOWN;
 577 
 578     return VFS_SUPER (arch);
 579 }
 580 
 581 /* --------------------------------------------------------------------------------------------- */
 582 
 583 static void
 584 ftpfs_free_archive (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 585 {
 586     ftp_super_t *ftp_super = FTP_SUPER (super);
 587 
 588     if (ftp_super->sock != -1)
 589     {
 590         vfs_print_message (_("ftpfs: Disconnecting from %s"), super->path_element->host);
 591         ftpfs_command (me, super, NONE, "%s", "QUIT");
 592         close (ftp_super->sock);
 593     }
 594     g_free (ftp_super->current_dir);
 595 }
 596 
 597 /* --------------------------------------------------------------------------------------------- */
 598 
 599 static int
 600 ftpfs_changetype (struct vfs_class *me, struct vfs_s_super *super, int binary)
     /* [previous][next][first][last][top][bottom][index][help]  */
 601 {
 602     if (binary != FTP_SUPER (super)->isbinary)
 603     {
 604         if (ftpfs_command (me, super, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE)
 605             ERRNOR (EIO, -1);
 606         FTP_SUPER (super)->isbinary = binary;
 607     }
 608     return binary;
 609 }
 610 
 611 /* --------------------------------------------------------------------------------------------- */
 612 /* This routine logs the user in */
 613 
 614 static int
 615 ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super, const char *netrcpass)
     /* [previous][next][first][last][top][bottom][index][help]  */
 616 {
 617     ftp_super_t *ftp_super = FTP_SUPER (super);
 618     char *pass;
 619     char *op;
 620     char *name;                 /* login user name */
 621     gboolean anon = FALSE;
 622     char reply_string[BUF_MEDIUM];
 623 
 624     ftp_super->isbinary = TYPE_UNKNOWN;
 625 
 626     if (super->path_element->password != NULL)  /* explicit password */
 627         op = g_strdup (super->path_element->password);
 628     else if (netrcpass != NULL) /* password from netrc */
 629         op = g_strdup (netrcpass);
 630     else if (strcmp (super->path_element->user, "anonymous") == 0
 631              || strcmp (super->path_element->user, "ftp") == 0)
 632     {
 633         if (ftpfs_anonymous_passwd == NULL)     /* default anonymous password */
 634             ftpfs_init_passwd ();
 635         op = g_strdup (ftpfs_anonymous_passwd);
 636         anon = TRUE;
 637     }
 638     else
 639     {                           /* ask user */
 640         char *p;
 641 
 642         p = g_strdup_printf (_("FTP: Password required for %s"), super->path_element->user);
 643         op = vfs_get_password (p);
 644         g_free (p);
 645         if (op == NULL)
 646             ERRNOR (EPERM, 0);
 647         super->path_element->password = g_strdup (op);
 648     }
 649 
 650     if (!anon || me->logfile != NULL)
 651         pass = op;
 652     else
 653     {
 654         pass = g_strconcat ("-", op, (char *) NULL);
 655         wipe_password (op);
 656     }
 657 
 658     /* Proxy server accepts: username@host-we-want-to-connect */
 659     if (ftp_super->proxy != NULL)
 660         name =
 661             g_strconcat (super->path_element->user, "@",
 662                          super->path_element->host[0] ==
 663                          '!' ? super->path_element->host + 1 : super->path_element->host,
 664                          (char *) NULL);
 665     else
 666         name = g_strdup (super->path_element->user);
 667 
 668     if (ftpfs_get_reply (me, ftp_super->sock, reply_string, sizeof (reply_string) - 1) == COMPLETE)
 669     {
 670         char *reply_up;
 671 
 672         reply_up = g_ascii_strup (reply_string, -1);
 673         ftp_super->remote_is_amiga = strstr (reply_up, "AMIGA") != NULL;
 674         if (strstr (reply_up, " SPFTP/1.0.0000 SERVER ") != NULL)       /* handles `LIST -la` in a weird way */
 675             ftp_super->strict = RFC_STRICT;
 676         g_free (reply_up);
 677 
 678         if (me->logfile != NULL)
 679         {
 680             fprintf (me->logfile, "MC -- remote_is_amiga = %s\n",
 681                      ftp_super->remote_is_amiga ? "yes" : "no");
 682             fflush (me->logfile);
 683         }
 684 
 685         vfs_print_message ("%s", _("ftpfs: sending login name"));
 686 
 687         switch (ftpfs_command (me, super, WAIT_REPLY, "USER %s", name))
 688         {
 689         case CONTINUE:
 690             vfs_print_message ("%s", _("ftpfs: sending user password"));
 691             code = ftpfs_command (me, super, WAIT_REPLY, "PASS %s", pass);
 692             if (code == CONTINUE)
 693             {
 694                 char *p;
 695 
 696                 p = g_strdup_printf (_("FTP: Account required for user %s"),
 697                                      super->path_element->user);
 698                 op = input_dialog (p, _("Account:"), MC_HISTORY_FTPFS_ACCOUNT, "",
 699                                    INPUT_COMPLETE_USERNAMES);
 700                 g_free (p);
 701                 if (op == NULL)
 702                     ERRNOR (EPERM, 0);
 703                 vfs_print_message ("%s", _("ftpfs: sending user account"));
 704                 code = ftpfs_command (me, super, WAIT_REPLY, "ACCT %s", op);
 705                 g_free (op);
 706             }
 707             if (code != COMPLETE)
 708                 break;
 709 
 710             MC_FALLTHROUGH;
 711 
 712         case COMPLETE:
 713             vfs_print_message ("%s", _("ftpfs: logged in"));
 714             wipe_password (pass);
 715             g_free (name);
 716             return TRUE;
 717 
 718         default:
 719             ftp_super->failed_on_login = TRUE;
 720             wipe_password (super->path_element->password);
 721             super->path_element->password = NULL;
 722             goto login_fail;
 723         }
 724     }
 725 
 726     message (D_ERROR, MSG_ERROR, _("ftpfs: Login incorrect for user %s "),
 727              super->path_element->user);
 728 
 729   login_fail:
 730     wipe_password (pass);
 731     g_free (name);
 732     ERRNOR (EPERM, FALSE);
 733 }
 734 
 735 /* --------------------------------------------------------------------------------------------- */
 736 
 737 static void
 738 ftpfs_load_no_proxy_list (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 739 {
 740     /* FixMe: shouldn't be hardcoded!!! */
 741     char *mc_file;
 742 
 743     mc_file = g_build_filename (mc_global.sysconfig_dir, "mc.no_proxy", (char *) NULL);
 744     if (exist_file (mc_file))
 745     {
 746         FILE *npf;
 747 
 748         npf = fopen (mc_file, "r");
 749         if (npf != NULL)
 750         {
 751             char s[BUF_LARGE];  /* provide for BUF_LARGE characters */
 752 
 753             while (fgets (s, sizeof (s), npf) != NULL)
 754             {
 755                 char *p;
 756 
 757                 p = strchr (s, '\n');
 758                 if (p == NULL)  /* skip bogus entries */
 759                 {
 760                     int c;
 761 
 762                     while ((c = fgetc (npf)) != EOF && c != '\n')
 763                         ;
 764                 }
 765                 else if (p != s)
 766                 {
 767                     *p = '\0';
 768                     no_proxy = g_slist_prepend (no_proxy, g_strdup (s));
 769                 }
 770             }
 771 
 772             fclose (npf);
 773         }
 774     }
 775 
 776     g_free (mc_file);
 777 }
 778 
 779 /* --------------------------------------------------------------------------------------------- */
 780 /* Return TRUE if FTP proxy should be used for this host, FALSE otherwise */
 781 
 782 static gboolean
 783 ftpfs_check_proxy (const char *host)
     /* [previous][next][first][last][top][bottom][index][help]  */
 784 {
 785     GSList *npe;
 786 
 787     if (ftpfs_proxy_host == NULL || *ftpfs_proxy_host == '\0' || host == NULL || *host == '\0')
 788         return FALSE;           /* sanity check */
 789 
 790     if (*host == '!')
 791         return TRUE;
 792 
 793     if (!ftpfs_always_use_proxy)
 794         return FALSE;
 795 
 796     if (strchr (host, '.') == NULL)
 797         return FALSE;
 798 
 799     ftpfs_load_no_proxy_list ();
 800     for (npe = no_proxy; npe != NULL; npe = g_slist_next (npe))
 801     {
 802         const char *domain = (const char *) npe->data;
 803 
 804         if (domain[0] == '.')
 805         {
 806             size_t ld, lh;
 807 
 808             ld = strlen (domain);
 809             lh = strlen (host);
 810 
 811             while (ld != 0 && lh != 0 && host[lh - 1] == domain[ld - 1])
 812             {
 813                 ld--;
 814                 lh--;
 815             }
 816 
 817             if (ld == 0)
 818                 return FALSE;
 819         }
 820         else if (g_ascii_strcasecmp (host, domain) == 0)
 821             return FALSE;
 822     }
 823 
 824     return TRUE;
 825 }
 826 
 827 /* --------------------------------------------------------------------------------------------- */
 828 
 829 static void
 830 ftpfs_get_proxy_host_and_port (const char *proxy, char **host, int *port)
     /* [previous][next][first][last][top][bottom][index][help]  */
 831 {
 832     vfs_path_element_t *path_element;
 833 
 834     path_element = vfs_url_split (proxy, FTP_COMMAND_PORT, URL_USE_ANONYMOUS);
 835     *host = path_element->host;
 836     path_element->host = NULL;
 837     *port = path_element->port;
 838     vfs_path_element_free (path_element);
 839 }
 840 
 841 /* --------------------------------------------------------------------------------------------- */
 842 
 843 static int
 844 ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 845 {
 846     struct addrinfo hints, *res, *curr_res;
 847     int my_socket = 0;
 848     char *host = NULL;
 849     char port[8];
 850     int tmp_port = 0;
 851     int e;
 852 
 853     (void) me;
 854 
 855     if (super->path_element->host == NULL || *super->path_element->host == '\0')
 856     {
 857         vfs_print_message ("%s", _("ftpfs: Invalid host name."));
 858         ftpfs_errno = EINVAL;
 859         return (-1);
 860     }
 861 
 862     /* Use a proxy host? */
 863     /* Hosts to connect to that start with a ! should use proxy */
 864     if (FTP_SUPER (super)->proxy != NULL)
 865         ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &tmp_port);
 866     else
 867     {
 868         host = g_strdup (super->path_element->host);
 869         tmp_port = super->path_element->port;
 870     }
 871 
 872     g_snprintf (port, sizeof (port), "%hu", (unsigned short) tmp_port);
 873 
 874     tty_enable_interrupt_key ();        /* clear the interrupt flag */
 875 
 876     memset (&hints, 0, sizeof (hints));
 877     hints.ai_family = AF_UNSPEC;
 878     hints.ai_socktype = SOCK_STREAM;
 879 
 880 #ifdef AI_ADDRCONFIG
 881     /* By default, only look up addresses using address types for
 882      * which a local interface is configured (i.e. no IPv6 if no IPv6
 883      * interfaces, likewise for IPv4 (see RFC 3493 for details). */
 884     hints.ai_flags = AI_ADDRCONFIG;
 885 #endif
 886 
 887     e = getaddrinfo (host, port, &hints, &res);
 888 
 889 #ifdef AI_ADDRCONFIG
 890     if (e == EAI_BADFLAGS)
 891     {
 892         /* Retry with no flags if AI_ADDRCONFIG was rejected. */
 893         hints.ai_flags = 0;
 894         e = getaddrinfo (host, port, &hints, &res);
 895     }
 896 #endif
 897 
 898     *port = '\0';
 899 
 900     if (e != 0)
 901     {
 902         tty_disable_interrupt_key ();
 903         vfs_print_message (_("ftpfs: %s"), gai_strerror (e));
 904         g_free (host);
 905         ftpfs_errno = EINVAL;
 906         return (-1);
 907     }
 908 
 909     for (curr_res = res; curr_res != NULL; curr_res = curr_res->ai_next)
 910     {
 911         my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol);
 912 
 913         if (my_socket < 0)
 914         {
 915             if (curr_res->ai_next != NULL)
 916                 continue;
 917 
 918             tty_disable_interrupt_key ();
 919             vfs_print_message (_("ftpfs: %s"), unix_error_string (errno));
 920             g_free (host);
 921             freeaddrinfo (res);
 922             ftpfs_errno = errno;
 923             return (-1);
 924         }
 925 
 926         vfs_print_message (_("ftpfs: making connection to %s"), host);
 927         MC_PTR_FREE (host);
 928 
 929         if (connect (my_socket, curr_res->ai_addr, curr_res->ai_addrlen) >= 0)
 930             break;
 931 
 932         ftpfs_errno = errno;
 933         close (my_socket);
 934 
 935         if (errno == EINTR && tty_got_interrupt ())
 936             vfs_print_message ("%s", _("ftpfs: connection interrupted by user"));
 937         else if (res->ai_next == NULL)
 938             vfs_print_message (_("ftpfs: connection to server failed: %s"),
 939                                unix_error_string (errno));
 940         else
 941             continue;
 942 
 943         freeaddrinfo (res);
 944         tty_disable_interrupt_key ();
 945         return (-1);
 946     }
 947 
 948     freeaddrinfo (res);
 949     tty_disable_interrupt_key ();
 950     return my_socket;
 951 }
 952 
 953 /* --------------------------------------------------------------------------------------------- */
 954 
 955 static int
 956 ftpfs_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 957 {
 958     ftp_super_t *ftp_super = FTP_SUPER (super);
 959     int retry_seconds = 0;
 960 
 961     /* We do not want to use the passive if we are using proxies */
 962     if (ftp_super->proxy != NULL)
 963         ftp_super->use_passive_connection = ftpfs_use_passive_connections_over_proxy;
 964 
 965     do
 966     {
 967         ftp_super->failed_on_login = FALSE;
 968 
 969         ftp_super->sock = ftpfs_open_socket (me, super);
 970         if (ftp_super->sock == -1)
 971             return (-1);
 972 
 973         if (ftpfs_login_server (me, super, NULL))
 974         {
 975             /* Logged in, no need to retry the connection */
 976             break;
 977         }
 978 
 979         if (!ftp_super->failed_on_login)
 980             return (-1);
 981 
 982         /* Close only the socket descriptor */
 983         close (ftp_super->sock);
 984 
 985         if (ftpfs_retry_seconds != 0)
 986         {
 987             int count_down;
 988 
 989             retry_seconds = ftpfs_retry_seconds;
 990             tty_enable_interrupt_key ();
 991             for (count_down = retry_seconds; count_down != 0; count_down--)
 992             {
 993                 vfs_print_message (_("Waiting to retry... %d (Control-G to cancel)"), count_down);
 994                 sleep (1);
 995                 if (tty_got_interrupt ())
 996                 {
 997                     /* ftpfs_errno = E; */
 998                     tty_disable_interrupt_key ();
 999                     return 0;
1000                 }
1001             }
1002             tty_disable_interrupt_key ();
1003         }
1004     }
1005     while (retry_seconds != 0);
1006 
1007     ftp_super->current_dir = ftpfs_get_current_directory (me, super);
1008     if (ftp_super->current_dir == NULL)
1009         ftp_super->current_dir = g_strdup (PATH_SEP_STR);
1010 
1011     return 0;
1012 }
1013 
1014 /* --------------------------------------------------------------------------------------------- */
1015 
1016 static int
1017 ftpfs_open_archive (struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1018                     const vfs_path_t * vpath, const vfs_path_element_t * vpath_element)
1019 {
1020     (void) vpath;
1021 
1022     super->path_element = ftpfs_correct_url_parameters (vpath_element);
1023     if (ftpfs_check_proxy (super->path_element->host))
1024         FTP_SUPER (super)->proxy = ftpfs_proxy_host;
1025     super->root =
1026         vfs_s_new_inode (vpath_element->class, super, ftpfs_default_stat (vpath_element->class));
1027 
1028     return ftpfs_open_archive_int (vpath_element->class, super);
1029 }
1030 
1031 /* --------------------------------------------------------------------------------------------- */
1032 
1033 static int
1034 ftpfs_archive_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1035                     const vfs_path_t * vpath, void *cookie)
1036 {
1037     vfs_path_element_t *path_element;
1038     int result;
1039 
1040     (void) vpath;
1041     (void) cookie;
1042 
1043     path_element = ftpfs_correct_url_parameters (vpath_element);
1044 
1045     result = ((strcmp (path_element->host, super->path_element->host) == 0)
1046               && (strcmp (path_element->user, super->path_element->user) == 0)
1047               && (path_element->port == super->path_element->port)) ? 1 : 0;
1048 
1049     vfs_path_element_free (path_element);
1050     return result;
1051 }
1052 
1053 /* --------------------------------------------------------------------------------------------- */
1054 /* The returned directory should always contain a trailing slash */
1055 
1056 static char *
1057 ftpfs_get_current_directory (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
1058 {
1059     char buf[MC_MAXPATHLEN + 1];
1060 
1061     if (ftpfs_command (me, super, NONE, "%s", "PWD") == COMPLETE &&
1062         ftpfs_get_reply (me, FTP_SUPER (super)->sock, buf, sizeof (buf)) == COMPLETE)
1063     {
1064         char *bufp = NULL;
1065         char *bufq;
1066 
1067         for (bufq = buf; *bufq != '\0'; bufq++)
1068             if (*bufq == '"')
1069             {
1070                 if (bufp == NULL)
1071                     bufp = bufq + 1;
1072                 else
1073                 {
1074                     *bufq = '\0';
1075 
1076                     if (*bufp != '\0')
1077                     {
1078                         if (!IS_PATH_SEP (bufq[-1]))
1079                         {
1080                             *bufq++ = PATH_SEP;
1081                             *bufq = '\0';
1082                         }
1083 
1084                         if (IS_PATH_SEP (*bufp))
1085                             return g_strdup (bufp);
1086 
1087                         /* If the remote server is an Amiga a leading slash
1088                            might be missing. MC needs it because it is used
1089                            as separator between hostname and path internally. */
1090                         return g_strconcat (PATH_SEP_STR, bufp, (char *) NULL);
1091                     }
1092 
1093                     break;
1094                 }
1095             }
1096     }
1097 
1098     ftpfs_errno = EIO;
1099     return NULL;
1100 }
1101 
1102 /* --------------------------------------------------------------------------------------------- */
1103 /* Setup Passive PASV FTP connection */
1104 
1105 static gboolean
1106 ftpfs_setup_passive_pasv (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1107                           int my_socket, struct sockaddr_storage *sa, socklen_t * salen)
1108 {
1109     char *c;
1110     char n[6];
1111     int xa, xb, xc, xd, xe, xf;
1112 
1113     if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "PASV") != COMPLETE)
1114         return FALSE;
1115 
1116     /* Parse remote parameters */
1117     for (c = reply_str + 4; *c != '\0' && !isdigit ((unsigned char) *c); c++)
1118         ;
1119 
1120     if (*c == '\0' || !isdigit ((unsigned char) *c))
1121         return FALSE;
1122 
1123     /* cppcheck-suppress invalidscanf */
1124     if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
1125         return FALSE;
1126 
1127     n[0] = (unsigned char) xa;
1128     n[1] = (unsigned char) xb;
1129     n[2] = (unsigned char) xc;
1130     n[3] = (unsigned char) xd;
1131     n[4] = (unsigned char) xe;
1132     n[5] = (unsigned char) xf;
1133 
1134     memcpy (&(((struct sockaddr_in *) sa)->sin_addr.s_addr), (void *) n, 4);
1135     memcpy (&(((struct sockaddr_in *) sa)->sin_port), (void *) &n[4], 2);
1136 
1137     return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1138 }
1139 
1140 /* --------------------------------------------------------------------------------------------- */
1141 /* Setup Passive EPSV FTP connection */
1142 
1143 static gboolean
1144 ftpfs_setup_passive_epsv (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1145                           int my_socket, struct sockaddr_storage *sa, socklen_t * salen)
1146 {
1147     char *c;
1148     int port;
1149 
1150     if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "%s", "EPSV") != COMPLETE)
1151         return FALSE;
1152 
1153     /* (|||<port>|) */
1154     c = strchr (reply_str, '|');
1155     if (c == NULL)
1156         return FALSE;
1157     if (strlen (c) > 3)
1158         c += 3;
1159     else
1160         return FALSE;
1161 
1162     port = atoi (c);
1163     if (port < 0 || port > 65535)
1164         return FALSE;
1165 
1166     port = htons (port);
1167 
1168     switch (sa->ss_family)
1169     {
1170     case AF_INET:
1171         ((struct sockaddr_in *) sa)->sin_port = port;
1172         break;
1173     case AF_INET6:
1174         ((struct sockaddr_in6 *) sa)->sin6_port = port;
1175         break;
1176     default:
1177         break;
1178     }
1179 
1180     return (connect (my_socket, (struct sockaddr *) sa, *salen) >= 0);
1181 }
1182 
1183 /* --------------------------------------------------------------------------------------------- */
1184 /* Setup Passive ftp connection, we use it for source routed connections */
1185 
1186 static gboolean
1187 ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1188                      int my_socket, struct sockaddr_storage *sa, socklen_t * salen)
1189 {
1190     /* It's IPV4, so try PASV first, some servers and ALGs get confused by EPSV */
1191     if (sa->ss_family == AF_INET)
1192     {
1193         if (!ftpfs_setup_passive_pasv (me, super, my_socket, sa, salen))
1194             /* An IPV4 FTP server might support EPSV, so if PASV fails we can try EPSV anyway */
1195             if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1196                 return FALSE;
1197     }
1198     /* It's IPV6, so EPSV is our only hope */
1199     else if (!ftpfs_setup_passive_epsv (me, super, my_socket, sa, salen))
1200         return FALSE;
1201 
1202     return TRUE;
1203 }
1204 
1205 /* --------------------------------------------------------------------------------------------- */
1206 /* Setup Active PORT or EPRT FTP connection */
1207 
1208 static int
1209 ftpfs_setup_active (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1210                     struct sockaddr_storage data_addr, socklen_t data_addrlen)
1211 {
1212     unsigned short int port;
1213     char *addr;
1214     unsigned int af;
1215     int res;
1216 
1217     switch (data_addr.ss_family)
1218     {
1219     case AF_INET:
1220         af = FTP_INET;
1221         port = ((struct sockaddr_in *) &data_addr)->sin_port;
1222         break;
1223     case AF_INET6:
1224         af = FTP_INET6;
1225         port = ((struct sockaddr_in6 *) &data_addr)->sin6_port;
1226         break;
1227     default:
1228         /* Not implemented */
1229         return 0;
1230     }
1231 
1232     addr = g_try_malloc (NI_MAXHOST);
1233     if (addr == NULL)
1234         ERRNOR (ENOMEM, -1);
1235 
1236     if (getnameinfo
1237         ((struct sockaddr *) &data_addr, data_addrlen, addr, NI_MAXHOST, NULL, 0,
1238          NI_NUMERICHOST) != 0)
1239     {
1240         g_free (addr);
1241         ERRNOR (EIO, -1);
1242     }
1243 
1244     /* If we are talking to an IPV4 server, try PORT, and, only if it fails, go for EPRT */
1245     if (af == FTP_INET)
1246     {
1247         unsigned char *a = (unsigned char *) &((struct sockaddr_in *) &data_addr)->sin_addr;
1248         unsigned char *p = (unsigned char *) &port;
1249 
1250         if (ftpfs_command (me, super, WAIT_REPLY,
1251                            "PORT %u,%u,%u,%u,%u,%u", a[0], a[1], a[2], a[3],
1252                            p[0], p[1]) == COMPLETE)
1253         {
1254             g_free (addr);
1255             return 1;
1256         }
1257     }
1258 
1259     /*
1260      * Converts network MSB first order to host byte order (LSB
1261      * first on i386). If we do it earlier, we will run into an
1262      * endianness issue, because the server actually expects to see
1263      * "PORT A,D,D,R,MSB,LSB" in the PORT command.
1264      */
1265     port = ntohs (port);
1266 
1267     /* We are talking to an IPV6 server or PORT failed, so we can try EPRT anyway */
1268     res =
1269         (ftpfs_command (me, super, WAIT_REPLY, "EPRT |%u|%s|%hu|", af, addr, port) ==
1270          COMPLETE) ? 1 : 0;
1271     g_free (addr);
1272     return res;
1273 }
1274 
1275 /* --------------------------------------------------------------------------------------------- */
1276 /* Initialize a socket for FTP DATA connection */
1277 
1278 static int
1279 ftpfs_init_data_socket (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1280                         struct sockaddr_storage *data_addr, socklen_t * data_addrlen)
1281 {
1282     ftp_super_t *ftp_super = FTP_SUPER (super);
1283     int result;
1284 
1285     memset (data_addr, 0, sizeof (*data_addr));
1286     *data_addrlen = sizeof (*data_addr);
1287 
1288     if (ftp_super->use_passive_connection)
1289         result = getpeername (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1290     else
1291         result = getsockname (ftp_super->sock, (struct sockaddr *) data_addr, data_addrlen);
1292 
1293     if (result == -1)
1294         return (-1);
1295 
1296     switch (data_addr->ss_family)
1297     {
1298     case AF_INET:
1299         ((struct sockaddr_in *) data_addr)->sin_port = 0;
1300         break;
1301     case AF_INET6:
1302         ((struct sockaddr_in6 *) data_addr)->sin6_port = 0;
1303         break;
1304     default:
1305         vfs_print_message ("%s", _("ftpfs: invalid address family"));
1306         ERRNOR (EINVAL, -1);
1307     }
1308 
1309     result = socket (data_addr->ss_family, SOCK_STREAM, IPPROTO_TCP);
1310 
1311     if (result < 0)
1312     {
1313         vfs_print_message (_("ftpfs: could not create socket: %s"), unix_error_string (errno));
1314         return (-1);
1315     }
1316 
1317     return result;
1318 }
1319 
1320 /* --------------------------------------------------------------------------------------------- */
1321 /* Initialize FTP DATA connection */
1322 
1323 static int
1324 ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
1325 {
1326     ftp_super_t *ftp_super = FTP_SUPER (super);
1327     struct sockaddr_storage data_addr;
1328     socklen_t data_addrlen;
1329 
1330     /*
1331      * Don't factor socket initialization out of these conditionals,
1332      * because ftpfs_init_data_socket initializes it in different way
1333      * depending on use_passive_connection flag.
1334      */
1335 
1336     /* Try to establish a passive connection first (if requested) */
1337     if (ftp_super->use_passive_connection)
1338     {
1339         int data_sock;
1340 
1341         data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1342         if (data_sock < 0)
1343             return (-1);
1344 
1345         if (ftpfs_setup_passive (me, super, data_sock, &data_addr, &data_addrlen))
1346             return data_sock;
1347 
1348         vfs_print_message ("%s", _("ftpfs: could not setup passive mode"));
1349         ftp_super->use_passive_connection = FALSE;
1350 
1351         close (data_sock);
1352     }
1353 
1354     /* If passive setup is diabled or failed, fallback to active connections */
1355     if (!ftp_super->use_passive_connection)
1356     {
1357         int data_sock;
1358 
1359         data_sock = ftpfs_init_data_socket (me, super, &data_addr, &data_addrlen);
1360         if (data_sock < 0)
1361             return (-1);
1362 
1363         if ((bind (data_sock, (struct sockaddr *) &data_addr, data_addrlen) == 0) &&
1364             (getsockname (data_sock, (struct sockaddr *) &data_addr, &data_addrlen) == 0) &&
1365             (listen (data_sock, 1) == 0) &&
1366             (ftpfs_setup_active (me, super, data_addr, data_addrlen) != 0))
1367             return data_sock;
1368 
1369         close (data_sock);
1370     }
1371 
1372     /* Restore the initial value of use_passive_connection (for subsequent retries) */
1373     ftp_super->use_passive_connection =
1374         ftp_super->proxy !=
1375         NULL ? ftpfs_use_passive_connections_over_proxy : ftpfs_use_passive_connections;
1376 
1377     ftpfs_errno = EIO;
1378     return (-1);
1379 }
1380 
1381 /* --------------------------------------------------------------------------------------------- */
1382 
1383 static int
1384 ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
     /* [previous][next][first][last][top][bottom][index][help]  */
1385                             const char *remote, int isbinary, int reget)
1386 {
1387     ftp_super_t *ftp_super = FTP_SUPER (super);
1388     int s, j, data;
1389 
1390     /* FTP doesn't allow to open more than one file at a time */
1391     if (ftp_super->ctl_connection_busy)
1392         return (-1);
1393 
1394     s = ftpfs_initconn (me, super);
1395     if (s == -1)
1396         return (-1);
1397 
1398     if (ftpfs_changetype (me, super, isbinary) == -1)
1399     {
1400         close (s);
1401         return (-1);
1402     }
1403 
1404     if (reget > 0)
1405     {
1406         j = ftpfs_command (me, super, WAIT_REPLY, "REST %d", reget);
1407         if (j != CONTINUE)
1408         {
1409             close (s);
1410             return (-1);
1411         }
1412     }
1413 
1414     if (remote == NULL)
1415         j = ftpfs_command (me, super, WAIT_REPLY, "%s", cmd);
1416     else
1417     {
1418         char *remote_path;
1419 
1420         remote_path = ftpfs_translate_path (me, super, remote);
1421         j = ftpfs_command (me, super, WAIT_REPLY, "%s /%s", cmd,
1422                            /* WarFtpD can't STORE //filename */
1423                            IS_PATH_SEP (*remote_path) ? remote_path + 1 : remote_path);
1424         g_free (remote_path);
1425     }
1426 
1427     if (j != PRELIM)
1428     {
1429         close (s);
1430         ERRNOR (EPERM, -1);
1431     }
1432 
1433     if (ftp_super->use_passive_connection)
1434         data = s;
1435     else
1436     {
1437         struct sockaddr_storage from;
1438         socklen_t fromlen = sizeof (from);
1439 
1440         tty_enable_interrupt_key ();
1441         data = accept (s, (struct sockaddr *) &from, &fromlen);
1442         if (data < 0)
1443             ftpfs_errno = errno;
1444         tty_disable_interrupt_key ();
1445         close (s);
1446         if (data < 0)
1447             return (-1);
1448     }
1449 
1450     ftp_super->ctl_connection_busy = TRUE;
1451     return data;
1452 }
1453 
1454 /* --------------------------------------------------------------------------------------------- */
1455 
1456 static void
1457 ftpfs_linear_abort (struct vfs_class *me, vfs_file_handler_t * fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
1458 {
1459     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1460     ftp_super_t *ftp_super = FTP_SUPER (super);
1461     static unsigned char const ipbuf[3] = { IAC, IP, IAC };
1462     fd_set mask;
1463     int dsock = FH_SOCK;
1464 
1465     FH_SOCK = -1;
1466     ftp_super->ctl_connection_busy = FALSE;
1467 
1468     vfs_print_message ("%s", _("ftpfs: aborting transfer."));
1469 
1470     if (send (ftp_super->sock, ipbuf, sizeof (ipbuf), MSG_OOB) != sizeof (ipbuf))
1471     {
1472         vfs_print_message (_("ftpfs: abort error: %s"), unix_error_string (errno));
1473         if (dsock != -1)
1474             close (dsock);
1475         return;
1476     }
1477 
1478     if (ftpfs_command (me, super, NONE, "%cABOR", DM) != COMPLETE)
1479     {
1480         vfs_print_message ("%s", _("ftpfs: abort failed"));
1481         if (dsock != -1)
1482             close (dsock);
1483         return;
1484     }
1485 
1486     if (dsock != -1)
1487     {
1488         FD_ZERO (&mask);
1489         FD_SET (dsock, &mask);
1490 
1491         if (select (dsock + 1, &mask, NULL, NULL, NULL) > 0)
1492         {
1493             struct timeval start_tim;
1494             char buf[BUF_8K];
1495 
1496             gettimeofday (&start_tim, NULL);
1497             /* flush the remaining data */
1498             while (read (dsock, buf, sizeof (buf)) > 0)
1499             {
1500                 struct timeval tim;
1501 
1502                 gettimeofday (&tim, NULL);
1503                 if (tim.tv_sec > start_tim.tv_sec + ABORT_TIMEOUT)
1504                 {
1505                     /* server keeps sending, drop the connection and ftpfs_reconnect */
1506                     close (dsock);
1507                     ftpfs_reconnect (me, super);
1508                     return;
1509                 }
1510             }
1511         }
1512         close (dsock);
1513     }
1514 
1515     if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) == TRANSIENT) && (code == 426))
1516         ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1517 }
1518 
1519 /* --------------------------------------------------------------------------------------------- */
1520 
1521 #if 0
1522 static void
1523 resolve_symlink_without_ls_options (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1524                                     struct vfs_s_inode *dir)
1525 {
1526     struct linklist *flist;
1527     struct direntry *fe, *fel;
1528     char tmp[MC_MAXPATHLEN];
1529 
1530     dir->symlink_status = FTPFS_RESOLVING_SYMLINKS;
1531     for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next)
1532     {
1533         /* flist->data->l_stat is alread initialized with 0 */
1534         fel = flist->data;
1535         if (S_ISLNK (fel->s.st_mode) && fel->linkname != NULL)
1536         {
1537             int depth;
1538 
1539             if (IS_PATH_SEP (fel->linkname[0]))
1540             {
1541                 if (strlen (fel->linkname) >= MC_MAXPATHLEN)
1542                     continue;
1543                 strcpy (tmp, fel->linkname);
1544             }
1545             else
1546             {
1547                 if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
1548                     continue;
1549                 strcpy (tmp, dir->remote_path);
1550                 if (tmp[1] != '\0')
1551                     strcat (tmp, PATH_SEP_STR);
1552                 strcat (tmp + 1, fel->linkname);
1553             }
1554 
1555             for (depth = 0; depth < 100; depth++)
1556             {                   /* depth protects against recursive symbolic links */
1557                 canonicalize_pathname (tmp);
1558                 fe = _get_file_entry_t (bucket, tmp, 0, 0);
1559                 if (fe != NULL)
1560                 {
1561                     if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0)
1562                     {
1563                         /* Symlink points to link which isn't resolved, yet. */
1564                         if (IS_PATH_SEP (fe->linkname[0]))
1565                         {
1566                             if (strlen (fe->linkname) >= MC_MAXPATHLEN)
1567                                 break;
1568                             strcpy (tmp, fe->linkname);
1569                         }
1570                         else
1571                         {
1572                             /* at this point tmp looks always like this
1573                                /directory/filename, i.e. no need to check
1574                                strrchr's return value */
1575                             *(strrchr (tmp, PATH_SEP) + 1) = '\0';      /* dirname */
1576                             if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
1577                                 break;
1578                             strcat (tmp, fe->linkname);
1579                         }
1580                         continue;
1581                     }
1582                     else
1583                     {
1584                         fel->l_stat = g_new (struct stat, 1);
1585                         if (S_ISLNK (fe->s.st_mode))
1586                             *fel->l_stat = *fe->l_stat;
1587                         else
1588                             *fel->l_stat = fe->s;
1589                         (*fel->l_stat).st_ino = bucket->__inode_counter++;
1590                     }
1591                 }
1592                 break;
1593             }
1594         }
1595     }
1596 
1597     dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1598 }
1599 
1600 /* --------------------------------------------------------------------------------------------- */
1601 
1602 static void
1603 resolve_symlink_with_ls_options (struct vfs_class *me, struct vfs_s_super *super,
     /* [previous][next][first][last][top][bottom][index][help]  */
1604                                  struct vfs_s_inode *dir)
1605 {
1606     char buffer[2048] = "", *filename;
1607     int sock;
1608     FILE *fp;
1609     struct stat s;
1610     struct linklist *flist;
1611     struct direntry *fe;
1612     int switch_method = 0;
1613 
1614     dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
1615     if (strchr (dir->remote_path, ' ') == NULL)
1616         sock = ftpfs_open_data_connection (bucket, "LIST -lLa", dir->remote_path, TYPE_ASCII, 0);
1617     else
1618     {
1619         if (ftpfs_chdir_internal (bucket, dir->remote_path) != COMPLETE)
1620         {
1621             vfs_print_message ("%s", _("ftpfs: CWD failed."));
1622             return;
1623         }
1624 
1625         sock = ftpfs_open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII, 0);
1626     }
1627 
1628     if (sock == -1)
1629     {
1630         vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1631         return;
1632     }
1633 
1634     fp = fdopen (sock, "r");
1635     if (fp == NULL)
1636     {
1637         close (sock);
1638         vfs_print_message ("%s", _("ftpfs: couldn't resolve symlink"));
1639         return;
1640     }
1641     tty_enable_interrupt_key ();
1642     flist = dir->file_list->next;
1643 
1644     while (TRUE)
1645     {
1646         do
1647         {
1648             if (flist == dir->file_list)
1649                 goto done;
1650 
1651             fe = flist->data;
1652             flist = flist->next;
1653         }
1654         while (!S_ISLNK (fe->s.st_mode));
1655 
1656         while (TRUE)
1657         {
1658             if (fgets (buffer, sizeof (buffer), fp) == NULL)
1659                 goto done;
1660 
1661             if (me->logfile != NULL)
1662             {
1663                 fputs (buffer, me->logfile);
1664                 fflush (me->logfile);
1665             }
1666 
1667             vfs_die ("This code should be commented out\n");
1668 
1669             if (vfs_parse_ls_lga (buffer, &s, &filename, NULL))
1670             {
1671                 int r;
1672 
1673                 r = strcmp (fe->name, filename);
1674                 g_free (filename);
1675                 if (r == 0)
1676                 {
1677                     if (S_ISLNK (s.st_mode))
1678                     {
1679                         /* This server doesn't understand LIST -lLa */
1680                         switch_method = 1;
1681                         goto done;
1682                     }
1683 
1684                     fe->l_stat = g_try_new (struct stat, 1);
1685                     if (fe->l_stat == NULL)
1686                         goto done;
1687 
1688                     *fe->l_stat = s;
1689                     (*fe->l_stat).st_ino = bucket->__inode_counter++;
1690                     break;
1691                 }
1692 
1693                 if (r < 0)
1694                     break;
1695             }
1696         }
1697     }
1698 
1699   done:
1700     while (fgets (buffer, sizeof (buffer), fp) != NULL)
1701         ;
1702     tty_disable_interrupt_key ();
1703     fclose (fp);
1704     ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0);
1705 }
1706 
1707 /* --------------------------------------------------------------------------------------------- */
1708 
1709 static void
1710 resolve_symlink (struct vfs_class *me, struct vfs_s_super *super, struct vfs_s_inode *dir)
     /* [previous][next][first][last][top][bottom][index][help]  */
1711 {
1712     vfs_print_message ("%s", _("Resolving symlink..."));
1713 
1714     if (FTP_SUPER (super)->strict_rfc959_list_cmd)
1715         resolve_symlink_without_ls_options (me, super, dir);
1716     else
1717         resolve_symlink_with_ls_options (me, super, dir);
1718 }
1719 #endif
1720 
1721 /* --------------------------------------------------------------------------------------------- */
1722 
1723 static int
1724 ftpfs_dir_load (struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
     /* [previous][next][first][last][top][bottom][index][help]  */
1725 {
1726     struct vfs_s_entry *ent;
1727     struct vfs_s_super *super = dir->super;
1728     ftp_super_t *ftp_super = FTP_SUPER (super);
1729     int sock, num_entries = 0;
1730     gboolean cd_first;
1731 
1732     cd_first = ftpfs_first_cd_then_ls || (ftp_super->strict == RFC_STRICT)
1733         || (strchr (remote_path, ' ') != NULL);
1734 
1735   again:
1736     vfs_print_message (_("ftpfs: Reading FTP directory %s... %s%s"),
1737                        remote_path,
1738                        ftp_super->strict ==
1739                        RFC_STRICT ? _("(strict rfc959)") : "", cd_first ? _("(chdir first)") : "");
1740 
1741     if (cd_first && ftpfs_chdir_internal (me, super, remote_path) != COMPLETE)
1742     {
1743         ftpfs_errno = ENOENT;
1744         vfs_print_message ("%s", _("ftpfs: CWD failed."));
1745         return (-1);
1746     }
1747 
1748     gettimeofday (&dir->timestamp, NULL);
1749     dir->timestamp.tv_sec += ftpfs_directory_timeout;
1750 
1751     if (ftp_super->strict == RFC_STRICT)
1752         sock = ftpfs_open_data_connection (me, super, "LIST", 0, TYPE_ASCII, 0);
1753     else if (cd_first)
1754         /* Dirty hack to avoid autoprepending / to . */
1755         /* Wu-ftpd produces strange output for '/' if 'LIST -la .' used */
1756         sock = ftpfs_open_data_connection (me, super, "LIST -la", 0, TYPE_ASCII, 0);
1757     else
1758     {
1759         char *path;
1760 
1761         /* Trailing "/." is necessary if remote_path is a symlink */
1762         path = mc_build_filename (remote_path, ".", (char *) NULL);
1763         sock = ftpfs_open_data_connection (me, super, "LIST -la", path, TYPE_ASCII, 0);
1764         g_free (path);
1765     }
1766 
1767     if (sock == -1)
1768     {
1769       fallback:
1770         if (ftp_super->strict == RFC_AUTODETECT)
1771         {
1772             /* It's our first attempt to get a directory listing from this
1773                server (UNIX style LIST command) */
1774             ftp_super->strict = RFC_STRICT;
1775             /* I hate goto, but recursive call needs another 8K on stack */
1776             /* return ftpfs_dir_load (me, dir, remote_path); */
1777             cd_first = TRUE;
1778             goto again;
1779         }
1780 
1781         vfs_print_message ("%s", _("ftpfs: failed; nowhere to fallback to"));
1782         ERRNOR (EACCES, -1);
1783     }
1784 
1785     vfs_parse_ls_lga_init ();
1786 
1787     while (TRUE)
1788     {
1789         int i;
1790         size_t count_spaces = 0;
1791         int res;
1792         char lc_buffer[BUF_8K] = "\0";
1793 
1794         res = vfs_s_get_line_interruptible (me, lc_buffer, sizeof (lc_buffer), sock);
1795         if (res == 0)
1796             break;
1797 
1798         if (res == EINTR)
1799         {
1800             me->verrno = ECONNRESET;
1801             close (sock);
1802             ftp_super->ctl_connection_busy = FALSE;
1803             ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1804             vfs_print_message (_("%s: failure"), me->name);
1805             return (-1);
1806         }
1807 
1808         if (me->logfile != NULL)
1809         {
1810             fputs (lc_buffer, me->logfile);
1811             fputs ("\n", me->logfile);
1812             fflush (me->logfile);
1813         }
1814 
1815         ent = vfs_s_generate_entry (me, NULL, dir, 0);
1816         i = ent->ino->st.st_nlink;
1817 
1818         if (!vfs_parse_ls_lga
1819             (lc_buffer, &ent->ino->st, &ent->name, &ent->ino->linkname, &count_spaces))
1820             vfs_s_free_entry (me, ent);
1821         else
1822         {
1823             ent->ino->st.st_nlink = i;  /* Ouch, we need to preserve our counts :-( */
1824             num_entries++;
1825             vfs_s_store_filename_leading_spaces (ent, count_spaces);
1826             vfs_s_insert_entry (me, dir, ent);
1827         }
1828     }
1829 
1830     close (sock);
1831     ftp_super->ctl_connection_busy = FALSE;
1832     me->verrno = E_REMOTE;
1833     if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE))
1834         goto fallback;
1835 
1836     if (num_entries == 0 && !cd_first)
1837     {
1838         /* The LIST command may produce an empty output. In such scenario
1839            it is not clear whether this is caused by  'remote_path' being
1840            a non-existent path or for some other reason (listing emtpy
1841            directory without the -a option, non-readable directory, etc.).
1842 
1843            Since 'dir_load' is a crucial method, when it comes to determine
1844            whether a given path is a _directory_, the code must try its best
1845            to determine the type of 'remote_path'. The only reliable way to
1846            achieve this is trough issuing a CWD command. */
1847 
1848         cd_first = TRUE;
1849         goto again;
1850     }
1851 
1852     vfs_s_normalize_filename_leading_spaces (dir, vfs_parse_ls_lga_get_final_spaces ());
1853 
1854     if (ftp_super->strict == RFC_AUTODETECT)
1855         ftp_super->strict = RFC_DARING;
1856 
1857     vfs_print_message (_("%s: done."), me->name);
1858     return 0;
1859 }
1860 
1861 /* --------------------------------------------------------------------------------------------- */
1862 
1863 static int
1864 ftpfs_file_store (struct vfs_class *me, vfs_file_handler_t * fh, char *name, char *localname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1865 {
1866     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1867     ftp_super_t *ftp_super = FTP_SUPER (super);
1868     ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
1869 
1870     int h, sock;
1871     off_t n_stored = 0;
1872 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1873     struct linger li;
1874 #else
1875     int flag_one = 1;
1876 #endif
1877     char lc_buffer[BUF_8K];
1878     struct stat s;
1879     char *w_buf;
1880 
1881     h = open (localname, O_RDONLY);
1882     if (h == -1)
1883         ERRNOR (EIO, -1);
1884 
1885     if (fstat (h, &s) == -1)
1886     {
1887         close (h);
1888         return (-1);
1889     }
1890 
1891     sock =
1892         ftpfs_open_data_connection (me, super, ftp->append ? "APPE" : "STOR", name, TYPE_BINARY, 0);
1893     if (sock < 0)
1894     {
1895         close (h);
1896         return (-1);
1897     }
1898 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1899     li.l_onoff = 1;
1900     li.l_linger = 120;
1901     setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (li));
1902 #else
1903     setsockopt (sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
1904 #endif
1905 
1906     tty_enable_interrupt_key ();
1907     while (TRUE)
1908     {
1909         ssize_t n_read, n_written;
1910 
1911         while ((n_read = read (h, lc_buffer, sizeof (lc_buffer))) == -1)
1912         {
1913             if (errno != EINTR)
1914             {
1915                 ftpfs_errno = errno;
1916                 goto error_return;
1917             }
1918             if (tty_got_interrupt ())
1919             {
1920                 ftpfs_errno = EINTR;
1921                 goto error_return;
1922             }
1923         }
1924         if (n_read == 0)
1925             break;
1926 
1927         n_stored += n_read;
1928         w_buf = lc_buffer;
1929 
1930         while ((n_written = write (sock, w_buf, n_read)) != n_read)
1931         {
1932             if (n_written == -1)
1933             {
1934                 if (errno == EINTR && !tty_got_interrupt ())
1935                     continue;
1936 
1937                 ftpfs_errno = errno;
1938                 goto error_return;
1939             }
1940 
1941             w_buf += n_written;
1942             n_read -= n_written;
1943         }
1944 
1945         vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX,
1946                            _("ftpfs: storing file"), (uintmax_t) n_stored, (uintmax_t) s.st_size);
1947     }
1948     tty_disable_interrupt_key ();
1949 
1950     close (sock);
1951     ftp_super->ctl_connection_busy = FALSE;
1952     close (h);
1953 
1954     if (ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE)
1955         ERRNOR (EIO, -1);
1956     return 0;
1957 
1958   error_return:
1959     tty_disable_interrupt_key ();
1960     close (sock);
1961     ftp_super->ctl_connection_busy = FALSE;
1962     close (h);
1963 
1964     ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1965     return (-1);
1966 }
1967 
1968 /* --------------------------------------------------------------------------------------------- */
1969 
1970 static int
1971 ftpfs_linear_start (struct vfs_class *me, vfs_file_handler_t * fh, off_t offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
1972 {
1973     char *name;
1974 
1975     name = vfs_s_fullpath (me, fh->ino);
1976     if (name == NULL)
1977         return 0;
1978 
1979     FH_SOCK =
1980         ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh), "RETR", name, TYPE_BINARY,
1981                                     offset);
1982     g_free (name);
1983     if (FH_SOCK == -1)
1984         ERRNOR (EACCES, 0);
1985 
1986     fh->linear = LS_LINEAR_OPEN;
1987     FTP_FILE_HANDLER (fh)->append = FALSE;
1988     return 1;
1989 }
1990 
1991 /* --------------------------------------------------------------------------------------------- */
1992 
1993 static ssize_t
1994 ftpfs_linear_read (struct vfs_class *me, vfs_file_handler_t * fh, void *buf, size_t len)
     /* [previous][next][first][last][top][bottom][index][help]  */
1995 {
1996     ssize_t n;
1997     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1998 
1999     while ((n = read (FH_SOCK, buf, len)) < 0)
2000     {
2001         if ((errno == EINTR) && !tty_got_interrupt ())
2002             continue;
2003         break;
2004     }
2005 
2006     if (n < 0)
2007         ftpfs_linear_abort (me, fh);
2008     else if (n == 0)
2009     {
2010         FTP_SUPER (super)->ctl_connection_busy = FALSE;
2011         close (FH_SOCK);
2012         FH_SOCK = -1;
2013         if ((ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0) != COMPLETE))
2014             ERRNOR (E_REMOTE, -1);
2015         return 0;
2016     }
2017 
2018     ERRNOR (errno, n);
2019 }
2020 
2021 /* --------------------------------------------------------------------------------------------- */
2022 
2023 static void
2024 ftpfs_linear_close (struct vfs_class *me, vfs_file_handler_t * fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
2025 {
2026     if (FH_SOCK != -1)
2027         ftpfs_linear_abort (me, fh);
2028 }
2029 
2030 /* --------------------------------------------------------------------------------------------- */
2031 
2032 static int
2033 ftpfs_ctl (void *fh, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
2034 {
2035     (void) arg;
2036 
2037     switch (ctlop)
2038     {
2039     case VFS_CTL_IS_NOTREADY:
2040         {
2041             vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
2042             int v;
2043 
2044             if (file->linear == LS_NOT_LINEAR)
2045                 vfs_die ("You may not do this");
2046             if (file->linear == LS_LINEAR_CLOSED || file->linear == LS_LINEAR_PREOPEN)
2047                 return 0;
2048 
2049             v = vfs_s_select_on_two (FH_SOCK, 0);
2050             return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
2051         }
2052     default:
2053         return 0;
2054     }
2055 }
2056 
2057 /* --------------------------------------------------------------------------------------------- */
2058 
2059 static int
2060 ftpfs_send_command (const vfs_path_t * vpath, const char *cmd, int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
2061 {
2062     const char *rpath;
2063     char *p;
2064     struct vfs_s_super *super;
2065     int r;
2066     const vfs_path_element_t *path_element;
2067     gboolean flush_directory_cache = (flags & OPT_FLUSH) != 0;
2068 
2069     path_element = vfs_path_get_by_index (vpath, -1);
2070 
2071     rpath = vfs_s_get_path (vpath, &super, 0);
2072     if (rpath == NULL)
2073         return (-1);
2074 
2075     p = ftpfs_translate_path (path_element->class, super, rpath);
2076     r = ftpfs_command (path_element->class, super, WAIT_REPLY, cmd, p);
2077     g_free (p);
2078     vfs_stamp_create (vfs_ftpfs_ops, super);
2079     if ((flags & OPT_IGNORE_ERROR) != 0)
2080         r = COMPLETE;
2081     if (r != COMPLETE)
2082     {
2083         path_element->class->verrno = EPERM;
2084         return (-1);
2085     }
2086     if (flush_directory_cache)
2087         vfs_s_invalidate (path_element->class, super);
2088     return 0;
2089 }
2090 
2091 /* --------------------------------------------------------------------------------------------- */
2092 
2093 static int
2094 ftpfs_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2095 {
2096     int ret;
2097 
2098     ret = vfs_s_stat (vpath, buf);
2099     ftpfs_set_blksize (buf);
2100     return ret;
2101 }
2102 
2103 /* --------------------------------------------------------------------------------------------- */
2104 
2105 static int
2106 ftpfs_lstat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2107 {
2108     int ret;
2109 
2110     ret = vfs_s_lstat (vpath, buf);
2111     ftpfs_set_blksize (buf);
2112     return ret;
2113 }
2114 
2115 /* --------------------------------------------------------------------------------------------- */
2116 
2117 static int
2118 ftpfs_fstat (void *vfs_info, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2119 {
2120     int ret;
2121 
2122     ret = vfs_s_fstat (vfs_info, buf);
2123     ftpfs_set_blksize (buf);
2124     return ret;
2125 }
2126 
2127 /* --------------------------------------------------------------------------------------------- */
2128 
2129 static int
2130 ftpfs_chmod (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2131 {
2132     char buf[BUF_SMALL];
2133     int ret;
2134 
2135     g_snprintf (buf, sizeof (buf), "SITE CHMOD %4.4o /%%s", (unsigned int) (mode & 07777));
2136     ret = ftpfs_send_command (vpath, buf, OPT_FLUSH);
2137     return ftpfs_ignore_chattr_errors ? 0 : ret;
2138 }
2139 
2140 /* --------------------------------------------------------------------------------------------- */
2141 
2142 static int
2143 ftpfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
2144 {
2145 #if 0
2146     (void) vpath;
2147     (void) owner;
2148     (void) group;
2149 
2150     ftpfs_errno = EPERM;
2151     return (-1);
2152 #else
2153     /* Everyone knows it is not possible to chown remotely, so why bother them.
2154        If someone's root, then copy/move will always try to chown it... */
2155     (void) vpath;
2156     (void) owner;
2157     (void) group;
2158     return 0;
2159 #endif
2160 }
2161 
2162 /* --------------------------------------------------------------------------------------------- */
2163 
2164 static int
2165 ftpfs_unlink (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2166 {
2167     return ftpfs_send_command (vpath, "DELE /%s", OPT_FLUSH);
2168 }
2169 
2170 /* --------------------------------------------------------------------------------------------- */
2171 
2172 /* Return TRUE if path is the same directory as the one we are in now */
2173 static gboolean
2174 ftpfs_is_same_dir (struct vfs_class *me, struct vfs_s_super *super, const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
2175 {
2176     (void) me;
2177 
2178     return (FTP_SUPER (super)->current_dir != NULL
2179             && strcmp (path, FTP_SUPER (super)->current_dir) == 0);
2180 }
2181 
2182 /* --------------------------------------------------------------------------------------------- */
2183 
2184 static int
2185 ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
     /* [previous][next][first][last][top][bottom][index][help]  */
2186 {
2187     ftp_super_t *ftp_super = FTP_SUPER (super);
2188     int r;
2189     char *p;
2190 
2191     if (!ftp_super->cwd_deferred && ftpfs_is_same_dir (me, super, remote_path))
2192         return COMPLETE;
2193 
2194     p = ftpfs_translate_path (me, super, remote_path);
2195     r = ftpfs_command (me, super, WAIT_REPLY, "CWD /%s", p);
2196     g_free (p);
2197 
2198     if (r != COMPLETE)
2199         ftpfs_errno = EIO;
2200     else
2201     {
2202         g_free (ftp_super->current_dir);
2203         ftp_super->current_dir = g_strdup (remote_path);
2204         ftp_super->cwd_deferred = FALSE;
2205     }
2206     return r;
2207 }
2208 
2209 /* --------------------------------------------------------------------------------------------- */
2210 
2211 static int
2212 ftpfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
2213 {
2214     ftpfs_send_command (vpath1, "RNFR /%s", OPT_FLUSH);
2215     return ftpfs_send_command (vpath2, "RNTO /%s", OPT_FLUSH);
2216 }
2217 
2218 /* --------------------------------------------------------------------------------------------- */
2219 
2220 static int
2221 ftpfs_mkdir (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2222 {
2223     (void) mode;                /* FIXME: should be used */
2224 
2225     return ftpfs_send_command (vpath, "MKD /%s", OPT_FLUSH);
2226 }
2227 
2228 /* --------------------------------------------------------------------------------------------- */
2229 
2230 static int
2231 ftpfs_rmdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2232 {
2233     return ftpfs_send_command (vpath, "RMD /%s", OPT_FLUSH);
2234 }
2235 
2236 /* --------------------------------------------------------------------------------------------- */
2237 
2238 static vfs_file_handler_t *
2239 ftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
2240 {
2241     ftp_file_handler_t *fh;
2242 
2243     fh = g_new0 (ftp_file_handler_t, 1);
2244     vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed);
2245     fh->sock = -1;
2246 
2247     return VFS_FILE_HANDLER (fh);
2248 }
2249 
2250 /* --------------------------------------------------------------------------------------------- */
2251 
2252 static int
2253 ftpfs_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2254 {
2255     ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
2256 
2257     (void) mode;
2258 
2259     /* File will be written only, so no need to retrieve it from ftp server */
2260     if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
2261     {
2262 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2263         struct linger li;
2264 #else
2265         int li = 1;
2266 #endif
2267         char *name;
2268 
2269         /* ftpfs_linear_start() called, so data will be written
2270          * to local temporary file and stored to ftp server
2271          * by vfs_s_close later
2272          */
2273         if (FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh))->ctl_connection_busy)
2274         {
2275             if (fh->ino->localname == NULL)
2276             {
2277                 vfs_path_t *vpath;
2278                 int handle;
2279 
2280                 handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
2281                 if (handle == -1)
2282                 {
2283                     vfs_path_free (vpath);
2284                     return (-1);
2285                 }
2286                 close (handle);
2287                 fh->ino->localname = g_strdup (vfs_path_as_str (vpath));
2288                 vfs_path_free (vpath);
2289                 ftp->append = (flags & O_APPEND) != 0;
2290             }
2291             return 0;
2292         }
2293         name = vfs_s_fullpath (me, fh->ino);
2294         if (name == NULL)
2295             return (-1);
2296 
2297         fh->handle =
2298             ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh),
2299                                         (flags & O_APPEND) != 0 ? "APPE" : "STOR", name,
2300                                         TYPE_BINARY, 0);
2301         g_free (name);
2302 
2303         if (fh->handle < 0)
2304             return (-1);
2305 
2306 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2307         li.l_onoff = 1;
2308         li.l_linger = 120;
2309 #endif
2310         setsockopt (fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof (li));
2311 
2312         if (fh->ino->localname != NULL)
2313         {
2314             unlink (fh->ino->localname);
2315             MC_PTR_FREE (fh->ino->localname);
2316         }
2317         return 0;
2318     }
2319 
2320     if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
2321         return (-1);
2322 
2323     if (fh->ino->localname == NULL)
2324         vfs_die ("retrieve_file failed to fill in localname");
2325     return 0;
2326 }
2327 
2328 /* --------------------------------------------------------------------------------------------- */
2329 
2330 static int
2331 ftpfs_fh_close (struct vfs_class *me, vfs_file_handler_t * fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
2332 {
2333     if (fh->handle != -1 && fh->ino->localname == NULL)
2334     {
2335         ftp_super_t *ftp = FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
2336 
2337         close (fh->handle);
2338         fh->handle = -1;
2339         ftp->ctl_connection_busy = FALSE;
2340         /* File is stored to destination already, so
2341          * we prevent VFS_SUBCLASS (me)->ftpfs_file_store() call from vfs_s_close ()
2342          */
2343         fh->changed = FALSE;
2344         if (ftpfs_get_reply (me, ftp->sock, NULL, 0) != COMPLETE)
2345             ERRNOR (EIO, -1);
2346         vfs_s_invalidate (me, VFS_FILE_HANDLER_SUPER (fh));
2347     }
2348 
2349     return 0;
2350 }
2351 
2352 /* --------------------------------------------------------------------------------------------- */
2353 
2354 static void
2355 ftpfs_done (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
2356 {
2357     (void) me;
2358 
2359     g_slist_free_full (no_proxy, g_free);
2360 
2361     g_free (ftpfs_anonymous_passwd);
2362     g_free (ftpfs_proxy_host);
2363 }
2364 
2365 /* --------------------------------------------------------------------------------------------- */
2366 
2367 static void
2368 ftpfs_fill_names (struct vfs_class *me, fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
2369 {
2370     GList *iter;
2371 
2372     for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
2373     {
2374         const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
2375         char *name;
2376 
2377         name = vfs_path_element_build_pretty_path_str (super->path_element);
2378 
2379         func (name);
2380         g_free (name);
2381     }
2382 }
2383 
2384 /* --------------------------------------------------------------------------------------------- */
2385 
2386 static keyword_t
2387 ftpfs_netrc_next (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2388 {
2389     char *p;
2390     keyword_t i;
2391     static const char *const keywords[] = { "default", "machine",
2392         "login", "password", "passwd", "account", "macdef", NULL
2393     };
2394 
2395     while (TRUE)
2396     {
2397         netrcp = skip_separators (netrcp);
2398         if (*netrcp != '\n')
2399             break;
2400         netrcp++;
2401     }
2402     if (*netrcp == '\0')
2403         return NETRC_NONE;
2404 
2405     p = buffer;
2406     if (*netrcp == '"')
2407     {
2408         for (netrcp++; *netrcp != '"' && *netrcp != '\0'; netrcp++)
2409         {
2410             if (*netrcp == '\\')
2411                 netrcp++;
2412             *p++ = *netrcp;
2413         }
2414     }
2415     else
2416     {
2417         for (; *netrcp != '\0' && !whiteness (*netrcp) && *netrcp != ','; netrcp++)
2418         {
2419             if (*netrcp == '\\')
2420                 netrcp++;
2421             *p++ = *netrcp;
2422         }
2423     }
2424 
2425     *p = '\0';
2426     if (*buffer == '\0')
2427         return NETRC_NONE;
2428 
2429     for (i = NETRC_DEFAULT; keywords[i - 1] != NULL; i++)
2430         if (strcmp (keywords[i - 1], buffer) == 0)
2431             return i;
2432 
2433     return NETRC_UNKNOWN;
2434 }
2435 
2436 /* --------------------------------------------------------------------------------------------- */
2437 
2438 static gboolean
2439 ftpfs_netrc_bad_mode (const char *netrcname)
     /* [previous][next][first][last][top][bottom][index][help]  */
2440 {
2441     struct stat mystat;
2442 
2443     if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077) != 0)
2444     {
2445         static gboolean be_angry = TRUE;
2446 
2447         if (be_angry)
2448         {
2449             message (D_ERROR, MSG_ERROR,
2450                      _("~/.netrc file has incorrect mode\nRemove password or correct mode"));
2451             be_angry = FALSE;
2452         }
2453         return TRUE;
2454     }
2455 
2456     return FALSE;
2457 }
2458 
2459 /* --------------------------------------------------------------------------------------------- */
2460 /* Scan .netrc until we find matching "machine" or "default"
2461  * domain is used for additional matching
2462  * No search is done after "default" in compliance with "man netrc"
2463  * Return TRUE if found, FALSE otherwise */
2464 
2465 static gboolean
2466 ftpfs_find_machine (const char *host, const char *domain)
     /* [previous][next][first][last][top][bottom][index][help]  */
2467 {
2468     keyword_t keyword;
2469 
2470     if (host == NULL)
2471         host = "";
2472     if (domain == NULL)
2473         domain = "";
2474 
2475     while ((keyword = ftpfs_netrc_next ()) != NETRC_NONE)
2476     {
2477         if (keyword == NETRC_DEFAULT)
2478             return TRUE;
2479 
2480         if (keyword == NETRC_MACDEF)
2481         {
2482             /* Scan for an empty line, which concludes "macdef" */
2483             do
2484             {
2485                 while (*netrcp != '\0' && *netrcp != '\n')
2486                     netrcp++;
2487                 if (*netrcp != '\n')
2488                     break;
2489                 netrcp++;
2490             }
2491             while (*netrcp != '\0' && *netrcp != '\n');
2492 
2493             continue;
2494         }
2495 
2496         if (keyword != NETRC_MACHINE)
2497             continue;
2498 
2499         /* Take machine name */
2500         if (ftpfs_netrc_next () == NETRC_NONE)
2501             break;
2502 
2503         if (g_ascii_strcasecmp (host, buffer) != 0)
2504         {
2505             const char *host_domain;
2506 
2507             /* Try adding our domain to short names in .netrc */
2508             host_domain = strchr (host, '.');
2509             if (host_domain == NULL)
2510                 continue;
2511 
2512             /* Compare domain part */
2513             if (g_ascii_strcasecmp (host_domain, domain) != 0)
2514                 continue;
2515 
2516             /* Compare local part */
2517             if (g_ascii_strncasecmp (host, buffer, host_domain - host) != 0)
2518                 continue;
2519         }
2520 
2521         return TRUE;
2522     }
2523 
2524     /* end of .netrc */
2525     return FALSE;
2526 }
2527 
2528 /* --------------------------------------------------------------------------------------------- */
2529 /* Extract login and password from .netrc for the host.
2530  * pass may be NULL.
2531  * Returns TRUE for success, FALSE for error */
2532 
2533 static gboolean
2534 ftpfs_netrc_lookup (const char *host, char **login, char **pass)
     /* [previous][next][first][last][top][bottom][index][help]  */
2535 {
2536     char *netrcname;
2537     char *tmp_pass = NULL;
2538     char hostname[MAXHOSTNAMELEN];
2539     const char *domain;
2540     static struct rupcache
2541     {
2542         struct rupcache *next;
2543         char *host;
2544         char *login;
2545         char *pass;
2546     } *rup_cache = NULL, *rupp;
2547 
2548     /* Initialize *login and *pass */
2549     MC_PTR_FREE (*login);
2550     MC_PTR_FREE (*pass);
2551 
2552     /* Look up in the cache first */
2553     for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
2554         if (strcmp (host, rupp->host) == 0)
2555         {
2556             *login = g_strdup (rupp->login);
2557             *pass = g_strdup (rupp->pass);
2558             return TRUE;
2559         }
2560 
2561     /* Load current .netrc */
2562     netrcname = g_build_filename (mc_config_get_home_dir (), ".netrc", (char *) NULL);
2563     if (!g_file_get_contents (netrcname, &netrc, NULL, NULL))
2564     {
2565         g_free (netrcname);
2566         return TRUE;
2567     }
2568 
2569     netrcp = netrc;
2570 
2571     /* Find our own domain name */
2572     if (gethostname (hostname, sizeof (hostname)) < 0)
2573         *hostname = '\0';
2574 
2575     domain = strchr (hostname, '.');
2576     if (domain == NULL)
2577         domain = "";
2578 
2579     /* Scan for "default" and matching "machine" keywords */
2580     ftpfs_find_machine (host, domain);
2581 
2582     /* Scan for keywords following "default" and "machine" */
2583     while (TRUE)
2584     {
2585         keyword_t keyword;
2586 
2587         gboolean need_break = FALSE;
2588         keyword = ftpfs_netrc_next ();
2589 
2590         switch (keyword)
2591         {
2592         case NETRC_LOGIN:
2593             if (ftpfs_netrc_next () == NETRC_NONE)
2594             {
2595                 need_break = TRUE;
2596                 break;
2597             }
2598 
2599             /* We have another name already - should not happen */
2600             if (*login != NULL)
2601             {
2602                 need_break = TRUE;
2603                 break;
2604             }
2605 
2606             /* We have login name now */
2607             *login = g_strdup (buffer);
2608             break;
2609 
2610         case NETRC_PASSWORD:
2611         case NETRC_PASSWD:
2612             if (ftpfs_netrc_next () == NETRC_NONE)
2613             {
2614                 need_break = TRUE;
2615                 break;
2616             }
2617 
2618             /* Ignore unsafe passwords */
2619             if (*login != NULL &&
2620                 strcmp (*login, "anonymous") != 0 && strcmp (*login, "ftp") != 0
2621                 && ftpfs_netrc_bad_mode (netrcname))
2622             {
2623                 need_break = TRUE;
2624                 break;
2625             }
2626 
2627             /* Remember password.  pass may be NULL, so use tmp_pass */
2628             if (tmp_pass == NULL)
2629                 tmp_pass = g_strdup (buffer);
2630             break;
2631 
2632         case NETRC_ACCOUNT:
2633             /* "account" is followed by a token which we ignore */
2634             if (ftpfs_netrc_next () == NETRC_NONE)
2635             {
2636                 need_break = TRUE;
2637                 break;
2638             }
2639 
2640             /* Ignore account, but warn user anyways */
2641             ftpfs_netrc_bad_mode (netrcname);
2642             break;
2643 
2644         default:
2645             /* Unexpected keyword or end of file */
2646             need_break = TRUE;
2647             break;
2648         }
2649 
2650         if (need_break)
2651             break;
2652     }
2653 
2654     MC_PTR_FREE (netrc);
2655     g_free (netrcname);
2656 
2657     rupp = g_new (struct rupcache, 1);
2658     rupp->host = g_strdup (host);
2659     rupp->login = g_strdup (*login);
2660     rupp->pass = g_strdup (tmp_pass);
2661 
2662     rupp->next = rup_cache;
2663     rup_cache = rupp;
2664 
2665     *pass = tmp_pass;
2666 
2667     return TRUE;
2668 }
2669 
2670 /* --------------------------------------------------------------------------------------------- */
2671 /*** public functions ****************************************************************************/
2672 /* --------------------------------------------------------------------------------------------- */
2673 
2674 /** This routine is called as the last step in load_setup */
2675 void
2676 ftpfs_init_passwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2677 {
2678     ftpfs_anonymous_passwd = load_anon_passwd ();
2679 
2680     if (ftpfs_anonymous_passwd == NULL)
2681     {
2682         /* If there is no anonymous ftp password specified
2683          * then we'll just use anonymous@
2684          * We don't send any other thing because:
2685          * - We want to remain anonymous
2686          * - We want to stop SPAM
2687          * - We don't want to let ftp sites to discriminate by the user,
2688          *   host or country.
2689          */
2690         ftpfs_anonymous_passwd = g_strdup ("anonymous@");
2691     }
2692 }
2693 
2694 /* --------------------------------------------------------------------------------------------- */
2695 
2696 void
2697 vfs_init_ftpfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2698 {
2699     tcp_init ();
2700 
2701     vfs_init_subclass (&ftpfs_subclass, "ftpfs", VFS_NOLINKS | VFS_REMOTE | VFS_USETMP, "ftp");
2702     vfs_ftpfs_ops->done = ftpfs_done;
2703     vfs_ftpfs_ops->fill_names = ftpfs_fill_names;
2704     vfs_ftpfs_ops->stat = ftpfs_stat;
2705     vfs_ftpfs_ops->lstat = ftpfs_lstat;
2706     vfs_ftpfs_ops->fstat = ftpfs_fstat;
2707     vfs_ftpfs_ops->chmod = ftpfs_chmod;
2708     vfs_ftpfs_ops->chown = ftpfs_chown;
2709     vfs_ftpfs_ops->unlink = ftpfs_unlink;
2710     vfs_ftpfs_ops->rename = ftpfs_rename;
2711     vfs_ftpfs_ops->mkdir = ftpfs_mkdir;
2712     vfs_ftpfs_ops->rmdir = ftpfs_rmdir;
2713     vfs_ftpfs_ops->ctl = ftpfs_ctl;
2714     ftpfs_subclass.archive_same = ftpfs_archive_same;
2715     ftpfs_subclass.new_archive = ftpfs_new_archive;
2716     ftpfs_subclass.open_archive = ftpfs_open_archive;
2717     ftpfs_subclass.free_archive = ftpfs_free_archive;
2718     ftpfs_subclass.fh_new = ftpfs_fh_new;
2719     ftpfs_subclass.fh_open = ftpfs_fh_open;
2720     ftpfs_subclass.fh_close = ftpfs_fh_close;
2721     ftpfs_subclass.dir_load = ftpfs_dir_load;
2722     ftpfs_subclass.file_store = ftpfs_file_store;
2723     ftpfs_subclass.linear_start = ftpfs_linear_start;
2724     ftpfs_subclass.linear_read = ftpfs_linear_read;
2725     ftpfs_subclass.linear_close = ftpfs_linear_close;
2726     vfs_register_class (vfs_ftpfs_ops);
2727 }
2728 
2729 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */