1 /* Virtual File System: FTP file system.
2 Copyright (C) 1995 The Free Software Foundation
4 Written by: 1995 Ching Hui
6 1995, 1996, 1997 Miguel de Icaza
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public License
12 as published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 - make it more robust - all the connects etc. should handle EADDRINUSE and
27 ERETRY (have I spelled these names correctly?)
28 - make the user able to flush a connection - all the caches will get empty
29 etc., (tarfs as well), we should give there a user selectable timeout
30 and assign a key sequence.
31 - use hash table instead of linklist to cache ftpfs directory.
34 /* Namespace pollution: horrible */
42 #include <sys/types.h>
46 #include <ctype.h> /* For isdigit */
48 # include <sys/timeb.h> /* alex: for struct timeb definition */
49 #endif /* SCO_FLAVOR */
51 #include <sys/types.h>
52 #if defined(HAVE_UNISTD_H)
56 # include <sys/select.h>
59 #include "../src/setup.h"
61 #include <netdb.h> /* struct hostent */
62 #include <sys/socket.h> /* AF_INET */
63 #include <netinet/in.h> /* struct in_addr */
64 #ifdef HAVE_SETSOCKOPT
65 # include <netinet/ip.h> /* IP options */
67 #include <arpa/inet.h>
69 #include <arpa/telnet.h>
71 # include <sys/time.h> /* alex: this redefines struct timeval */
72 #endif /* SCO_FLAVOR */
73 #include <sys/param.h>
83 #include "../src/dialog.h"
84 #include "container.h"
86 #ifndef MAXHOSTNAMELEN
87 # define MAXHOSTNAMELEN 64
90 #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
91 #define UPLOAD_ZERO_LENGTH_FILE
96 /* Delay to retry a connection */
97 int ftpfs_retry_seconds
= 30;
99 /* Method to use to connect to ftp sites */
100 int ftpfs_use_passive_connections
= 1;
102 /* Method used to get directory listings:
103 * 1: try 'LIST -la <path>', if it fails
104 * fall back to CWD <path>; LIST
105 * 0: always use CWD <path>; LIST
107 int ftpfs_use_unix_list_options
= 1;
109 /* First "CWD <path>", then "LIST -la ." */
110 int ftpfs_first_cd_then_ls
;
112 /* Use the ~/.netrc */
115 extern char *home_dir
;
117 /* Anonymous setup */
118 char *ftpfs_anonymous_passwd
= 0;
119 int ftpfs_directory_timeout
;
122 char *ftpfs_proxy_host
= 0;
124 /* wether we have to use proxy by default? */
125 int ftpfs_always_use_proxy
;
127 /* source routing host */
128 extern int source_route
;
130 /* Where we store the transactions */
131 static FILE *logfile
= NULL
;
133 /* If true, the directory cache is forced to reload */
134 static int force_expiration
= 0;
136 static struct linklist
*connections_list
;
138 /* command wait_flag: */
140 #define WAIT_REPLY 0x01
141 #define WANT_STRING 0x02
142 static char reply_str
[80];
144 static struct direntry
*_get_file_entry (struct connection
*bucket
,
145 char *file_name
, int op
, int flags
);
147 static char *ftpfs_get_current_directory (struct connection
*bucket
);
148 static int ftpfs_chdir_internal (struct connection
*bucket
,
150 static void free_bucket (void *data
);
151 static void connection_destructor (void *data
);
152 static void flush_all_directory (struct connection
*bucket
);
153 static int get_line (int sock
, char *buf
, int buf_len
,
155 static char *get_path (struct connection
**bucket
,
158 /* char *translate_path (struct ftpfs_connection *bucket, char *remote_path)
159 Translate a Unix path, i.e. MC's internal path representation (e.g.
160 /somedir/somefile) to a path valid for the remote server. Every path
161 transfered to the remote server has to be mangled by this function
162 right prior to sending it.
163 Currently only Amiga ftp servers are handled in a special manner.
165 When the remote server is an amiga:
166 a) strip leading slash if necesarry
167 b) replace first occurance of ":/" with ":"
168 c) strip trailing "/."
172 translate_path (struct connection
*bucket
, char *remote_path
)
175 static char buf
[255]; /* No one ever needs more ;-).
176 Actually I consider this static a bug
179 if (!bucket
->remote_is_amiga
|| strlen (remote_path
) >= sizeof (buf
) - 1)
183 fprintf (logfile
, "MC -- translate_path: %s\n", remote_path
);
187 if (*remote_path
== '/' && remote_path
[1] == '\0')
188 return "."; /* Don't change "/" into "", e.g. "CWD " would be
191 /* strip leading slash */
192 if (*remote_path
== '/')
193 strcpy (buf
, remote_path
+ 1);
195 strcpy (buf
, remote_path
);
197 /* replace first occurance of ":/" with ":" */
198 if ((p
= strchr (buf
, ':')) && *(p
+ 1) == '/')
199 strcpy (p
+ 1, p
+ 2);
201 /* strip trailing "/." */
202 if ((p
= strrchr (buf
, '/')) && *(p
+ 1) == '.' && *(p
+ 2) == '\0')
208 /* Extract the hostname and username from the path */
211 * path is in the form: [user@]hostname:port/remote-dir, e.g.:
212 * ftp://sunsite.unc.edu/pub/linux
213 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
214 * ftp://tsx-11.mit.edu:8192/
215 * ftp://joe@foo.edu:11321/private
216 * If the user is empty, e.g. ftp://@roxanne/private, then your login name
222 my_get_host_and_username (char *path
, char **host
, char **user
, int *port
, char **pass
)
224 return vfs_split_url (path
, host
, user
, port
, pass
, 21, URL_DEFAULTANON
);
227 /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
229 get_reply (int sock
, char *string_buf
, int string_len
)
235 if (!get_line (sock
, answer
, sizeof (answer
), '\n')){
241 switch (sscanf(answer
, "%d", &code
)){
244 strncpy (string_buf
, answer
, string_len
- 1);
245 *(string_buf
+ string_len
- 1) = 0;
250 if (answer
[3] == '-') {
252 if (!get_line (sock
, answer
, sizeof(answer
), '\n')){
258 if ((sscanf (answer
, "%d", &i
) > 0) &&
259 (code
== i
) && (answer
[3] == ' '))
264 strncpy (string_buf
, answer
, string_len
- 1);
265 *(string_buf
+ string_len
- 1) = 0;
273 command (struct connection
*bucket
, int wait_reply
, char *fmt
, ...)
278 int sock
= qsock (bucket
);
282 fmt_str
= g_strdup_vprintf (fmt
, ap
);
285 str
= g_strconcat (fmt_str
, "\r\n", NULL
);
289 if (strncmp (str
, "PASS ", 5) == 0){
290 char *tmp
= "PASS <Password not logged>\r\n";
292 fwrite (tmp
, strlen (tmp
), 1, logfile
);
294 fwrite (str
, strlen (str
), 1, logfile
);
300 enable_interrupt_key ();
301 status
= write (sock
, str
, strlen (str
));
310 disable_interrupt_key ();
313 disable_interrupt_key ();
316 return get_reply (sock
, (wait_reply
& WANT_STRING
) ? reply_str
: NULL
, sizeof (reply_str
)-1);
321 connection_close (void *data
)
323 struct connection
*bucket
= data
;
325 if (qsock (bucket
) != -1){
326 print_vfs_message ("ftpfs: Disconnecting from %s", qhost (bucket
));
327 command(bucket
, NONE
, "QUIT");
328 close(qsock(bucket
));
332 /* some defines only used by changetype */
333 /* These two are valid values for the second parameter */
335 #define TYPE_BINARY 1
337 /* This one is only used to initialize bucket->isbinary, don't use it as
338 second parameter to changetype. */
339 #define TYPE_UNKNOWN -1
342 changetype (struct connection
*bucket
, int binary
)
344 if (binary
!= bucket
->isbinary
) {
345 if (command (bucket
, WAIT_REPLY
, "TYPE %c", binary
? 'I' : 'A') != COMPLETE
)
347 bucket
->isbinary
= binary
;
352 /* This routine logs the user in */
354 login_server (struct connection
*bucket
, char *netrcpass
)
356 #if defined(HSC_PROXY)
357 char *proxypass
, *proxyname
;
361 char *name
; /* login user name */
363 char reply_string
[255];
365 bucket
->isbinary
= TYPE_UNKNOWN
;
367 op
= g_strdup (netrcpass
);
369 if (!strcmp (quser (bucket
), "anonymous") ||
370 !strcmp (quser (bucket
), "ftp")) {
371 op
= g_strdup (ftpfs_anonymous_passwd
);
376 if (!bucket
->password
){
377 p
= g_strconcat (" FTP: Password required for ", quser (bucket
),
379 op
= vfs_get_password (p
);
383 bucket
->password
= g_strdup (op
);
385 op
= g_strdup (bucket
->password
);
389 if (!anon
|| logfile
)
390 pass
= g_strdup (op
);
392 pass
= g_strconcat ("-", op
, NULL
);
396 /* Proxy server accepts: username@host-we-want-to-connect*/
397 if (qproxy (bucket
)){
398 #if defined(HSC_PROXY)
401 p
= my_get_host_and_username (ftpfs_proxy_host
, &host
, &proxyname
,
408 wipe_password (proxypass
);
409 p
= g_strconcat (" Proxy: Password required for ", proxyname
, " ",
411 proxypass
= vfs_get_password (p
);
413 if (proxypass
== NULL
) {
414 wipe_password (pass
);
418 name
= g_strdup (quser (bucket
));
420 name
= g_strconcat (quser (bucket
), "@",
421 qhost (bucket
)[0] == '!' ? qhost (bucket
)+1 : qhost (bucket
), NULL
);
424 name
= g_strdup (quser (bucket
));
426 if (get_reply (qsock(bucket
), reply_string
, sizeof (reply_string
) - 1) == COMPLETE
) {
427 g_strup (reply_string
);
428 bucket
->remote_is_amiga
= strstr (reply_string
, "AMIGA") != 0;
430 fprintf (logfile
, "MC -- remote_is_amiga = %d\n", bucket
->remote_is_amiga
);
433 #if defined(HSC_PROXY)
434 if (qproxy (bucket
)){
435 print_vfs_message ("ftpfs: sending proxy login name");
436 if (command (bucket
, 1, "USER %s", proxyname
) != CONTINUE
)
439 print_vfs_message ("ftpfs: sending proxy user password");
440 if (command (bucket
, 1, "PASS %s", proxypass
) != COMPLETE
)
443 print_vfs_message ("ftpfs: proxy authentication succeeded");
444 if (command (bucket
, 1, "SITE %s", qhost (bucket
)+1) != COMPLETE
)
447 print_vfs_message ("ftpfs: connected to %s", qhost (bucket
)+1);
450 bucket
->failed_on_login
= 1;
453 wipe_password (proxypass
);
454 wipe_password (pass
);
460 wipe_password (proxypass
);
464 print_vfs_message ("ftpfs: sending login name");
465 code
= command (bucket
, WAIT_REPLY
, "USER %s", name
);
469 print_vfs_message ("ftpfs: sending user password");
470 if (command (bucket
, WAIT_REPLY
, "PASS %s", pass
) != COMPLETE
)
474 print_vfs_message ("ftpfs: logged in");
475 wipe_password (pass
);
480 bucket
->failed_on_login
= 1;
482 if (bucket
->password
)
483 wipe_password (bucket
->password
);
484 bucket
->password
= 0;
489 print_vfs_message ("ftpfs: Login incorrect for user %s ", quser (bucket
));
491 wipe_password (pass
);
496 #ifdef HAVE_SETSOCKOPT
498 setup_source_route (int socket
, int dest
)
505 bzero (buffer
, sizeof (buffer
));
508 *ptr
++ = 4; /* pointer */
511 bcopy ((char *) &source_route
, ptr
, sizeof (int));
514 /* Second hop (ie, final destination) */
515 bcopy ((char *) &dest
, ptr
, sizeof (int));
517 while ((ptr
- buffer
) & 3)
519 if (setsockopt (socket
, IPPROTO_IP
, IP_OPTIONS
,
520 buffer
, ptr
- buffer
) < 0)
521 message_2s (1, MSG_ERROR
, _(" Could not set source routing (%s)"), unix_error_string (errno
));
524 #define setup_source_route(x,y)
527 static struct no_proxy_entry
{
533 load_no_proxy_list ()
535 /* FixMe: shouldn't be hardcoded!!! */
536 char s
[BUF_LARGE
]; /* provide for BUF_LARGE characters */
537 struct no_proxy_entry
*np
, *current
= 0;
546 mc_file
= concat_dir_and_file (mc_home
, "mc.no_proxy");
547 if (exist_file (mc_file
) &&
548 (npf
= fopen (mc_file
, "r"))) {
549 while (fgets (s
, sizeof(s
), npf
) || !(feof (npf
) || ferror (npf
))) {
550 if (!(p
= strchr (s
, '\n'))) { /* skip bogus entries */
551 while ((c
= fgetc (npf
)) != EOF
&& c
!= '\n')
561 np
= g_new (struct no_proxy_entry
, 1);
562 np
->domain
= g_strdup (s
);
578 ftpfs_check_proxy (char *host
)
580 struct no_proxy_entry
*npe
;
582 if (!ftpfs_proxy_host
|| !*ftpfs_proxy_host
|| !host
|| !*host
)
583 return 0; /* sanity check */
588 if (!ftpfs_always_use_proxy
)
591 if (!strchr (host
, '.'))
594 load_no_proxy_list ();
595 for (npe
= no_proxy
; npe
; npe
=npe
->next
) {
596 char *domain
= npe
->domain
;
598 if (domain
[0] == '.') {
599 int ld
= strlen (domain
);
600 int lh
= strlen (host
);
602 while (ld
&& lh
&& host
[lh
- 1] == domain
[ld
- 1]) {
610 if (!g_strcasecmp (host
, domain
))
618 ftpfs_get_proxy_host_and_port (char *proxy
, char **host
, int *port
)
620 char *user
, *pass
, *dir
;
622 #if defined(HSC_PROXY)
627 dir
= vfs_split_url (proxy
, host
, &user
, port
, &pass
, PORT
, URL_DEFAULTANON
);
631 wipe_password (pass
);
637 ftpfs_open_socket (struct connection
*bucket
)
639 struct sockaddr_in server_address
;
646 /* Use a proxy host? */
647 host
= qhost (bucket
);
649 if (!host
|| !*host
){
650 print_vfs_message ("ftpfs: Invalid host name.");
655 /* Hosts to connect to that start with a ! should use proxy */
656 if (qproxy (bucket
)){
657 ftpfs_get_proxy_host_and_port (ftpfs_proxy_host
, &host
, &port
);
661 /* Get host address */
662 bzero ((char *) &server_address
, sizeof (server_address
));
663 server_address
.sin_family
= AF_INET
;
664 server_address
.sin_addr
.s_addr
= inet_addr (host
);
665 if (server_address
.sin_addr
.s_addr
!= -1)
666 server_address
.sin_family
= AF_INET
;
668 hp
= gethostbyname (host
);
670 print_vfs_message ("ftpfs: Invalid host address.");
676 server_address
.sin_family
= hp
->h_addrtype
;
678 /* We copy only 4 bytes, we can not trust hp->h_length, as it comes from the DNS */
679 bcopy ((char *) hp
->h_addr
, (char *) &server_address
.sin_addr
, 4);
682 #define THE_PORT qproxy(bucket) ? port : qport (bucket)
684 server_address
.sin_port
= htons (THE_PORT
);
687 if ((my_socket
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0) {
693 setup_source_route (my_socket
, server_address
.sin_addr
.s_addr
);
695 print_vfs_message ("ftpfs: making connection to %s", host
);
699 enable_interrupt_key (); /* clear the interrupt flag */
701 if (connect (my_socket
, (struct sockaddr
*) &server_address
,
702 sizeof (server_address
)) < 0){
704 if (errno
== EINTR
&& got_interrupt ())
705 print_vfs_message ("ftpfs: connection interrupted by user");
707 print_vfs_message ("ftpfs: connection to server failed: %s",
708 unix_error_string(errno
));
709 disable_interrupt_key();
713 disable_interrupt_key();
717 static struct connection
*
718 open_command_connection (char *host
, char *user
, int port
, char *netrcpass
)
720 struct connection
*bucket
;
721 int retry_seconds
, count_down
;
723 bucket
= g_new (struct connection
, 1);
726 ERRNOR (ENOMEM
, NULL
);
729 extern void *watch_free_pointer
;
731 if (!watch_free_pointer
)
732 watch_free_pointer
= host
;
735 qhost (bucket
) = g_strdup (host
);
736 quser (bucket
) = g_strdup (user
);
737 qcdir (bucket
) = NULL
;
738 qport (bucket
) = port
;
740 qhome (bucket
) = NULL
;
744 bucket
->__inode_counter
= 0;
746 bucket
->use_proxy
= ftpfs_check_proxy (host
);
747 bucket
->password
= 0;
748 bucket
->use_passive_connection
= ftpfs_use_passive_connections
| source_route
;
749 bucket
->use_source_route
= source_route
;
750 bucket
->strict_rfc959_list_cmd
= !ftpfs_use_unix_list_options
;
751 bucket
->isbinary
= TYPE_UNKNOWN
;
752 bucket
->remote_is_amiga
= 0;
754 /* We do not want to use the passive if we are using proxies */
755 if (bucket
->use_proxy
)
756 bucket
->use_passive_connection
= 0;
758 if ((qdcache (bucket
) = linklist_init ()) == NULL
) {
760 g_free (qhost (bucket
));
761 g_free (quser (bucket
));
768 bucket
->failed_on_login
= 0;
770 qsock (bucket
) = ftpfs_open_socket (bucket
);
771 if (qsock (bucket
) == -1) {
772 free_bucket (bucket
);
776 if (login_server (bucket
, netrcpass
)) {
777 /* Logged in, no need to retry the connection */
780 if (bucket
->failed_on_login
){
781 /* Close only the socket descriptor */
782 close (qsock (bucket
));
784 connection_destructor (bucket
);
787 if (ftpfs_retry_seconds
){
788 retry_seconds
= ftpfs_retry_seconds
;
789 enable_interrupt_key ();
790 for (count_down
= retry_seconds
; count_down
; count_down
--){
791 print_vfs_message ("Waiting to retry... %d (Control-C to cancel)", count_down
);
793 if (got_interrupt ()){
795 disable_interrupt_key ();
796 free_bucket (bucket
);
800 disable_interrupt_key ();
803 } while (retry_seconds
);
805 qhome (bucket
) = ftpfs_get_current_directory (bucket
);
807 qhome (bucket
) = g_strdup (PATH_SEP_STR
);
808 qupdir (bucket
) = g_strdup (PATH_SEP_STR
); /* FIXME: I changed behavior to ignore last_current_dir */
813 is_connection_closed (struct connection
*bucket
)
824 FD_SET (qsock (bucket
), &rset
);
826 if (select (qsock (bucket
) + 1, &rset
, NULL
, NULL
, &t
) < 0)
831 if (FD_ISSET (qsock(bucket
), &rset
)) {
832 n
= read (qsock(bucket
), &read_ahead
, sizeof (read_ahead
));
840 /* This routine keeps track of open connections */
841 /* Returns a connected socket to host */
842 static struct connection
*
843 open_link (char *host
, char *user
, int port
, char *netrcpass
)
846 struct connection
*bucket
;
847 struct linklist
*lptr
;
849 for (lptr
= connections_list
->next
;
850 lptr
!= connections_list
; lptr
= lptr
->next
) {
852 if ((strcmp (host
, qhost (bucket
)) == 0) &&
853 (strcmp (user
, quser (bucket
)) == 0) &&
854 (port
== qport (bucket
))) {
856 /* check the connection is closed or not, just hack */
857 if (is_connection_closed (bucket
)) {
858 flush_all_directory (bucket
);
859 sock
= ftpfs_open_socket (bucket
);
861 close (qsock (bucket
));
862 qsock (bucket
) = sock
;
863 if (login_server (bucket
, netrcpass
))
867 /* connection refused */
868 lptr
->prev
->next
= lptr
->next
;
869 lptr
->next
->prev
= lptr
->prev
;
870 connection_destructor (bucket
);
876 bucket
= open_command_connection (host
, user
, port
, netrcpass
);
879 if (!linklist_insert (connections_list
, bucket
)) {
881 connection_destructor (bucket
);
887 /* The returned directory should always contain a trailing slash */
889 ftpfs_get_current_directory (struct connection
*bucket
)
891 char buf
[4096], *bufp
, *bufq
;
893 if (command (bucket
, NONE
, "PWD") == COMPLETE
&&
894 get_reply(qsock(bucket
), buf
, sizeof(buf
)) == COMPLETE
) {
896 for (bufq
= buf
; *bufq
; bufq
++)
903 if (*(bufq
- 1) != '/') {
908 return g_strdup (bufp
);
910 /* If the remote server is an Amiga a leading slash
911 might be missing. MC needs it because it is used
912 as seperator between hostname and path internally. */
913 return g_strconcat( "/", bufp
, 0);
927 /* Setup Passive ftp connection, we use it for source routed connections */
929 setup_passive (int my_socket
, struct connection
*bucket
, struct sockaddr_in
*sa
)
931 int xa
, xb
, xc
, xd
, xe
, xf
;
935 if (command (bucket
, WAIT_REPLY
| WANT_STRING
, "PASV") != COMPLETE
)
938 /* Parse remote parameters */
939 for (c
= reply_str
+ 4; (*c
) && (!isdigit (*c
)); c
++)
945 if (sscanf (c
, "%d,%d,%d,%d,%d,%d", &xa
, &xb
, &xc
, &xd
, &xe
, &xf
) != 6)
947 n
[0] = (unsigned char) xa
;
948 n
[1] = (unsigned char) xb
;
949 n
[2] = (unsigned char) xc
;
950 n
[3] = (unsigned char) xd
;
951 n
[4] = (unsigned char) xe
;
952 n
[5] = (unsigned char) xf
;
954 bcopy ((void *)n
, &(sa
->sin_addr
.s_addr
), 4);
955 bcopy ((void *)&n
[4], &(sa
->sin_port
), 2);
956 setup_source_route (my_socket
, sa
->sin_addr
.s_addr
);
957 if (connect (my_socket
, (struct sockaddr
*) sa
, sizeof (struct sockaddr_in
)) < 0)
963 initconn (struct connection
*bucket
)
965 struct sockaddr_in data_addr
;
966 int data
, len
= sizeof(data_addr
);
969 getsockname(qsock(bucket
), (struct sockaddr
*) &data_addr
, &len
);
970 data_addr
.sin_port
= 0;
972 pe
= getprotobyname("tcp");
975 data
= socket (AF_INET
, SOCK_STREAM
, pe
->p_proto
);
979 #ifdef ORIGINAL_CONNECT_CODE
980 if (bucket
->use_source_route
){
983 if ((c
= setup_passive (data
, bucket
, &data_addr
)))
985 print_vfs_message("ftpfs: could not setup passive mode for source routing");
986 bucket
->use_source_route
= 0;
989 if (bucket
->use_passive_connection
){
990 if ((bucket
->use_passive_connection
= setup_passive (data
, bucket
, &data_addr
)))
993 bucket
->use_source_route
= 0;
994 bucket
->use_passive_connection
= 0;
995 print_vfs_message ("ftpfs: could not setup passive mode");
998 /* If passive setup fails, fallback to active connections */
999 /* Active FTP connection */
1000 if (bind (data
, (struct sockaddr
*)&data_addr
, len
) < 0)
1002 getsockname(data
, (struct sockaddr
*) &data_addr
, &len
);
1003 if (listen (data
, 1) < 0)
1006 unsigned char *a
= (unsigned char *)&data_addr
.sin_addr
;
1007 unsigned char *p
= (unsigned char *)&data_addr
.sin_port
;
1009 if (command (bucket
, WAIT_REPLY
, "PORT %d,%d,%d,%d,%d,%d", a
[0], a
[1],
1010 a
[2], a
[3], p
[0], p
[1]) != COMPLETE
)
1021 open_data_connection (struct connection
*bucket
, char *cmd
, char *remote
,
1022 int isbinary
, int reget
)
1024 struct sockaddr_in from
;
1025 int s
, j
, data
, fromlen
= sizeof(from
);
1027 if ((s
= initconn (bucket
)) == -1)
1029 if (changetype (bucket
, isbinary
) == -1)
1032 j
= command (bucket
, WAIT_REPLY
, "REST %d", reget
);
1037 j
= command (bucket
, WAIT_REPLY
, "%s %s", cmd
,
1038 translate_path (bucket
, remote
));
1040 j
= command (bucket
, WAIT_REPLY
, "%s", cmd
);
1043 enable_interrupt_key();
1044 if (bucket
->use_passive_connection
)
1047 data
= accept (s
, (struct sockaddr
*)&from
, &fromlen
);
1055 disable_interrupt_key();
1060 my_abort (struct connection
*bucket
, int dsock
)
1062 static unsigned char ipbuf
[3] = { IAC
, IP
, IAC
};
1066 print_vfs_message("ftpfs: aborting transfer.");
1067 if (send(qsock(bucket
), ipbuf
, sizeof(ipbuf
), MSG_OOB
) != sizeof(ipbuf
)) {
1068 print_vfs_message("ftpfs: abort error: %s", unix_error_string(errno
));
1072 if (command(bucket
, NONE
, "%cABOR", DM
) != COMPLETE
){
1073 print_vfs_message ("ftpfs: abort failed");
1078 FD_SET(dsock
, &mask
);
1079 if (select(dsock
+ 1, &mask
, NULL
, NULL
, NULL
) > 0)
1080 while (read(dsock
, buf
, sizeof(buf
)) > 0);
1082 if ((get_reply(qsock(bucket
), NULL
, 0) == TRANSIENT
) && (code
== 426))
1083 get_reply(qsock(bucket
), NULL
, 0);
1087 resolve_symlink_without_ls_options(struct connection
*bucket
, struct dir
*dir
)
1089 struct linklist
*flist
;
1090 struct direntry
*fe
, *fel
;
1091 char tmp
[MC_MAXPATHLEN
];
1093 dir
->symlink_status
= FTPFS_RESOLVING_SYMLINKS
;
1094 for (flist
= dir
->file_list
->next
; flist
!= dir
->file_list
; flist
= flist
->next
) {
1095 /* flist->data->l_stat is alread initialized with 0 */
1097 if (S_ISLNK(fel
->s
.st_mode
)) {
1098 if (fel
->linkname
[0] == '/') {
1099 if (strlen (fel
->linkname
) >= MC_MAXPATHLEN
)
1101 strcpy (tmp
, fel
->linkname
);
1103 if ((strlen (dir
->remote_path
) + strlen (fel
->linkname
)) >= MC_MAXPATHLEN
)
1105 strcpy (tmp
, dir
->remote_path
);
1108 strcat (tmp
+ 1, fel
->linkname
);
1111 canonicalize_pathname (tmp
);
1112 fe
= _get_file_entry(bucket
, tmp
, 0, 0);
1114 if (S_ISLNK (fe
->s
.st_mode
) && fe
->l_stat
== 0) {
1115 /* Symlink points to link which isn't resolved, yet. */
1116 if (fe
->linkname
[0] == '/') {
1117 if (strlen (fe
->linkname
) >= MC_MAXPATHLEN
)
1119 strcpy (tmp
, fe
->linkname
);
1121 /* at this point tmp looks always like this
1122 /directory/filename, i.e. no need to check
1123 strrchr's return value */
1124 *(strrchr (tmp
, '/') + 1) = '\0'; /* dirname */
1125 if ((strlen (tmp
) + strlen (fe
->linkname
)) >= MC_MAXPATHLEN
)
1127 strcat (tmp
, fe
->linkname
);
1131 fel
->l_stat
= g_new (struct stat
, 1);
1132 if ( S_ISLNK (fe
->s
.st_mode
))
1133 *fel
->l_stat
= *fe
->l_stat
;
1135 *fel
->l_stat
= fe
->s
;
1136 (*fel
->l_stat
).st_ino
= bucket
->__inode_counter
++;
1143 dir
->symlink_status
= FTPFS_RESOLVED_SYMLINKS
;
1147 resolve_symlink_with_ls_options(struct connection
*bucket
, struct dir
*dir
)
1149 char buffer
[2048] = "", *filename
;
1153 struct linklist
*flist
;
1154 struct direntry
*fe
;
1156 dir
->symlink_status
= FTPFS_RESOLVED_SYMLINKS
;
1157 if (strchr (dir
->remote_path
, ' ')) {
1158 if (ftpfs_chdir_internal (bucket
, dir
->remote_path
) != COMPLETE
) {
1159 print_vfs_message("ftpfs: CWD failed.");
1162 sock
= open_data_connection (bucket
, "LIST -lLa", ".", TYPE_ASCII
, 0);
1165 sock
= open_data_connection (bucket
, "LIST -lLa",
1166 dir
->remote_path
, TYPE_ASCII
, 0);
1169 print_vfs_message("ftpfs: couldn't resolve symlink");
1173 fp
= fdopen(sock
, "r");
1176 print_vfs_message("ftpfs: couldn't resolve symlink");
1179 enable_interrupt_key();
1180 flist
= dir
->file_list
->next
;
1183 if (flist
== dir
->file_list
)
1186 flist
= flist
->next
;
1187 } while (!S_ISLNK(fe
->s
.st_mode
));
1189 if (fgets (buffer
, sizeof (buffer
), fp
) == NULL
)
1192 fputs (buffer
, logfile
);
1195 if (vfs_parse_ls_lga (buffer
, &s
, &filename
, NULL
)) {
1196 int r
= strcmp(fe
->name
, filename
);
1199 fe
->l_stat
= g_new (struct stat
, 1);
1200 if (fe
->l_stat
== NULL
)
1203 (*fe
->l_stat
).st_ino
= bucket
->__inode_counter
++;
1212 while (fgets(buffer
, sizeof(buffer
), fp
) != NULL
);
1213 disable_interrupt_key();
1215 get_reply(qsock(bucket
), NULL
, 0);
1219 resolve_symlink(struct connection
*bucket
, struct dir
*dir
)
1221 print_vfs_message("Resolving symlink...");
1223 if (bucket
->strict_rfc959_list_cmd
)
1224 resolve_symlink_without_ls_options(bucket
, dir
);
1226 resolve_symlink_with_ls_options(bucket
, dir
);
1231 #define X_myname "/#ftp:"
1232 #define vfs_X_ops vfs_ftpfs_ops
1233 #define X_fill_names ftpfs_fill_names
1234 #define X_hint_reread ftpfs_hint_reread
1235 #define X_flushdir ftpfs_flushdir
1236 #define X_done ftpfs_done
1237 #include "shared_ftp_fish.c"
1240 get_path (struct connection
**bucket
, char *path
)
1242 return s_get_path (bucket
, path
, "/#ftp:");
1245 /* Inserts an entry for "." (and "..") into the linked list. Ignore any
1246 errors because "." isn't important (as fas as you don't try to save a
1247 file in the root dir of the ftp server).
1248 Actually the dot is needed when stating the root directory, e.g.
1249 mc_stat ("/ftp#localhost", &buf). Down the call tree _get_file_entry
1250 gets called with filename = "/" which will be transformed into "."
1251 before searching for a fileentry. Whithout "." in the linked list
1252 this search fails. -- Norbert. */
1254 insert_dots (struct linklist
*file_list
, struct connection
*bucket
)
1256 struct direntry
*fe
;
1258 char buffer
[][58] = {
1259 "drwxrwxrwx 1 0 0 1024 Jan 1 1970 .",
1260 "drwxrwxrwx 1 0 0 1024 Jan 1 1970 .."
1263 for (i
= 0; i
< 2; i
++ ) {
1264 fe
= malloc(sizeof(struct direntry
));
1267 if (vfs_parse_ls_lga (buffer
[i
], &fe
->s
, &fe
->name
, &fe
->linkname
)) {
1268 fe
->freshly_created
= 0;
1270 fe
->local_filename
= fe
->remote_filename
= NULL
;
1272 fe
->bucket
= bucket
;
1273 (fe
->s
).st_ino
= bucket
->__inode_counter
++;
1275 if (!linklist_insert(file_list
, fe
))
1283 retrieve_dir(struct connection
*bucket
, char *remote_path
, int resolve_symlinks
)
1288 int sock
, has_symlinks
;
1289 struct linklist
*file_list
, *p
;
1290 struct direntry
*fe
;
1295 int dot_dot_found
= 0;
1296 int has_spaces
= (strchr (remote_path
, ' ') != NULL
);
1298 canonicalize_pathname (remote_path
);
1299 for (p
= qdcache(bucket
)->next
;p
!= qdcache(bucket
);
1302 if (strcmp(dcache
->remote_path
, remote_path
) == 0) {
1305 gettimeofday(&tim
, NULL
);
1306 if (((tim
.tv_sec
< dcache
->timestamp
.tv_sec
) && !force_expiration
)
1307 || dcache
->symlink_status
== FTPFS_RESOLVING_SYMLINKS
) {
1308 if (resolve_symlinks
&& dcache
->symlink_status
== FTPFS_UNRESOLVED_SYMLINKS
)
1309 resolve_symlink(bucket
, dcache
);
1312 force_expiration
= 0;
1313 p
->next
->prev
= p
->prev
;
1314 p
->prev
->next
= p
->next
;
1315 dir_destructor(dcache
);
1323 if (bucket
->strict_rfc959_list_cmd
)
1324 print_vfs_message("ftpfs: Reading FTP directory %s... (don't use UNIX ls options)", remote_path
);
1326 print_vfs_message("ftpfs: Reading FTP directory %s...", remote_path
);
1327 if (has_spaces
|| bucket
->strict_rfc959_list_cmd
|| ftpfs_first_cd_then_ls
) {
1330 p
= translate_path (bucket
, remote_path
);
1331 if (ftpfs_chdir_internal (bucket
, p
) != COMPLETE
) {
1333 print_vfs_message("ftpfs: CWD failed.");
1338 file_list
= linklist_init();
1339 if (file_list
== NULL
)
1340 ERRNOR (ENOMEM
, NULL
);
1341 dcache
= g_new (struct dir
, 1);
1342 if (dcache
== NULL
) {
1344 linklist_destroy(file_list
, NULL
);
1345 print_vfs_message("ftpfs: FAIL");
1348 gettimeofday(&dcache
->timestamp
, NULL
);
1349 dcache
->timestamp
.tv_sec
+= ftpfs_directory_timeout
;
1350 dcache
->file_list
= file_list
;
1351 dcache
->remote_path
= g_strdup(remote_path
);
1353 dcache
->symlink_status
= FTPFS_NO_SYMLINKS
;
1355 if (bucket
->strict_rfc959_list_cmd
== 1)
1356 sock
= open_data_connection (bucket
, "LIST", 0, TYPE_ASCII
, 0);
1357 else if (has_spaces
|| ftpfs_first_cd_then_ls
)
1358 sock
= open_data_connection (bucket
, "LIST -la", ".", TYPE_ASCII
, 0);
1360 /* Trailing "/." is necessary if remote_path is a symlink
1361 but don't generate "//." */
1362 char *path
= g_strconcat (remote_path
,
1363 remote_path
[1] == '\0' ? "" : PATH_SEP_STR
,
1366 sock
= open_data_connection (bucket
, "LIST -la", path
, TYPE_ASCII
, 0);
1374 #define close_this_sock(x,y) fclose (x)
1375 fp
= fdopen(sock
, "r");
1382 #define close_this_sock(x,y) close (y)
1385 /* Clear the interrupt flag */
1386 enable_interrupt_key ();
1390 while (fgets (buffer
, sizeof (buffer
), fp
) != NULL
) {
1391 if (got_intr
= got_interrupt ())
1394 while ((got_intr
= get_line_interruptible (buffer
, sizeof (buffer
), sock
)) != EINTR
){
1396 int eof
= got_intr
== 0;
1399 fputs (buffer
, logfile
);
1400 fputs ("\n", logfile
);
1403 if (buffer
[0] == 0 && eof
)
1405 fe
= g_new (struct direntry
, 1);
1406 fe
->freshly_created
= 0;
1407 fe
->local_filename
= NULL
;
1412 if (vfs_parse_ls_lga (buffer
, &fe
->s
, &fe
->name
, &fe
->linkname
)) {
1413 if (strcmp (fe
->name
, ".") == 0)
1416 fe
->local_filename
= fe
->remote_filename
= NULL
;
1418 fe
->bucket
= bucket
;
1419 (fe
->s
).st_ino
= bucket
->__inode_counter
++;
1420 if (S_ISLNK(fe
->s
.st_mode
))
1423 if (!linklist_insert(file_list
, fe
)) {
1435 disable_interrupt_key();
1436 print_vfs_message("ftpfs: reading FTP directory interrupt by user");
1438 my_abort(bucket
, fileno(fp
));
1440 my_abort(bucket
, sock
);
1442 close_this_sock(fp
, sock
);
1446 close_this_sock(fp
, sock
);
1447 disable_interrupt_key();
1448 if ((get_reply (qsock (bucket
), NULL
, 0) != COMPLETE
) ||
1449 (file_list
->next
== file_list
))
1453 insert_dots (file_list
, bucket
);
1455 if (!linklist_insert(qdcache(bucket
), dcache
)) {
1460 if (resolve_symlinks
)
1461 resolve_symlink(bucket
, dcache
);
1463 dcache
->symlink_status
= FTPFS_UNRESOLVED_SYMLINKS
;
1465 print_vfs_message("ftpfs: got listing");
1468 disable_interrupt_key();
1469 close_this_sock(fp
, sock
);
1473 get_reply(qsock(bucket
), NULL
, 0);
1475 g_free(dcache
->remote_path
);
1477 linklist_destroy(file_list
, direntry_destructor
);
1478 print_vfs_message("ftpfs: failed");
1482 if (bucket
->__inode_counter
== 0 && (!bucket
->strict_rfc959_list_cmd
)) {
1483 /* It's our first attempt to get a directory listing from this
1484 server (UNIX style LIST command) */
1485 bucket
->strict_rfc959_list_cmd
= 1;
1486 g_free(dcache
->remote_path
);
1488 linklist_destroy(file_list
, direntry_destructor
);
1489 return retrieve_dir (bucket
, remote_path
, resolve_symlinks
);
1492 g_free(dcache
->remote_path
);
1494 linklist_destroy(file_list
, direntry_destructor
);
1495 print_vfs_message("ftpfs: failed; nowhere to fallback to");
1500 store_file(struct direntry
*fe
)
1502 int local_handle
, sock
, n
, total
;
1503 #ifdef HAVE_STRUCT_LINGER
1511 local_handle
= open(fe
->local_filename
, O_RDONLY
);
1512 unlink (fe
->local_filename
);
1513 if (local_handle
== -1)
1515 fstat(local_handle
, &s
);
1516 sock
= open_data_connection(fe
->bucket
, "STOR", fe
->remote_filename
, TYPE_BINARY
, 0);
1518 close(local_handle
);
1521 #ifdef HAVE_STRUCT_LINGER
1524 setsockopt(sock
, SOL_SOCKET
, SO_LINGER
, (char *) &li
, sizeof(li
));
1526 setsockopt(sock
, SOL_SOCKET
, SO_LINGER
, &flag_one
, sizeof (flag_one
));
1530 enable_interrupt_key();
1532 while ((n
= read(local_handle
, buffer
, sizeof(buffer
))) < 0) {
1533 if (errno
== EINTR
) {
1534 if (got_interrupt()) {
1546 while (write(sock
, buffer
, n
) < 0) {
1547 if (errno
== EINTR
) {
1548 if (got_interrupt()) {
1559 print_vfs_message("ftpfs: storing file %d (%d)",
1562 disable_interrupt_key();
1564 close(local_handle
);
1565 if (get_reply (qsock (fe
->bucket
), NULL
, 0) != COMPLETE
)
1569 disable_interrupt_key();
1571 close(local_handle
);
1572 get_reply(qsock(fe
->bucket
), NULL
, 0);
1577 linear_start(struct direntry
*fe
, int offset
)
1579 fe
->local_stat
.st_mtime
= 0;
1580 fe
->data_sock
= open_data_connection(fe
->bucket
, "RETR", fe
->remote_filename
, TYPE_BINARY
, offset
);
1581 if (fe
->data_sock
== -1)
1583 fe
->linear_state
= LS_LINEAR_OPEN
;
1588 linear_abort (struct direntry
*fe
)
1590 my_abort(fe
->bucket
, fe
->data_sock
);
1595 linear_read (struct direntry
*fe
, void *buf
, int len
)
1598 while ((n
= read (fe
->data_sock
, buf
, len
))<0) {
1599 if ((errno
== EINTR
) && !got_interrupt())
1608 if ((get_reply (qsock (fe
->bucket
), NULL
, 0) != COMPLETE
)) {
1612 close (fe
->data_sock
);
1619 linear_close (struct direntry
*fe
)
1621 if (fe
->data_sock
!= -1)
1625 int ftpfs_ctl (void *data
, int ctlop
, int arg
)
1627 struct filp
*fp
= data
;
1629 case MCCTL_IS_NOTREADY
:
1633 if (!fp
->fe
->linear_state
)
1634 vfs_die ("You may not do this");
1635 if (fp
->fe
->linear_state
== LS_LINEAR_CLOSED
)
1638 v
= select_on_two (fp
->fe
->data_sock
, 0);
1639 if (((v
< 0) && (errno
== EINTR
)) || v
== 0)
1649 send_ftp_command(char *filename
, char *cmd
, int flags
)
1651 char *remote_path
, *p
;
1652 struct connection
*bucket
;
1654 int flush_directory_cache
= (flags
& OPT_FLUSH
) && (normal_flush
> 0);
1656 if (!(remote_path
= get_path(&bucket
, filename
)))
1658 p
= translate_path (bucket
, remote_path
);
1659 r
= command (bucket
, WAIT_REPLY
, cmd
, p
);
1660 g_free(remote_path
);
1661 vfs_add_noncurrent_stamps (&vfs_ftpfs_ops
, (vfsid
) bucket
, NULL
);
1662 if (flags
& OPT_IGNORE_ERROR
)
1666 if (flush_directory_cache
)
1667 flush_all_directory(bucket
);
1671 /* This routine is called as the last step in load_setup */
1673 ftpfs_init_passwd(void)
1675 struct passwd
*passwd_info
;
1676 char *p
, hostname
[MAXHOSTNAMELEN
];
1679 ftpfs_anonymous_passwd
= load_anon_passwd ();
1680 if (ftpfs_anonymous_passwd
)
1683 if ((passwd_info
= getpwuid (geteuid ())) == NULL
)
1686 p
= passwd_info
->pw_name
;
1687 gethostname(hostname
, sizeof(hostname
));
1688 hp
= gethostbyname(hostname
);
1690 ftpfs_anonymous_passwd
= g_strconcat (p
, "@", hp
->h_name
, NULL
);
1692 ftpfs_anonymous_passwd
= g_strconcat (p
, "@", hostname
, NULL
);
1697 ftpfs_init (vfs
*me
)
1699 connections_list
= linklist_init();
1700 ftpfs_directory_timeout
= FTPFS_DIRECTORY_TIMEOUT
;
1704 static int ftpfs_chmod (vfs
*me
, char *path
, int mode
)
1706 char buf
[BUF_SMALL
];
1708 g_snprintf(buf
, sizeof(buf
), "SITE CHMOD %4.4o %%s", mode
& 07777);
1709 return send_ftp_command(path
, buf
, OPT_IGNORE_ERROR
| OPT_FLUSH
);
1712 static int ftpfs_chown (vfs
*me
, char *path
, int owner
, int group
)
1718 /* Everyone knows it is not possible to chown remotely, so why bother them.
1719 If someone's root, then copy/move will always try to chown it... */
1724 static int ftpfs_unlink (vfs
*me
, char *path
)
1726 return send_ftp_command(path
, "DELE %s", OPT_FLUSH
);
1729 /* Return true if path is the same directoy as the one we are on now */
1731 is_same_dir (char *path
, struct connection
*bucket
)
1733 if (!qcdir (bucket
))
1735 if (strcmp (path
, qcdir (bucket
)) == 0)
1741 ftpfs_chdir_internal (struct connection
*bucket
,char *remote_path
)
1746 if (!bucket
->cwd_defered
&& is_same_dir (remote_path
, bucket
))
1749 p
= translate_path (bucket
, remote_path
);
1750 r
= command (bucket
, WAIT_REPLY
, "CWD %s", p
);
1752 if (r
!= COMPLETE
) {
1756 g_free(qcdir(bucket
));
1757 qcdir(bucket
) = g_strdup (remote_path
);
1758 bucket
->cwd_defered
= 0;
1763 static int ftpfs_rename (vfs
*me
, char *path1
, char *path2
)
1765 send_ftp_command(path1
, "RNFR %s", OPT_FLUSH
);
1766 return send_ftp_command(path2
, "RNTO %s", OPT_FLUSH
);
1769 static int ftpfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
1771 return send_ftp_command(path
, "MKD %s", OPT_FLUSH
);
1774 static int ftpfs_rmdir (vfs
*me
, char *path
)
1776 return send_ftp_command(path
, "RMD %s", OPT_FLUSH
);
1779 void ftpfs_set_debug (char *file
)
1781 logfile
= fopen (file
, "w+");
1784 static void my_forget (char *file
)
1787 char *host
, *user
, *pass
, *rp
;
1790 #ifndef BROKEN_PATHS
1791 if (strncmp (file
, "/#ftp:", 6))
1792 return; /* Normal: consider cd /bla/#ftp */
1794 if (!(file
= strstr (file
, "/#ftp:")))
1799 if (!(rp
= my_get_host_and_username (file
, &host
, &user
, &port
, &pass
))) {
1803 wipe_password (pass
);
1807 /* we do not care about the path actually */
1810 for (l
= connections_list
->next
; l
!= connections_list
; l
= l
->next
){
1811 struct connection
*bucket
= l
->data
;
1813 if ((strcmp (host
, qhost (bucket
)) == 0) &&
1814 (strcmp (user
, quser (bucket
)) == 0) &&
1815 (port
== qport (bucket
))){
1817 /* close socket: the child owns it now */
1818 close (bucket
->sock
);
1821 /* reopen the connection */
1822 bucket
->sock
= ftpfs_open_socket (bucket
);
1823 if (bucket
->sock
!= -1)
1824 login_server (bucket
, pass
);
1831 wipe_password (pass
);
1834 vfs vfs_ftpfs_ops
= {
1835 NULL
, /* This is place of next pointer */
1836 "File Tranfer Protocol (ftp)",
1838 "ftp:", /* prefix */
1862 ftpfs_chown
, /* not really implemented but returns success */
1892 static char buffer
[BUF_MEDIUM
];
1893 static char *netrc
, *netrcp
;
1895 static int netrc_next (void)
1899 static char *keywords
[] = { "default", "machine",
1900 "login", "password", "passwd",
1901 "account", "macdef" };
1904 netrcp
= skip_separators (netrcp
);
1905 if (*netrcp
!= '\n')
1912 if (*netrcp
== '"') {
1913 for (;*netrcp
!= '"' && *netrcp
; netrcp
++) {
1914 if (*netrcp
== '\\')
1919 for (;*netrcp
!= '\n' && *netrcp
!= '\t' && *netrcp
!= ' ' &&
1920 *netrcp
!= ',' && *netrcp
; netrcp
++) {
1921 if (*netrcp
== '\\')
1929 for (i
= 0; i
< sizeof (keywords
) / sizeof (keywords
[0]); i
++)
1930 if (!strcmp (keywords
[i
], buffer
))
1935 int lookup_netrc (char *host
, char **login
, char **pass
)
1937 char *netrcname
, *tmp
;
1938 char hostname
[MAXHOSTNAMELEN
], *domain
;
1941 static int be_angry
= 1;
1942 static struct rupcache
{
1943 struct rupcache
*next
;
1947 } *rup_cache
= NULL
, *rupp
;
1949 for (rupp
= rup_cache
; rupp
!= NULL
; rupp
= rupp
->next
)
1950 if (!strcmp (host
, rupp
->host
)) {
1951 if (rupp
->login
!= NULL
)
1952 *login
= g_strdup (rupp
->login
);
1953 if (rupp
->pass
!= NULL
)
1954 *pass
= g_strdup (rupp
->pass
);
1957 netrcname
= concat_dir_and_file (home_dir
, ".netrc");
1958 netrcp
= netrc
= load_file (netrcname
);
1959 if (netrc
== NULL
) {
1963 if (gethostname (hostname
, sizeof (hostname
)) < 0)
1965 if (!(domain
= strchr (hostname
, '.')))
1968 while ((keyword
= netrc_next ())) {
1970 if (netrc_next () != 8)
1972 if (g_strcasecmp (host
, buffer
) &&
1973 ((tmp
= strchr (host
, '.')) == NULL
||
1974 g_strcasecmp (tmp
, domain
) ||
1975 g_strncasecmp (host
, buffer
, tmp
- host
) ||
1976 buffer
[tmp
- host
]))
1978 } else if (keyword
!= 1)
1980 while ((keyword
= netrc_next ()) > 2) {
1985 *login
= g_strdup (buffer
);
1986 else if (strcmp (*login
, buffer
))
1991 if (strcmp (*login
, "anonymous") && strcmp (*login
, "ftp") &&
1992 stat (netrcname
, &mystat
) >= 0 &&
1993 (mystat
.st_mode
& 077)) {
1995 message_1s (1, MSG_ERROR
, _("~/.netrc file has not correct mode.\n"
1996 "Remove password or correct mode."));
2003 if (netrc_next () && *pass
== NULL
)
2004 *pass
= g_strdup (buffer
);
2007 if (stat (netrcname
, &mystat
) >= 0 &&
2008 (mystat
.st_mode
& 077)) {
2010 message_1s (1, MSG_ERROR
, _("~/.netrc file has not correct mode.\n"
2011 "Remove password or correct mode."));
2022 while (*netrcp
!= '\n' && *netrcp
);
2023 if (*netrcp
!= '\n')
2026 if (*netrcp
== '\n' || !*netrcp
)
2039 rupp
= g_new (struct rupcache
, 1);
2040 rupp
->host
= g_strdup (host
);
2041 rupp
->login
= rupp
->pass
= 0;
2044 rupp
->login
= g_strdup (*login
);
2046 rupp
->pass
= g_strdup (*pass
);
2047 rupp
->next
= rup_cache
;
2055 #endif /* USE_NETRC */