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         goto fallback;
1769 
1770     /* Clear the interrupt flag */
1771     tty_enable_interrupt_key ();
1772 
1773     vfs_parse_ls_lga_init ();
1774     while (TRUE)
1775     {
1776         int i;
1777         size_t count_spaces = 0;
1778         int res;
1779         char lc_buffer[BUF_8K] = "\0";
1780 
1781         res = vfs_s_get_line_interruptible (me, lc_buffer, sizeof (lc_buffer), sock);
1782         if (res == 0)
1783             break;
1784 
1785         if (res == EINTR)
1786         {
1787             me->verrno = ECONNRESET;
1788             close (sock);
1789             ftp_super->ctl_connection_busy = FALSE;
1790             tty_disable_interrupt_key ();
1791             ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1792             vfs_print_message (_("%s: failure"), me->name);
1793             return (-1);
1794         }
1795 
1796         if (me->logfile != NULL)
1797         {
1798             fputs (lc_buffer, me->logfile);
1799             fputs ("\n", me->logfile);
1800             fflush (me->logfile);
1801         }
1802 
1803         ent = vfs_s_generate_entry (me, NULL, dir, 0);
1804         i = ent->ino->st.st_nlink;
1805 
1806         if (!vfs_parse_ls_lga
1807             (lc_buffer, &ent->ino->st, &ent->name, &ent->ino->linkname, &count_spaces))
1808             vfs_s_free_entry (me, ent);
1809         else
1810         {
1811             ent->ino->st.st_nlink = i;  /* Ouch, we need to preserve our counts :-( */
1812             num_entries++;
1813             vfs_s_store_filename_leading_spaces (ent, count_spaces);
1814             vfs_s_insert_entry (me, dir, ent);
1815         }
1816     }
1817 
1818     close (sock);
1819     ftp_super->ctl_connection_busy = FALSE;
1820     me->verrno = E_REMOTE;
1821     if ((ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE))
1822         goto fallback;
1823 
1824     if (num_entries == 0 && !cd_first)
1825     {
1826         /* The LIST command may produce an empty output. In such scenario
1827            it is not clear whether this is caused by  'remote_path' being
1828            a non-existent path or for some other reason (listing emtpy
1829            directory without the -a option, non-readable directory, etc.).
1830 
1831            Since 'dir_load' is a crucial method, when it comes to determine
1832            whether a given path is a _directory_, the code must try its best
1833            to determine the type of 'remote_path'. The only reliable way to
1834            achieve this is trough issuing a CWD command. */
1835 
1836         cd_first = TRUE;
1837         goto again;
1838     }
1839 
1840     vfs_s_normalize_filename_leading_spaces (dir, vfs_parse_ls_lga_get_final_spaces ());
1841 
1842     if (ftp_super->strict == RFC_AUTODETECT)
1843         ftp_super->strict = RFC_DARING;
1844 
1845     vfs_print_message (_("%s: done."), me->name);
1846     return 0;
1847 
1848   fallback:
1849     if (ftp_super->strict == RFC_AUTODETECT)
1850     {
1851         /* It's our first attempt to get a directory listing from this
1852            server (UNIX style LIST command) */
1853         ftp_super->strict = RFC_STRICT;
1854         /* I hate goto, but recursive call needs another 8K on stack */
1855         /* return ftpfs_dir_load (me, dir, remote_path); */
1856         cd_first = TRUE;
1857         goto again;
1858     }
1859 
1860     vfs_print_message ("%s", _("ftpfs: failed; nowhere to fallback to"));
1861     ERRNOR (EACCES, -1);
1862 }
1863 
1864 /* --------------------------------------------------------------------------------------------- */
1865 
1866 static int
1867 ftpfs_file_store (struct vfs_class *me, vfs_file_handler_t * fh, char *name, char *localname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1868 {
1869     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
1870     ftp_super_t *ftp_super = FTP_SUPER (super);
1871     ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
1872 
1873     int h, sock;
1874     off_t n_stored = 0;
1875 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1876     struct linger li;
1877 #else
1878     int flag_one = 1;
1879 #endif
1880     char lc_buffer[BUF_8K];
1881     struct stat s;
1882     char *w_buf;
1883 
1884     h = open (localname, O_RDONLY);
1885     if (h == -1)
1886         ERRNOR (EIO, -1);
1887 
1888     if (fstat (h, &s) == -1)
1889     {
1890         close (h);
1891         return (-1);
1892     }
1893 
1894     sock =
1895         ftpfs_open_data_connection (me, super, ftp->append ? "APPE" : "STOR", name, TYPE_BINARY, 0);
1896     if (sock < 0)
1897     {
1898         close (h);
1899         return (-1);
1900     }
1901 #ifdef HAVE_STRUCT_LINGER_L_LINGER
1902     li.l_onoff = 1;
1903     li.l_linger = 120;
1904     setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof (li));
1905 #else
1906     setsockopt (sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
1907 #endif
1908 
1909     tty_enable_interrupt_key ();
1910     while (TRUE)
1911     {
1912         ssize_t n_read, n_written;
1913 
1914         while ((n_read = read (h, lc_buffer, sizeof (lc_buffer))) == -1)
1915         {
1916             if (errno != EINTR)
1917             {
1918                 ftpfs_errno = errno;
1919                 goto error_return;
1920             }
1921             if (tty_got_interrupt ())
1922             {
1923                 ftpfs_errno = EINTR;
1924                 goto error_return;
1925             }
1926         }
1927         if (n_read == 0)
1928             break;
1929 
1930         n_stored += n_read;
1931         w_buf = lc_buffer;
1932 
1933         while ((n_written = write (sock, w_buf, n_read)) != n_read)
1934         {
1935             if (n_written == -1)
1936             {
1937                 if (errno == EINTR && !tty_got_interrupt ())
1938                     continue;
1939 
1940                 ftpfs_errno = errno;
1941                 goto error_return;
1942             }
1943 
1944             w_buf += n_written;
1945             n_read -= n_written;
1946         }
1947 
1948         vfs_print_message ("%s: %" PRIuMAX "/%" PRIuMAX,
1949                            _("ftpfs: storing file"), (uintmax_t) n_stored, (uintmax_t) s.st_size);
1950     }
1951     tty_disable_interrupt_key ();
1952 
1953     close (sock);
1954     ftp_super->ctl_connection_busy = FALSE;
1955     close (h);
1956 
1957     if (ftpfs_get_reply (me, ftp_super->sock, NULL, 0) != COMPLETE)
1958         ERRNOR (EIO, -1);
1959     return 0;
1960 
1961   error_return:
1962     tty_disable_interrupt_key ();
1963     close (sock);
1964     ftp_super->ctl_connection_busy = FALSE;
1965     close (h);
1966 
1967     ftpfs_get_reply (me, ftp_super->sock, NULL, 0);
1968     return (-1);
1969 }
1970 
1971 /* --------------------------------------------------------------------------------------------- */
1972 
1973 static int
1974 ftpfs_linear_start (struct vfs_class *me, vfs_file_handler_t * fh, off_t offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
1975 {
1976     char *name;
1977 
1978     name = vfs_s_fullpath (me, fh->ino);
1979     if (name == NULL)
1980         return 0;
1981 
1982     FH_SOCK =
1983         ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh), "RETR", name, TYPE_BINARY,
1984                                     offset);
1985     g_free (name);
1986     if (FH_SOCK == -1)
1987         ERRNOR (EACCES, 0);
1988 
1989     fh->linear = LS_LINEAR_OPEN;
1990     FTP_FILE_HANDLER (fh)->append = FALSE;
1991     return 1;
1992 }
1993 
1994 /* --------------------------------------------------------------------------------------------- */
1995 
1996 static ssize_t
1997 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]  */
1998 {
1999     ssize_t n;
2000     struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
2001 
2002     while ((n = read (FH_SOCK, buf, len)) < 0)
2003     {
2004         if ((errno == EINTR) && !tty_got_interrupt ())
2005             continue;
2006         break;
2007     }
2008 
2009     if (n < 0)
2010         ftpfs_linear_abort (me, fh);
2011     else if (n == 0)
2012     {
2013         FTP_SUPER (super)->ctl_connection_busy = FALSE;
2014         close (FH_SOCK);
2015         FH_SOCK = -1;
2016         if ((ftpfs_get_reply (me, FTP_SUPER (super)->sock, NULL, 0) != COMPLETE))
2017             ERRNOR (E_REMOTE, -1);
2018         return 0;
2019     }
2020 
2021     ERRNOR (errno, n);
2022 }
2023 
2024 /* --------------------------------------------------------------------------------------------- */
2025 
2026 static void
2027 ftpfs_linear_close (struct vfs_class *me, vfs_file_handler_t * fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
2028 {
2029     if (FH_SOCK != -1)
2030         ftpfs_linear_abort (me, fh);
2031 }
2032 
2033 /* --------------------------------------------------------------------------------------------- */
2034 
2035 static int
2036 ftpfs_ctl (void *fh, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
2037 {
2038     (void) arg;
2039 
2040     switch (ctlop)
2041     {
2042     case VFS_CTL_IS_NOTREADY:
2043         {
2044             vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
2045             int v;
2046 
2047             if (file->linear == LS_NOT_LINEAR)
2048                 vfs_die ("You may not do this");
2049             if (file->linear == LS_LINEAR_CLOSED || file->linear == LS_LINEAR_PREOPEN)
2050                 return 0;
2051 
2052             v = vfs_s_select_on_two (FH_SOCK, 0);
2053             return (((v < 0) && (errno == EINTR)) || v == 0) ? 1 : 0;
2054         }
2055     default:
2056         return 0;
2057     }
2058 }
2059 
2060 /* --------------------------------------------------------------------------------------------- */
2061 
2062 static int
2063 ftpfs_send_command (const vfs_path_t * vpath, const char *cmd, int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
2064 {
2065     const char *rpath;
2066     char *p;
2067     struct vfs_s_super *super;
2068     int r;
2069     const vfs_path_element_t *path_element;
2070     gboolean flush_directory_cache = (flags & OPT_FLUSH) != 0;
2071 
2072     path_element = vfs_path_get_by_index (vpath, -1);
2073 
2074     rpath = vfs_s_get_path (vpath, &super, 0);
2075     if (rpath == NULL)
2076         return (-1);
2077 
2078     p = ftpfs_translate_path (path_element->class, super, rpath);
2079     r = ftpfs_command (path_element->class, super, WAIT_REPLY, cmd, p);
2080     g_free (p);
2081     vfs_stamp_create (vfs_ftpfs_ops, super);
2082     if ((flags & OPT_IGNORE_ERROR) != 0)
2083         r = COMPLETE;
2084     if (r != COMPLETE)
2085     {
2086         path_element->class->verrno = EPERM;
2087         return (-1);
2088     }
2089     if (flush_directory_cache)
2090         vfs_s_invalidate (path_element->class, super);
2091     return 0;
2092 }
2093 
2094 /* --------------------------------------------------------------------------------------------- */
2095 
2096 static int
2097 ftpfs_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2098 {
2099     int ret;
2100 
2101     ret = vfs_s_stat (vpath, buf);
2102     ftpfs_set_blksize (buf);
2103     return ret;
2104 }
2105 
2106 /* --------------------------------------------------------------------------------------------- */
2107 
2108 static int
2109 ftpfs_lstat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2110 {
2111     int ret;
2112 
2113     ret = vfs_s_lstat (vpath, buf);
2114     ftpfs_set_blksize (buf);
2115     return ret;
2116 }
2117 
2118 /* --------------------------------------------------------------------------------------------- */
2119 
2120 static int
2121 ftpfs_fstat (void *vfs_info, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
2122 {
2123     int ret;
2124 
2125     ret = vfs_s_fstat (vfs_info, buf);
2126     ftpfs_set_blksize (buf);
2127     return ret;
2128 }
2129 
2130 /* --------------------------------------------------------------------------------------------- */
2131 
2132 static int
2133 ftpfs_chmod (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2134 {
2135     char buf[BUF_SMALL];
2136     int ret;
2137 
2138     g_snprintf (buf, sizeof (buf), "SITE CHMOD %4.4o /%%s", (unsigned int) (mode & 07777));
2139     ret = ftpfs_send_command (vpath, buf, OPT_FLUSH);
2140     return ftpfs_ignore_chattr_errors ? 0 : ret;
2141 }
2142 
2143 /* --------------------------------------------------------------------------------------------- */
2144 
2145 static int
2146 ftpfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
2147 {
2148 #if 0
2149     (void) vpath;
2150     (void) owner;
2151     (void) group;
2152 
2153     ftpfs_errno = EPERM;
2154     return (-1);
2155 #else
2156     /* Everyone knows it is not possible to chown remotely, so why bother them.
2157        If someone's root, then copy/move will always try to chown it... */
2158     (void) vpath;
2159     (void) owner;
2160     (void) group;
2161     return 0;
2162 #endif
2163 }
2164 
2165 /* --------------------------------------------------------------------------------------------- */
2166 
2167 static int
2168 ftpfs_unlink (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2169 {
2170     return ftpfs_send_command (vpath, "DELE /%s", OPT_FLUSH);
2171 }
2172 
2173 /* --------------------------------------------------------------------------------------------- */
2174 
2175 /* Return TRUE if path is the same directory as the one we are in now */
2176 static gboolean
2177 ftpfs_is_same_dir (struct vfs_class *me, struct vfs_s_super *super, const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
2178 {
2179     (void) me;
2180 
2181     return (FTP_SUPER (super)->current_dir != NULL
2182             && strcmp (path, FTP_SUPER (super)->current_dir) == 0);
2183 }
2184 
2185 /* --------------------------------------------------------------------------------------------- */
2186 
2187 static int
2188 ftpfs_chdir_internal (struct vfs_class *me, struct vfs_s_super *super, const char *remote_path)
     /* [previous][next][first][last][top][bottom][index][help]  */
2189 {
2190     ftp_super_t *ftp_super = FTP_SUPER (super);
2191     int r;
2192     char *p;
2193 
2194     if (!ftp_super->cwd_deferred && ftpfs_is_same_dir (me, super, remote_path))
2195         return COMPLETE;
2196 
2197     p = ftpfs_translate_path (me, super, remote_path);
2198     r = ftpfs_command (me, super, WAIT_REPLY, "CWD /%s", p);
2199     g_free (p);
2200 
2201     if (r != COMPLETE)
2202         ftpfs_errno = EIO;
2203     else
2204     {
2205         g_free (ftp_super->current_dir);
2206         ftp_super->current_dir = g_strdup (remote_path);
2207         ftp_super->cwd_deferred = FALSE;
2208     }
2209     return r;
2210 }
2211 
2212 /* --------------------------------------------------------------------------------------------- */
2213 
2214 static int
2215 ftpfs_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
2216 {
2217     ftpfs_send_command (vpath1, "RNFR /%s", OPT_FLUSH);
2218     return ftpfs_send_command (vpath2, "RNTO /%s", OPT_FLUSH);
2219 }
2220 
2221 /* --------------------------------------------------------------------------------------------- */
2222 
2223 static int
2224 ftpfs_mkdir (const vfs_path_t * vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
2225 {
2226     (void) mode;                /* FIXME: should be used */
2227 
2228     return ftpfs_send_command (vpath, "MKD /%s", OPT_FLUSH);
2229 }
2230 
2231 /* --------------------------------------------------------------------------------------------- */
2232 
2233 static int
2234 ftpfs_rmdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
2235 {
2236     return ftpfs_send_command (vpath, "RMD /%s", OPT_FLUSH);
2237 }
2238 
2239 /* --------------------------------------------------------------------------------------------- */
2240 
2241 static vfs_file_handler_t *
2242 ftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
2243 {
2244     ftp_file_handler_t *fh;
2245 
2246     fh = g_new0 (ftp_file_handler_t, 1);
2247     vfs_s_init_fh (VFS_FILE_HANDLER (fh), ino, changed);
2248     fh->sock = -1;
2249 
2250     return VFS_FILE_HANDLER (fh);
2251 }
2252 
2253 /* --------------------------------------------------------------------------------------------- */
2254 
2255 static int
2256 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]  */
2257 {
2258     ftp_file_handler_t *ftp = FTP_FILE_HANDLER (fh);
2259 
2260     (void) mode;
2261 
2262     /* File will be written only, so no need to retrieve it from ftp server */
2263     if (((flags & O_WRONLY) == O_WRONLY) && ((flags & (O_RDONLY | O_RDWR)) == 0))
2264     {
2265 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2266         struct linger li;
2267 #else
2268         int li = 1;
2269 #endif
2270         char *name;
2271 
2272         /* ftpfs_linear_start() called, so data will be written
2273          * to local temporary file and stored to ftp server
2274          * by vfs_s_close later
2275          */
2276         if (FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh))->ctl_connection_busy)
2277         {
2278             if (fh->ino->localname == NULL)
2279             {
2280                 vfs_path_t *vpath;
2281                 int handle;
2282 
2283                 handle = vfs_mkstemps (&vpath, me->name, fh->ino->ent->name);
2284                 if (handle == -1)
2285                 {
2286                     vfs_path_free (vpath);
2287                     return (-1);
2288                 }
2289                 close (handle);
2290                 fh->ino->localname = g_strdup (vfs_path_as_str (vpath));
2291                 vfs_path_free (vpath);
2292                 ftp->append = (flags & O_APPEND) != 0;
2293             }
2294             return 0;
2295         }
2296         name = vfs_s_fullpath (me, fh->ino);
2297         if (name == NULL)
2298             return (-1);
2299 
2300         fh->handle =
2301             ftpfs_open_data_connection (me, VFS_FILE_HANDLER_SUPER (fh),
2302                                         (flags & O_APPEND) != 0 ? "APPE" : "STOR", name,
2303                                         TYPE_BINARY, 0);
2304         g_free (name);
2305 
2306         if (fh->handle < 0)
2307             return (-1);
2308 
2309 #ifdef HAVE_STRUCT_LINGER_L_LINGER
2310         li.l_onoff = 1;
2311         li.l_linger = 120;
2312 #endif
2313         setsockopt (fh->handle, SOL_SOCKET, SO_LINGER, &li, sizeof (li));
2314 
2315         if (fh->ino->localname != NULL)
2316         {
2317             unlink (fh->ino->localname);
2318             MC_PTR_FREE (fh->ino->localname);
2319         }
2320         return 0;
2321     }
2322 
2323     if (fh->ino->localname == NULL && vfs_s_retrieve_file (me, fh->ino) == -1)
2324         return (-1);
2325 
2326     if (fh->ino->localname == NULL)
2327         vfs_die ("retrieve_file failed to fill in localname");
2328     return 0;
2329 }
2330 
2331 /* --------------------------------------------------------------------------------------------- */
2332 
2333 static int
2334 ftpfs_fh_close (struct vfs_class *me, vfs_file_handler_t * fh)
     /* [previous][next][first][last][top][bottom][index][help]  */
2335 {
2336     if (fh->handle != -1 && fh->ino->localname == NULL)
2337     {
2338         ftp_super_t *ftp = FTP_SUPER (VFS_FILE_HANDLER_SUPER (fh));
2339 
2340         close (fh->handle);
2341         fh->handle = -1;
2342         ftp->ctl_connection_busy = FALSE;
2343         /* File is stored to destination already, so
2344          * we prevent VFS_SUBCLASS (me)->ftpfs_file_store() call from vfs_s_close ()
2345          */
2346         fh->changed = FALSE;
2347         if (ftpfs_get_reply (me, ftp->sock, NULL, 0) != COMPLETE)
2348             ERRNOR (EIO, -1);
2349         vfs_s_invalidate (me, VFS_FILE_HANDLER_SUPER (fh));
2350     }
2351 
2352     return 0;
2353 }
2354 
2355 /* --------------------------------------------------------------------------------------------- */
2356 
2357 static void
2358 ftpfs_done (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
2359 {
2360     (void) me;
2361 
2362     g_slist_free_full (no_proxy, g_free);
2363 
2364     g_free (ftpfs_anonymous_passwd);
2365     g_free (ftpfs_proxy_host);
2366 }
2367 
2368 /* --------------------------------------------------------------------------------------------- */
2369 
2370 static void
2371 ftpfs_fill_names (struct vfs_class *me, fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
2372 {
2373     GList *iter;
2374 
2375     for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
2376     {
2377         const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
2378         char *name;
2379 
2380         name = vfs_path_element_build_pretty_path_str (super->path_element);
2381 
2382         func (name);
2383         g_free (name);
2384     }
2385 }
2386 
2387 /* --------------------------------------------------------------------------------------------- */
2388 
2389 static keyword_t
2390 ftpfs_netrc_next (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2391 {
2392     char *p;
2393     keyword_t i;
2394     static const char *const keywords[] = { "default", "machine",
2395         "login", "password", "passwd", "account", "macdef", NULL
2396     };
2397 
2398     while (TRUE)
2399     {
2400         netrcp = skip_separators (netrcp);
2401         if (*netrcp != '\n')
2402             break;
2403         netrcp++;
2404     }
2405     if (*netrcp == '\0')
2406         return NETRC_NONE;
2407 
2408     p = buffer;
2409     if (*netrcp == '"')
2410     {
2411         for (netrcp++; *netrcp != '"' && *netrcp != '\0'; netrcp++)
2412         {
2413             if (*netrcp == '\\')
2414                 netrcp++;
2415             *p++ = *netrcp;
2416         }
2417     }
2418     else
2419     {
2420         for (; *netrcp != '\0' && !whiteness (*netrcp) && *netrcp != ','; netrcp++)
2421         {
2422             if (*netrcp == '\\')
2423                 netrcp++;
2424             *p++ = *netrcp;
2425         }
2426     }
2427 
2428     *p = '\0';
2429     if (*buffer == '\0')
2430         return NETRC_NONE;
2431 
2432     for (i = NETRC_DEFAULT; keywords[i - 1] != NULL; i++)
2433         if (strcmp (keywords[i - 1], buffer) == 0)
2434             return i;
2435 
2436     return NETRC_UNKNOWN;
2437 }
2438 
2439 /* --------------------------------------------------------------------------------------------- */
2440 
2441 static gboolean
2442 ftpfs_netrc_bad_mode (const char *netrcname)
     /* [previous][next][first][last][top][bottom][index][help]  */
2443 {
2444     struct stat mystat;
2445 
2446     if (stat (netrcname, &mystat) >= 0 && (mystat.st_mode & 077) != 0)
2447     {
2448         static gboolean be_angry = TRUE;
2449 
2450         if (be_angry)
2451         {
2452             message (D_ERROR, MSG_ERROR,
2453                      _("~/.netrc file has incorrect mode\nRemove password or correct mode"));
2454             be_angry = FALSE;
2455         }
2456         return TRUE;
2457     }
2458 
2459     return FALSE;
2460 }
2461 
2462 /* --------------------------------------------------------------------------------------------- */
2463 /* Scan .netrc until we find matching "machine" or "default"
2464  * domain is used for additional matching
2465  * No search is done after "default" in compliance with "man netrc"
2466  * Return TRUE if found, FALSE otherwise */
2467 
2468 static gboolean
2469 ftpfs_find_machine (const char *host, const char *domain)
     /* [previous][next][first][last][top][bottom][index][help]  */
2470 {
2471     keyword_t keyword;
2472 
2473     if (host == NULL)
2474         host = "";
2475     if (domain == NULL)
2476         domain = "";
2477 
2478     while ((keyword = ftpfs_netrc_next ()) != NETRC_NONE)
2479     {
2480         if (keyword == NETRC_DEFAULT)
2481             return TRUE;
2482 
2483         if (keyword == NETRC_MACDEF)
2484         {
2485             /* Scan for an empty line, which concludes "macdef" */
2486             do
2487             {
2488                 while (*netrcp != '\0' && *netrcp != '\n')
2489                     netrcp++;
2490                 if (*netrcp != '\n')
2491                     break;
2492                 netrcp++;
2493             }
2494             while (*netrcp != '\0' && *netrcp != '\n');
2495 
2496             continue;
2497         }
2498 
2499         if (keyword != NETRC_MACHINE)
2500             continue;
2501 
2502         /* Take machine name */
2503         if (ftpfs_netrc_next () == NETRC_NONE)
2504             break;
2505 
2506         if (g_ascii_strcasecmp (host, buffer) != 0)
2507         {
2508             const char *host_domain;
2509 
2510             /* Try adding our domain to short names in .netrc */
2511             host_domain = strchr (host, '.');
2512             if (host_domain == NULL)
2513                 continue;
2514 
2515             /* Compare domain part */
2516             if (g_ascii_strcasecmp (host_domain, domain) != 0)
2517                 continue;
2518 
2519             /* Compare local part */
2520             if (g_ascii_strncasecmp (host, buffer, host_domain - host) != 0)
2521                 continue;
2522         }
2523 
2524         return TRUE;
2525     }
2526 
2527     /* end of .netrc */
2528     return FALSE;
2529 }
2530 
2531 /* --------------------------------------------------------------------------------------------- */
2532 /* Extract login and password from .netrc for the host.
2533  * pass may be NULL.
2534  * Returns TRUE for success, FALSE for error */
2535 
2536 static gboolean
2537 ftpfs_netrc_lookup (const char *host, char **login, char **pass)
     /* [previous][next][first][last][top][bottom][index][help]  */
2538 {
2539     char *netrcname;
2540     char *tmp_pass = NULL;
2541     char hostname[MAXHOSTNAMELEN];
2542     const char *domain;
2543     static struct rupcache
2544     {
2545         struct rupcache *next;
2546         char *host;
2547         char *login;
2548         char *pass;
2549     } *rup_cache = NULL, *rupp;
2550 
2551     /* Initialize *login and *pass */
2552     MC_PTR_FREE (*login);
2553     MC_PTR_FREE (*pass);
2554 
2555     /* Look up in the cache first */
2556     for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
2557         if (strcmp (host, rupp->host) == 0)
2558         {
2559             *login = g_strdup (rupp->login);
2560             *pass = g_strdup (rupp->pass);
2561             return TRUE;
2562         }
2563 
2564     /* Load current .netrc */
2565     netrcname = g_build_filename (mc_config_get_home_dir (), ".netrc", (char *) NULL);
2566     if (!g_file_get_contents (netrcname, &netrc, NULL, NULL))
2567     {
2568         g_free (netrcname);
2569         return TRUE;
2570     }
2571 
2572     netrcp = netrc;
2573 
2574     /* Find our own domain name */
2575     if (gethostname (hostname, sizeof (hostname)) < 0)
2576         *hostname = '\0';
2577 
2578     domain = strchr (hostname, '.');
2579     if (domain == NULL)
2580         domain = "";
2581 
2582     /* Scan for "default" and matching "machine" keywords */
2583     ftpfs_find_machine (host, domain);
2584 
2585     /* Scan for keywords following "default" and "machine" */
2586     while (TRUE)
2587     {
2588         keyword_t keyword;
2589 
2590         gboolean need_break = FALSE;
2591         keyword = ftpfs_netrc_next ();
2592 
2593         switch (keyword)
2594         {
2595         case NETRC_LOGIN:
2596             if (ftpfs_netrc_next () == NETRC_NONE)
2597             {
2598                 need_break = TRUE;
2599                 break;
2600             }
2601 
2602             /* We have another name already - should not happen */
2603             if (*login != NULL)
2604             {
2605                 need_break = TRUE;
2606                 break;
2607             }
2608 
2609             /* We have login name now */
2610             *login = g_strdup (buffer);
2611             break;
2612 
2613         case NETRC_PASSWORD:
2614         case NETRC_PASSWD:
2615             if (ftpfs_netrc_next () == NETRC_NONE)
2616             {
2617                 need_break = TRUE;
2618                 break;
2619             }
2620 
2621             /* Ignore unsafe passwords */
2622             if (*login != NULL &&
2623                 strcmp (*login, "anonymous") != 0 && strcmp (*login, "ftp") != 0
2624                 && ftpfs_netrc_bad_mode (netrcname))
2625             {
2626                 need_break = TRUE;
2627                 break;
2628             }
2629 
2630             /* Remember password.  pass may be NULL, so use tmp_pass */
2631             if (tmp_pass == NULL)
2632                 tmp_pass = g_strdup (buffer);
2633             break;
2634 
2635         case NETRC_ACCOUNT:
2636             /* "account" is followed by a token which we ignore */
2637             if (ftpfs_netrc_next () == NETRC_NONE)
2638             {
2639                 need_break = TRUE;
2640                 break;
2641             }
2642 
2643             /* Ignore account, but warn user anyways */
2644             ftpfs_netrc_bad_mode (netrcname);
2645             break;
2646 
2647         default:
2648             /* Unexpected keyword or end of file */
2649             need_break = TRUE;
2650             break;
2651         }
2652 
2653         if (need_break)
2654             break;
2655     }
2656 
2657     MC_PTR_FREE (netrc);
2658     g_free (netrcname);
2659 
2660     rupp = g_new (struct rupcache, 1);
2661     rupp->host = g_strdup (host);
2662     rupp->login = g_strdup (*login);
2663     rupp->pass = g_strdup (tmp_pass);
2664 
2665     rupp->next = rup_cache;
2666     rup_cache = rupp;
2667 
2668     *pass = tmp_pass;
2669 
2670     return TRUE;
2671 }
2672 
2673 /* --------------------------------------------------------------------------------------------- */
2674 /*** public functions ****************************************************************************/
2675 /* --------------------------------------------------------------------------------------------- */
2676 
2677 /** This routine is called as the last step in load_setup */
2678 void
2679 ftpfs_init_passwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2680 {
2681     ftpfs_anonymous_passwd = load_anon_passwd ();
2682 
2683     if (ftpfs_anonymous_passwd == NULL)
2684     {
2685         /* If there is no anonymous ftp password specified
2686          * then we'll just use anonymous@
2687          * We don't send any other thing because:
2688          * - We want to remain anonymous
2689          * - We want to stop SPAM
2690          * - We don't want to let ftp sites to discriminate by the user,
2691          *   host or country.
2692          */
2693         ftpfs_anonymous_passwd = g_strdup ("anonymous@");
2694     }
2695 }
2696 
2697 /* --------------------------------------------------------------------------------------------- */
2698 
2699 void
2700 vfs_init_ftpfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2701 {
2702     tcp_init ();
2703 
2704     vfs_init_subclass (&ftpfs_subclass, "ftpfs", VFS_NOLINKS | VFS_REMOTE | VFS_USETMP, "ftp");
2705     vfs_ftpfs_ops->done = ftpfs_done;
2706     vfs_ftpfs_ops->fill_names = ftpfs_fill_names;
2707     vfs_ftpfs_ops->stat = ftpfs_stat;
2708     vfs_ftpfs_ops->lstat = ftpfs_lstat;
2709     vfs_ftpfs_ops->fstat = ftpfs_fstat;
2710     vfs_ftpfs_ops->chmod = ftpfs_chmod;
2711     vfs_ftpfs_ops->chown = ftpfs_chown;
2712     vfs_ftpfs_ops->unlink = ftpfs_unlink;
2713     vfs_ftpfs_ops->rename = ftpfs_rename;
2714     vfs_ftpfs_ops->mkdir = ftpfs_mkdir;
2715     vfs_ftpfs_ops->rmdir = ftpfs_rmdir;
2716     vfs_ftpfs_ops->ctl = ftpfs_ctl;
2717     ftpfs_subclass.archive_same = ftpfs_archive_same;
2718     ftpfs_subclass.new_archive = ftpfs_new_archive;
2719     ftpfs_subclass.open_archive = ftpfs_open_archive;
2720     ftpfs_subclass.free_archive = ftpfs_free_archive;
2721     ftpfs_subclass.fh_new = ftpfs_fh_new;
2722     ftpfs_subclass.fh_open = ftpfs_fh_open;
2723     ftpfs_subclass.fh_close = ftpfs_fh_close;
2724     ftpfs_subclass.dir_load = ftpfs_dir_load;
2725     ftpfs_subclass.file_store = ftpfs_file_store;
2726     ftpfs_subclass.linear_start = ftpfs_linear_start;
2727     ftpfs_subclass.linear_read = ftpfs_linear_read;
2728     ftpfs_subclass.linear_close = ftpfs_linear_close;
2729     vfs_register_class (vfs_ftpfs_ops);
2730 }
2731 
2732 /* --------------------------------------------------------------------------------------------- */

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