# HG changeset patch # User masneyb # Date 1204633720 0 # Node ID c7d7a081cd9c0191ccb602ddfeb12e0265e2781a # Parent 9a6571938f89d03aef9acaf5c21ccfe296195039 2008-03-04 Brian Masney * lib/gftp.h lib/socket-connect.c lib/sockutils.c lib/protocols.c lib/Makefile.am lib/charset-conv.c lib/parse-dir-listing.c - split protocols.c into smaller files. No changes were made to the moved functions. diff -r 9a6571938f89 -r c7d7a081cd9c ChangeLog --- a/ChangeLog Tue Mar 04 12:02:47 2008 +0000 +++ b/ChangeLog Tue Mar 04 12:28:40 2008 +0000 @@ -1,4 +1,9 @@ 2008-03-04 Brian Masney + * lib/gftp.h lib/socket-connect.c lib/sockutils.c lib/protocols.c + lib/Makefile.am lib/charset-conv.c lib/parse-dir-listing.c - split + protocols.c into smaller files. No changes were made to the moved + functions. + * lib/rfc959.c - removed unneeded FIXME comment * lib/ftps.c - removed uncommented code diff -r 9a6571938f89 -r c7d7a081cd9c lib/Makefile.am --- a/lib/Makefile.am Tue Mar 04 12:02:47 2008 +0000 +++ b/lib/Makefile.am Tue Mar 04 12:28:40 2008 +0000 @@ -2,8 +2,9 @@ SUBDIRS=fsplib noinst_LIBRARIES = libgftp.a -libgftp_a_SOURCES=bookmark.c cache.c config_file.c fsp.c ftps.c https.c \ - local.c misc.c mkstemps.c protocols.c pty.c rfc959.c \ - rfc2068.c sshv2.c sslcommon.c +libgftp_a_SOURCES=bookmark.c cache.c charset-conv.c config_file.c fsp.c ftps.c \ + https.c local.c misc.c mkstemps.c parse-dir-listing.c \ + protocols.c pty.c rfc959.c rfc2068.c sshv2.c sslcommon.c \ + socket-connect.c sockutils.c INCLUDES=@GLIB_CFLAGS@ @PTHREAD_CFLAGS@ -I../intl -DSHARE_DIR=\"$(datadir)/gftp\" -DLOCALE_DIR=\"$(datadir)/locale\" noinst_HEADERS=gftp.h ftpcommon.h httpcommon.h options.h diff -r 9a6571938f89 -r c7d7a081cd9c lib/charset-conv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/charset-conv.c Tue Mar 04 12:28:40 2008 +0000 @@ -0,0 +1,263 @@ +/*****************************************************************************/ +/* charset-conv.c - contains functions for performing conversions between */ +/* character sets. */ +/* Copyright (C) 1998-2008 Brian Masney */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ +/*****************************************************************************/ + +#include "gftp.h" +static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $"; + +#if GLIB_MAJOR_VERSION > 1 + +static /*@null@*/ char * +_gftp_get_next_charset (char **curpos) +{ + char *ret, *endpos; + size_t len, retlen; + + if (**curpos == '\0') + return (NULL); + + for (; **curpos == ' ' || **curpos == '\t'; (*curpos)++); + + if ((endpos = strchr (*curpos, ',')) == NULL) + len = strlen (*curpos) - 1; /* the trailing ',' should be omitted */ + else + len = endpos - *curpos; + + for (retlen = len - 1; + (*curpos)[retlen - 1] == ' ' || (*curpos)[retlen - 1] == '\t'; + retlen--); + + retlen++; /* Needed due to the len - 1 above... */ + ret = g_malloc0 (retlen + 1); + memcpy (ret, *curpos, retlen); + + for (*curpos += len; **curpos == ','; (*curpos)++); + + return (ret); +} + + +static void +_do_show_iconv_error (const char *str, char *charset, int from_utf8, + GError * error) +{ + const char *fromset, *toset; + + if (from_utf8) + { + fromset = "UTF-8"; + toset = charset; + } + else + { + fromset = charset; + toset = "UTF-8"; + } + + printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"), + str, fromset, toset, error->message); +} + + +/*@null@*/ static char * +_do_convert_string (gftp_request * request, int is_filename, int force_local, + const char *str, size_t *dest_len, int from_utf8) +{ + char *remote_charsets, *ret, *fromset, *toset, *stpos, *cur_charset; + GError * error; + gsize bread; + + if (request == NULL) + return (NULL); + + if (g_utf8_validate (str, -1, NULL) != from_utf8) + return (NULL); + + error = NULL; + gftp_lookup_request_option (request, "remote_charsets", &remote_charsets); + if (*remote_charsets == '\0' || request->use_local_encoding || + force_local == 1) + { + if (from_utf8) + { + if (is_filename) + ret = g_filename_from_utf8 (str, -1, &bread, dest_len, &error); + else + ret = g_locale_from_utf8 (str, -1, &bread, dest_len, &error); + } + else + { + if (is_filename) + ret = g_filename_to_utf8 (str, -1, &bread, dest_len, &error); + else + ret = g_locale_to_utf8 (str, -1, &bread, dest_len, &error); + } + + if (ret == NULL) + _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); + + return (ret); + } + + if (from_utf8) + { + if (request->iconv_from_initialized) + { + ret = g_convert_with_iconv (str, -1, request->iconv_from, &bread, dest_len, + &error); + if (ret == NULL) + _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); + + return (ret); + } + } + else + { + if (request->iconv_to_initialized) + { + ret = g_convert_with_iconv (str, -1, request->iconv_to, &bread, dest_len, + &error); + if (ret == NULL) + _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); + + return (ret); + } + } + + stpos = remote_charsets; + while ((cur_charset = _gftp_get_next_charset (&stpos)) != NULL) + { + if (from_utf8) + { + fromset = "UTF-8"; + toset = cur_charset; + if ((request->iconv_from = g_iconv_open (toset, fromset)) == (GIConv) -1) + { + g_free (cur_charset); + continue; + } + + error = NULL; + if ((ret = g_convert_with_iconv (str, -1, request->iconv_from, &bread, + dest_len, &error)) == NULL) + { + g_iconv_close (request->iconv_from); + request->iconv_from = NULL; + _do_show_iconv_error (str, cur_charset, from_utf8, error); + g_free (cur_charset); + continue; + } + + request->iconv_from_initialized = 1; + } + else + { + fromset = cur_charset; + toset = "UTF-8"; + if ((request->iconv_to = g_iconv_open (toset, fromset)) == (GIConv) -1) + { + g_free (cur_charset); + continue; + } + + error = NULL; + if ((ret = g_convert_with_iconv (str, -1, request->iconv_to, &bread, + dest_len, &error)) == NULL) + { + g_iconv_close (request->iconv_to); + request->iconv_to = NULL; + _do_show_iconv_error (str, cur_charset, from_utf8, error); + g_free (cur_charset); + continue; + } + + request->iconv_to_initialized = 1; + } + + request->iconv_charset = cur_charset; + return (ret); + } + + return (NULL); +} + +char * +gftp_string_to_utf8 (gftp_request * request, const char *str, size_t *dest_len) +{ + return (_do_convert_string (request, 0, 0, str, dest_len, 0)); +} + + +char * +gftp_string_from_utf8 (gftp_request * request, int force_local, const char *str, + size_t *dest_len) +{ + return (_do_convert_string (request, 0, force_local, str, dest_len, 1)); +} + + +char * +gftp_filename_to_utf8 (gftp_request * request, const char *str, + size_t *dest_len) +{ + return (_do_convert_string (request, 1, 0, str, dest_len, 0)); +} + + +char * +gftp_filename_from_utf8 (gftp_request * request, const char *str, + size_t *dest_len) +{ + return (_do_convert_string (request, 1, 0, str, dest_len, 1)); +} + +#else + +char * +gftp_string_to_utf8 (gftp_request * request, const char *str, size_t dest_len) +{ + return (NULL); +} + + +char * +gftp_string_from_utf8 (gftp_request * request, int force_local, const char *str, + size_t dest_len) +{ + return (NULL); +} + + +char * +gftp_filename_to_utf8 (gftp_request * request, const char *str, size_t dest_len) +{ + return (NULL); +} + + +char * +gftp_filename_from_utf8 (gftp_request * request, int force_local, + const char *str, size_t dest_len) +{ + return (NULL); +} + +#endif + + diff -r 9a6571938f89 -r c7d7a081cd9c lib/gftp.h --- a/lib/gftp.h Tue Mar 04 12:02:47 2008 +0000 +++ b/lib/gftp.h Tue Mar 04 12:28:40 2008 +0000 @@ -668,6 +668,24 @@ char *descr, int ignore_directory ); +/* charset-conv.c */ +/*@null@*/ char * gftp_string_to_utf8 ( gftp_request * request, + const char *str, + size_t *dest_len ); + +/*@null@*/ char * gftp_string_from_utf8 ( gftp_request * request, + int force_local, + const char *str, + size_t *dest_len ); + +/*@null@*/ char * gftp_filename_to_utf8 ( gftp_request * request, + const char *str, + size_t *dest_len ); + +/*@null@*/ char * gftp_filename_from_utf8 ( gftp_request * request, + const char *str, + size_t *dest_len ); + /* config_file.c */ int gftp_config_parse_args ( char *str, int numargs, @@ -812,6 +830,15 @@ int mkstemps ( char *template, int suffix_len ); +/* parse-dir-listing.c */ +time_t parse_time ( char *str, + char **endpos ); + +int gftp_parse_ls ( gftp_request * request, + const char *lsoutput, + gftp_file *fle, + int fd ); + /* protocols.c */ #define GFTP_FTP_NUM 0 #define GFTP_FTPS_NUM 1 @@ -909,23 +936,6 @@ int gftp_list_files ( gftp_request * request ); -/*@null@*/ char * gftp_string_to_utf8 ( gftp_request * request, - const char *str, - size_t *dest_len ); - -/*@null@*/ char * gftp_string_from_utf8 ( gftp_request * request, - int force_local, - const char *str, - size_t *dest_len ); - -/*@null@*/ char * gftp_filename_to_utf8 ( gftp_request * request, - const char *str, - size_t *dest_len ); - -/*@null@*/ char * gftp_filename_from_utf8 ( gftp_request * request, - const char *str, - size_t *dest_len ); - int gftp_parse_bookmark ( gftp_request * request, gftp_request * local_request, const char * bookmark, @@ -996,23 +1006,10 @@ void gftp_calc_kbs ( gftp_transfer * tdata, ssize_t num_read ); -time_t parse_time ( char *str, - char **endpos ); - -int gftp_parse_ls ( gftp_request * request, - const char *lsoutput, - gftp_file *fle, - int fd ); - int gftp_get_all_subdirs ( gftp_transfer * transfer, void (*update_func) ( gftp_transfer * transfer )); -int gftp_connect_server ( gftp_request * request, - char *service, - char *proxy_hostname, - unsigned int proxy_port ); - struct hostent *r_gethostbyname ( const char *name, struct hostent *result_buf, int *h_errnop ); @@ -1026,33 +1023,6 @@ void print_file_list ( GList * list ); -void gftp_free_getline_buffer ( gftp_getline_buffer ** rbuf ); - -ssize_t gftp_get_line ( gftp_request * request, - /*@out@*/ gftp_getline_buffer ** rbuf, - /*@out@*/ char * str, - size_t len, - int fd ); - -ssize_t gftp_fd_read ( gftp_request * request, - void *ptr, - size_t size, - int fd ); - -ssize_t gftp_fd_write ( gftp_request * request, - const char *ptr, - size_t size, - int fd ); - -ssize_t gftp_writefmt ( gftp_request * request, - int fd, - const char *fmt, - ... ); - -int gftp_fd_set_sockblocking ( gftp_request * request, - int fd, - int non_blocking ); - void gftp_swap_socks ( gftp_request * dest, gftp_request * source ); @@ -1118,3 +1088,37 @@ #endif +/* socket-connect.c */ +int gftp_connect_server ( gftp_request * request, + char *service, + char *proxy_hostname, + unsigned int proxy_port ); + +/* sockutils.c */ +ssize_t gftp_get_line ( gftp_request * request, + /*@out@*/ gftp_getline_buffer ** rbuf, + /*@out@*/ char * str, + size_t len, + int fd ); + +void gftp_free_getline_buffer ( gftp_getline_buffer ** rbuf ); + +ssize_t gftp_fd_read ( gftp_request * request, + void *ptr, + size_t size, + int fd ); + +ssize_t gftp_fd_write ( gftp_request * request, + const char *ptr, + size_t size, + int fd ); + +ssize_t gftp_writefmt ( gftp_request * request, + int fd, + const char *fmt, + ... ); + +int gftp_fd_set_sockblocking ( gftp_request * request, + int fd, + int non_blocking ); + diff -r 9a6571938f89 -r c7d7a081cd9c lib/parse-dir-listing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/parse-dir-listing.c Tue Mar 04 12:28:40 2008 +0000 @@ -0,0 +1,655 @@ +/*****************************************************************************/ +/* parse-dir-listing.c - contains functions for parsing the different types */ +/* of directory listings. */ +/* Copyright (C) 1998-2008 Brian Masney */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ +/*****************************************************************************/ + +#include "gftp.h" +static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $"; + +static char * +copy_token (/*@out@*/ char **dest, char *source) +{ + char *endpos, savepos; + + endpos = source; + while (*endpos != ' ' && *endpos != '\t' && *endpos != '\0') + endpos++; + if (*endpos == '\0') + { + *dest = NULL; + return (NULL); + } + + savepos = *endpos; + *endpos = '\0'; + *dest = g_malloc0 ((gulong) (endpos - source + 1)); + strcpy (*dest, source); + *endpos = savepos; + + /* Skip the blanks till we get to the next entry */ + source = endpos + 1; + while ((*source == ' ' || *source == '\t') && *source != '\0') + source++; + return (source); +} + + +static char * +goto_next_token (char *pos) +{ + while (*pos != ' ' && *pos != '\t' && *pos != '\0') + pos++; + + while (*pos == ' ' || *pos == '\t') + pos++; + + return (pos); +} + + +static time_t +parse_vms_time (char *str, char **endpos) +{ + struct tm curtime; + time_t ret; + + /* 8-JUN-2004 13:04:14 */ + memset (&curtime, 0, sizeof (curtime)); + + *endpos = strptime (str, "%d-%b-%Y %H:%M:%S", &curtime); + if (*endpos == NULL) + *endpos = strptime (str, "%d-%b-%Y %H:%M", &curtime); + + if (*endpos != NULL) + { + ret = mktime (&curtime); + for (; **endpos == ' ' || **endpos == '\t'; (*endpos)++); + } + else + { + ret = 0; + *endpos = goto_next_token (str); + if (*endpos != NULL) + *endpos = goto_next_token (*endpos); + } + + return (ret); +} + + +time_t +parse_time (char *str, char **endpos) +{ + struct tm curtime, *loctime; + time_t t, ret; + char *tmppos; + size_t slen; + int i, num; + + slen = strlen (str); + memset (&curtime, 0, sizeof (curtime)); + curtime.tm_isdst = -1; + + if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && + isdigit ((int) str[3])) + { + /* This is how DOS will return the date/time */ + /* 07-06-99 12:57PM */ + + tmppos = strptime (str, "%m-%d-%y %I:%M%p", &curtime); + } + else if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && + isalpha (str[3])) + { + /* 10-Jan-2003 09:14 */ + tmppos = strptime (str, "%d-%h-%Y %H:%M", &curtime); + } + else if (slen > 4 && isdigit ((int) str[0]) && str[4] == '/') + { + /* 2003/12/25 */ + tmppos = strptime (str, "%Y/%m/%d", &curtime); + } + else + { + /* This is how most UNIX, Novell, and MacOS ftp servers send their time */ + /* Jul 06 12:57 or Jul 6 1999 */ + + if (strchr (str, ':') != NULL) + { + tmppos = strptime (str, "%h %d %H:%M", &curtime); + t = time (NULL); + loctime = localtime (&t); + + if (curtime.tm_mon > loctime->tm_mon) + curtime.tm_year = loctime->tm_year - 1; + else + curtime.tm_year = loctime->tm_year; + } + else + tmppos = strptime (str, "%h %d %Y", &curtime); + } + + if (tmppos != NULL) + ret = mktime (&curtime); + else + ret = 0; + + if (endpos != NULL) + { + if (tmppos == NULL) + { + /* We cannot parse this date format. So, just skip this date field + and continue to the next token. This is mainly for the HTTP + support */ + + *endpos = str; + for (num = 0; num < 2 && **endpos != '\0'; num++) + { + for (i=0; + (*endpos)[i] != ' ' && (*endpos)[i] != '\t' && + (*endpos)[i] != '\0'; + i++); + *endpos += i; + + for (i=0; (*endpos)[i] == ' ' || (*endpos)[i] == '\t'; i++); + *endpos += i; + } + } + else + *endpos = tmppos; + } + + return (ret); +} + + +static mode_t +gftp_parse_vms_attribs (char **src, mode_t mask) +{ + char *endpos; + mode_t ret; + + if (*src == NULL) + return (0); + + if ((endpos = strchr (*src, ',')) != NULL) + *endpos = '\0'; + + ret = 0; + if (strchr (*src, 'R') != NULL) + ret |= S_IRUSR | S_IRGRP | S_IROTH; + if (strchr (*src, 'W') != NULL) + ret |= S_IWUSR | S_IWGRP | S_IWOTH; + if (strchr (*src, 'E') != NULL) + ret |= S_IXUSR | S_IXGRP | S_IXOTH; + + *src = endpos + 1; + + return (ret & mask); +} + + +static int +gftp_parse_ls_vms (gftp_request * request, int fd, char *str, gftp_file * fle) +{ + char *curpos, *endpos, tempstr[1024]; + int multiline; + ssize_t len; + + /* .PINE-DEBUG1;1 9 21-AUG-2002 20:06 [MYERSRG] (RWED,RWED,,) */ + /* WWW.DIR;1 1 23-NOV-1999 05:47 [MYERSRG] (RWE,RWE,RE,E) */ + + /* Multiline VMS + $MAIN.TPU$JOURNAL;1 + 1/18 8-JUN-2004 13:04:14 [NUCLEAR,FISSION] (RWED,RWED,RE,) + TCPIP$FTP_SERVER.LOG;29 + 0/18 8-JUN-2004 14:42:04 [NUCLEAR,FISSION] (RWED,RWED,RE,) + TCPIP$FTP_SERVER.LOG;28 + 5/18 8-JUN-2004 13:05:11 [NUCLEAR,FISSION] (RWED,RWED,RE,) + TCPIP$FTP_SERVER.LOG;27 + 5/18 8-JUN-2004 13:03:51 [NUCLEAR,FISSION] (RWED,RWED,RE,) */ + + if ((curpos = strchr (str, ';')) == NULL) + return (GFTP_EFATAL); + + multiline = strchr (str, ' ') == NULL; + + *curpos = '\0'; + if (strlen (str) > 4 && strcmp (curpos - 4, ".DIR") == 0) + { + fle->st_mode |= S_IFDIR; + *(curpos - 4) = '\0'; + } + + fle->file = g_strdup (str); + + if (multiline) + { + if (request->get_next_dirlist_line == NULL) + return (GFTP_EFATAL); + + len = request->get_next_dirlist_line (request, fd, tempstr, + sizeof (tempstr)); + if (len <= 0) + return ((int) len); + + for (curpos = tempstr; *curpos == ' ' || *curpos == '\t'; curpos++); + } + else + curpos = goto_next_token (curpos + 1); + + fle->size = gftp_parse_file_size (curpos) * 512; /* Is this correct? */ + + curpos = goto_next_token (curpos); + + fle->datetime = parse_vms_time (curpos, &curpos); + + if (*curpos != '[') + return (GFTP_EFATAL); + + if ((endpos = strchr (curpos, ']')) == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (endpos + 1); + if ((curpos = strchr (curpos, ',')) == NULL) + return (0); + curpos++; + + fle->st_mode = gftp_parse_vms_attribs (&curpos, S_IRWXU); + fle->st_mode |= gftp_parse_vms_attribs (&curpos, S_IRWXG); + fle->st_mode |= gftp_parse_vms_attribs (&curpos, S_IRWXO); + + fle->user = g_strdup (""); + fle->group = g_strdup (""); + + return (0); +} + + +static int +gftp_parse_ls_mvs (char *str, gftp_file * fle) +{ + char *curpos; + + /* Volume Unit Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname */ + /* SVI52A 3390 2003/12/10 8 216 FB 80 27920 PS CARDS.DELETES */ + /* SVI528 3390 2003/12/12 1 5 FB 80 24000 PO CLIST */ + + curpos = goto_next_token (str + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + fle->datetime = parse_time (curpos, &curpos); + + curpos = goto_next_token (curpos); + if (curpos == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + fle->size = gftp_parse_file_size (curpos) * 55996; + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + if (curpos == NULL) + return (GFTP_EFATAL); + + if (strncmp (curpos, "PS", 2) == 0) + fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + else if (strncmp (curpos, "PO", 2) == 0) + fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + else + return (GFTP_EFATAL); + + curpos = goto_next_token (curpos + 1); + + fle->user = g_strdup (_("unknown")); + fle->group = g_strdup (_("unknown")); + fle->file = g_strdup (curpos); + + return (0); +} + + +static int +gftp_parse_ls_eplf (char *str, gftp_file * fle) +{ + char *startpos; + int isdir = 0; + + startpos = str; + while (startpos) + { + startpos++; + switch (*startpos) + { + case '/': + isdir = 1; + break; + case 's': + fle->size = gftp_parse_file_size (startpos + 1); + break; + case 'm': + fle->datetime = strtol (startpos + 1, NULL, 10); + break; + } + startpos = strchr (startpos, ','); + } + + if ((startpos = strchr (str, 9)) == NULL) + return (GFTP_EFATAL); + + if (isdir) + fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + else + fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + + fle->file = g_strdup (startpos + 1); + fle->user = g_strdup (_("unknown")); + fle->group = g_strdup (_("unknown")); + return (0); +} + + +static int +gftp_parse_ls_unix (gftp_request * request, char *str, size_t slen, + gftp_file * fle) +{ + char *endpos, *startpos, *pos, *attribs; + int cols; + + /* If there is no space between the attribs and links field, just make one */ + if (slen > 10) + str[10] = ' '; + + /* Determine the number of columns */ + cols = 0; + pos = str; + while (*pos != '\0') + { + while (*pos != '\0' && *pos != ' ' && *pos != '\t') + { + if (*pos == ':') + break; + pos++; + } + + cols++; + + if (*pos == ':') + { + cols++; + break; + } + + while (*pos == ' ' || *pos == '\t') + pos++; + } + + startpos = str; + /* Copy file attributes */ + if ((startpos = copy_token (&attribs, startpos)) == NULL) + return (GFTP_EFATAL); + + if (strlen (attribs) < 10) + return (GFTP_EFATAL); + + fle->st_mode = gftp_convert_attributes_to_mode_t (attribs); + g_free (attribs); + + if (cols >= 9) + { + /* Skip the number of links */ + startpos = goto_next_token (startpos); + + /* Copy the user that owns this file */ + if ((startpos = copy_token (&fle->user, startpos)) == NULL) + return (GFTP_EFATAL); + + /* Copy the group that owns this file */ + if ((startpos = copy_token (&fle->group, startpos)) == NULL) + return (GFTP_EFATAL); + } + else + { + fle->group = g_strdup (_("unknown")); + if (cols == 8) + { + if ((startpos = copy_token (&fle->user, startpos)) == NULL) + return (GFTP_EFATAL); + } + else + fle->user = g_strdup (_("unknown")); + startpos = goto_next_token (startpos); + } + + if (request->server_type == GFTP_DIRTYPE_CRAY) + { + /* See if this is a Cray directory listing. It has the following format: + drwx------ 2 feiliu g913 DK common 4096 Sep 24 2001 wv */ + if (cols == 11 && strstr (str, "->") == NULL) + { + startpos = goto_next_token (startpos); + startpos = goto_next_token (startpos); + } + } + + /* See if this is a block or character device. We will store the major number + in the high word and the minor number in the low word. */ + if (GFTP_IS_SPECIAL_DEVICE (fle->st_mode) && + (endpos = strchr (startpos, ',')) != NULL) + { + fle->size = (unsigned long) strtol (startpos, NULL, 10) << 16; + + startpos = endpos + 1; + while (*startpos == ' ') + startpos++; + + /* Get the minor number */ + if ((endpos = strchr (startpos, ' ')) == NULL) + return (GFTP_EFATAL); + fle->size |= strtol (startpos, NULL, 10) & 0xFF; + } + else + { + /* This is a regular file */ + if ((endpos = strchr (startpos, ' ')) == NULL) + return (GFTP_EFATAL); + fle->size = gftp_parse_file_size (startpos); + } + + /* Skip the blanks till we get to the next entry */ + startpos = endpos + 1; + while (*startpos == ' ') + startpos++; + + fle->datetime = parse_time (startpos, &startpos); + + /* Skip the blanks till we get to the next entry */ + startpos = goto_next_token (startpos); + + /* Parse the filename. If this file is a symbolic link, remove the -> part */ + if (S_ISLNK (fle->st_mode) && ((endpos = strstr (startpos, "->")) != NULL)) + *(endpos - 1) = '\0'; + + fle->file = g_strdup (startpos); + + /* Uncomment this if you want to strip the spaces off of the end of the file. + I don't want to do this by default since there are valid filenames with + spaces at the end of them. Some broken FTP servers like the Paradyne IPC + DSLAMS append a bunch of spaces at the end of the file. + for (endpos = fle->file + strlen (fle->file) - 1; + *endpos == ' '; + *endpos-- = '\0'); + */ + + return (0); +} + + +static int +gftp_parse_ls_nt (char *str, gftp_file * fle) +{ + char *startpos; + + startpos = str; + fle->datetime = parse_time (startpos, &startpos); + + fle->user = g_strdup (_("unknown")); + fle->group = g_strdup (_("unknown")); + + startpos = goto_next_token (startpos); + + if (startpos[0] == '<') + fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + else + { + fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + fle->size = gftp_parse_file_size (startpos); + } + + startpos = goto_next_token (startpos); + fle->file = g_strdup (startpos); + return (0); +} + + +static int +gftp_parse_ls_novell (char *str, gftp_file * fle) +{ + char *startpos; + + if (str[12] != ' ') + return (GFTP_EFATAL); + + str[12] = '\0'; + fle->st_mode = gftp_convert_attributes_to_mode_t (str); + startpos = str + 13; + + while ((*startpos == ' ' || *startpos == '\t') && *startpos != '\0') + startpos++; + + if ((startpos = copy_token (&fle->user, startpos)) == NULL) + return (GFTP_EFATAL); + + fle->group = g_strdup (_("unknown")); + + while (*startpos != '\0' && !isdigit (*startpos)) + startpos++; + + fle->size = gftp_parse_file_size (startpos); + + startpos = goto_next_token (startpos); + fle->datetime = parse_time (startpos, &startpos); + + startpos = goto_next_token (startpos); + fle->file = g_strdup (startpos); + return (0); +} + + +int +gftp_parse_ls (gftp_request * request, const char *lsoutput, gftp_file * fle, + int fd) +{ + char *str, *endpos, tmpchar; + int result, is_vms; + size_t len; + + g_return_val_if_fail (lsoutput != NULL, GFTP_EFATAL); + g_return_val_if_fail (fle != NULL, GFTP_EFATAL); + + str = g_strdup (lsoutput); + memset (fle, 0, sizeof (*fle)); + + len = strlen (str); + if (len > 0 && str[len - 1] == '\n') + str[--len] = '\0'; + if (len > 0 && str[len - 1] == '\r') + str[--len] = '\0'; + + switch (request->server_type) + { + case GFTP_DIRTYPE_CRAY: + case GFTP_DIRTYPE_UNIX: + result = gftp_parse_ls_unix (request, str, len, fle); + break; + case GFTP_DIRTYPE_EPLF: + result = gftp_parse_ls_eplf (str, fle); + break; + case GFTP_DIRTYPE_NOVELL: + result = gftp_parse_ls_novell (str, fle); + break; + case GFTP_DIRTYPE_DOS: + result = gftp_parse_ls_nt (str, fle); + break; + case GFTP_DIRTYPE_VMS: + result = gftp_parse_ls_vms (request, fd, str, fle); + break; + case GFTP_DIRTYPE_MVS: + result = gftp_parse_ls_mvs (str, fle); + break; + default: /* autodetect */ + if (*lsoutput == '+') + result = gftp_parse_ls_eplf (str, fle); + else if (isdigit ((int) str[0]) && str[2] == '-') + result = gftp_parse_ls_nt (str, fle); + else if (str[1] == ' ' && str[2] == '[') + result = gftp_parse_ls_novell (str, fle); + else + { + if ((endpos = strchr (str, ' ')) != NULL) + { + /* If the first token in the string has a ; in it, then */ + /* we'll assume that this is a VMS directory listing */ + tmpchar = *endpos; + *endpos = '\0'; + is_vms = strchr (str, ';') != NULL; + *endpos = tmpchar; + } + else + is_vms = 0; + + if (is_vms) + result = gftp_parse_ls_vms (request, fd, str, fle); + else + result = gftp_parse_ls_unix (request, str, len, fle); + } + break; + } + g_free (str); + + return (result); +} + diff -r 9a6571938f89 -r c7d7a081cd9c lib/protocols.c --- a/lib/protocols.c Tue Mar 04 12:02:47 2008 +0000 +++ b/lib/protocols.c Tue Mar 04 12:28:40 2008 +0000 @@ -413,246 +413,6 @@ } -#if GLIB_MAJOR_VERSION > 1 - -static /*@null@*/ char * -_gftp_get_next_charset (char **curpos) -{ - char *ret, *endpos; - size_t len, retlen; - - if (**curpos == '\0') - return (NULL); - - for (; **curpos == ' ' || **curpos == '\t'; (*curpos)++); - - if ((endpos = strchr (*curpos, ',')) == NULL) - len = strlen (*curpos) - 1; /* the trailing ',' should be omitted */ - else - len = endpos - *curpos; - - for (retlen = len - 1; - (*curpos)[retlen - 1] == ' ' || (*curpos)[retlen - 1] == '\t'; - retlen--); - - retlen++; /* Needed due to the len - 1 above... */ - ret = g_malloc0 (retlen + 1); - memcpy (ret, *curpos, retlen); - - for (*curpos += len; **curpos == ','; (*curpos)++); - - return (ret); -} - - -static void -_do_show_iconv_error (const char *str, char *charset, int from_utf8, - GError * error) -{ - const char *fromset, *toset; - - if (from_utf8) - { - fromset = "UTF-8"; - toset = charset; - } - else - { - fromset = charset; - toset = "UTF-8"; - } - - printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"), - str, fromset, toset, error->message); -} - - -/*@null@*/ char * -_do_convert_string (gftp_request * request, int is_filename, int force_local, - const char *str, size_t *dest_len, int from_utf8) -{ - char *remote_charsets, *ret, *fromset, *toset, *stpos, *cur_charset; - GError * error; - gsize bread; - - if (request == NULL) - return (NULL); - - if (g_utf8_validate (str, -1, NULL) != from_utf8) - return (NULL); - - error = NULL; - gftp_lookup_request_option (request, "remote_charsets", &remote_charsets); - if (*remote_charsets == '\0' || request->use_local_encoding || - force_local == 1) - { - if (from_utf8) - { - if (is_filename) - ret = g_filename_from_utf8 (str, -1, &bread, dest_len, &error); - else - ret = g_locale_from_utf8 (str, -1, &bread, dest_len, &error); - } - else - { - if (is_filename) - ret = g_filename_to_utf8 (str, -1, &bread, dest_len, &error); - else - ret = g_locale_to_utf8 (str, -1, &bread, dest_len, &error); - } - - if (ret == NULL) - _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); - - return (ret); - } - - if (from_utf8) - { - if (request->iconv_from_initialized) - { - ret = g_convert_with_iconv (str, -1, request->iconv_from, &bread, dest_len, - &error); - if (ret == NULL) - _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); - - return (ret); - } - } - else - { - if (request->iconv_to_initialized) - { - ret = g_convert_with_iconv (str, -1, request->iconv_to, &bread, dest_len, - &error); - if (ret == NULL) - _do_show_iconv_error (str, request->iconv_charset, from_utf8, error); - - return (ret); - } - } - - stpos = remote_charsets; - while ((cur_charset = _gftp_get_next_charset (&stpos)) != NULL) - { - if (from_utf8) - { - fromset = "UTF-8"; - toset = cur_charset; - if ((request->iconv_from = g_iconv_open (toset, fromset)) == (GIConv) -1) - { - g_free (cur_charset); - continue; - } - - error = NULL; - if ((ret = g_convert_with_iconv (str, -1, request->iconv_from, &bread, - dest_len, &error)) == NULL) - { - g_iconv_close (request->iconv_from); - request->iconv_from = NULL; - _do_show_iconv_error (str, cur_charset, from_utf8, error); - g_free (cur_charset); - continue; - } - - request->iconv_from_initialized = 1; - } - else - { - fromset = cur_charset; - toset = "UTF-8"; - if ((request->iconv_to = g_iconv_open (toset, fromset)) == (GIConv) -1) - { - g_free (cur_charset); - continue; - } - - error = NULL; - if ((ret = g_convert_with_iconv (str, -1, request->iconv_to, &bread, - dest_len, &error)) == NULL) - { - g_iconv_close (request->iconv_to); - request->iconv_to = NULL; - _do_show_iconv_error (str, cur_charset, from_utf8, error); - g_free (cur_charset); - continue; - } - - request->iconv_to_initialized = 1; - } - - request->iconv_charset = cur_charset; - return (ret); - } - - return (NULL); -} - -char * -gftp_string_to_utf8 (gftp_request * request, const char *str, size_t *dest_len) -{ - return (_do_convert_string (request, 0, 0, str, dest_len, 0)); -} - - -char * -gftp_string_from_utf8 (gftp_request * request, int force_local, const char *str, - size_t *dest_len) -{ - return (_do_convert_string (request, 0, force_local, str, dest_len, 1)); -} - - -char * -gftp_filename_to_utf8 (gftp_request * request, const char *str, - size_t *dest_len) -{ - return (_do_convert_string (request, 1, 0, str, dest_len, 0)); -} - - -char * -gftp_filename_from_utf8 (gftp_request * request, const char *str, - size_t *dest_len) -{ - return (_do_convert_string (request, 1, 0, str, dest_len, 1)); -} - -#else - -char * -gftp_string_to_utf8 (gftp_request * request, const char *str, size_t dest_len) -{ - return (NULL); -} - - -char * -gftp_string_from_utf8 (gftp_request * request, int force_local, const char *str, - size_t dest_len) -{ - return (NULL); -} - - -char * -gftp_filename_to_utf8 (gftp_request * request, const char *str, size_t dest_len) -{ - return (NULL); -} - - -char * -gftp_filename_from_utf8 (gftp_request * request, int force_local, - const char *str, size_t dest_len) -{ - return (NULL); -} - -#endif - - int gftp_get_next_file (gftp_request * request, const char *filespec, gftp_file * fle) @@ -1157,746 +917,6 @@ } -/* FIXME - clean up this function */ -static int -gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname, - unsigned int proxy_port) -{ - gftp_config_list_vars * proxy_hosts; - gftp_proxy_hosts * hostname; - size_t hostlen, domlen; - unsigned char addy[4]; - struct sockaddr *addr; - GList * templist; - gint32 netaddr; - char *pos; -#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) - struct addrinfo hints, *hostp; - unsigned int port; - int errnum; - char serv[8]; -#else - struct hostent host, *hostp; -#endif - - gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts); - - if (proxy_hostname == NULL || *proxy_hostname == '\0') - return (0); - else if (proxy_hosts->list == NULL) - return (proxy_hostname != NULL && - *proxy_hostname != '\0'); - - hostp = NULL; -#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) - memset (&hints, 0, sizeof (hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - port = request->use_proxy ? proxy_port : request->port; - if (port == 0) - strcpy (serv, service); - else - snprintf (serv, sizeof (serv), "%d", port); - - request->logging_function (gftp_logging_misc, request, - _("Looking up %s\n"), request->hostname); - - if ((errnum = getaddrinfo (request->hostname, serv, &hints, - &hostp)) != 0) - { - request->logging_function (gftp_logging_error, request, - _("Cannot look up hostname %s: %s\n"), - request->hostname, gai_strerror (errnum)); - return (GFTP_ERETRYABLE); - } - - addr = hostp->ai_addr; - -#else /* !HAVE_GETADDRINFO */ - request->logging_function (gftp_logging_misc, request, - _("Looking up %s\n"), request->hostname); - - if (!(hostp = r_gethostbyname (request->hostname, &host, NULL))) - { - request->logging_function (gftp_logging_error, request, - _("Cannot look up hostname %s: %s\n"), - request->hostname, g_strerror (errno)); - return (GFTP_ERETRYABLE); - } - - addr = (struct sockaddr *) host.h_addr_list[0]; - -#endif /* HAVE_GETADDRINFO */ - - templist = proxy_hosts->list; - while (templist != NULL) - { - hostname = templist->data; - if (hostname->domain != NULL) - { - hostlen = strlen (request->hostname); - domlen = strlen (hostname->domain); - if (hostlen > domlen) - { - pos = request->hostname + hostlen - domlen; - if (strcmp (hostname->domain, pos) == 0) - return (0); - } - } - - if (hostname->ipv4_network_address != 0) - { - memcpy (addy, addr, sizeof (*addy)); - netaddr = - (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) | - ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) & - hostname->ipv4_netmask; - if (netaddr == hostname->ipv4_network_address) - return (0); - } - templist = templist->next; - } - - return (proxy_hostname != NULL && *proxy_hostname != '\0'); -} - - -static char * -copy_token (/*@out@*/ char **dest, char *source) -{ - /* This function is used internally by gftp_parse_ls () */ - char *endpos, savepos; - - endpos = source; - while (*endpos != ' ' && *endpos != '\t' && *endpos != '\0') - endpos++; - if (*endpos == '\0') - { - *dest = NULL; - return (NULL); - } - - savepos = *endpos; - *endpos = '\0'; - *dest = g_malloc0 ((gulong) (endpos - source + 1)); - strcpy (*dest, source); - *endpos = savepos; - - /* Skip the blanks till we get to the next entry */ - source = endpos + 1; - while ((*source == ' ' || *source == '\t') && *source != '\0') - source++; - return (source); -} - - -static char * -goto_next_token (char *pos) -{ - while (*pos != ' ' && *pos != '\t' && *pos != '\0') - pos++; - - while (*pos == ' ' || *pos == '\t') - pos++; - - return (pos); -} - - -static time_t -parse_vms_time (char *str, char **endpos) -{ - struct tm curtime; - time_t ret; - - /* 8-JUN-2004 13:04:14 */ - memset (&curtime, 0, sizeof (curtime)); - - *endpos = strptime (str, "%d-%b-%Y %H:%M:%S", &curtime); - if (*endpos == NULL) - *endpos = strptime (str, "%d-%b-%Y %H:%M", &curtime); - - if (*endpos != NULL) - { - ret = mktime (&curtime); - for (; **endpos == ' ' || **endpos == '\t'; (*endpos)++); - } - else - { - ret = 0; - *endpos = goto_next_token (str); - if (*endpos != NULL) - *endpos = goto_next_token (*endpos); - } - - return (ret); -} - - -time_t -parse_time (char *str, char **endpos) -{ - struct tm curtime, *loctime; - time_t t, ret; - char *tmppos; - size_t slen; - int i, num; - - slen = strlen (str); - memset (&curtime, 0, sizeof (curtime)); - curtime.tm_isdst = -1; - - if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && - isdigit ((int) str[3])) - { - /* This is how DOS will return the date/time */ - /* 07-06-99 12:57PM */ - - tmppos = strptime (str, "%m-%d-%y %I:%M%p", &curtime); - } - else if (slen > 4 && isdigit ((int) str[0]) && str[2] == '-' && - isalpha (str[3])) - { - /* 10-Jan-2003 09:14 */ - tmppos = strptime (str, "%d-%h-%Y %H:%M", &curtime); - } - else if (slen > 4 && isdigit ((int) str[0]) && str[4] == '/') - { - /* 2003/12/25 */ - tmppos = strptime (str, "%Y/%m/%d", &curtime); - } - else - { - /* This is how most UNIX, Novell, and MacOS ftp servers send their time */ - /* Jul 06 12:57 or Jul 6 1999 */ - - if (strchr (str, ':') != NULL) - { - tmppos = strptime (str, "%h %d %H:%M", &curtime); - t = time (NULL); - loctime = localtime (&t); - - if (curtime.tm_mon > loctime->tm_mon) - curtime.tm_year = loctime->tm_year - 1; - else - curtime.tm_year = loctime->tm_year; - } - else - tmppos = strptime (str, "%h %d %Y", &curtime); - } - - if (tmppos != NULL) - ret = mktime (&curtime); - else - ret = 0; - - if (endpos != NULL) - { - if (tmppos == NULL) - { - /* We cannot parse this date format. So, just skip this date field - and continue to the next token. This is mainly for the HTTP - support */ - - *endpos = str; - for (num = 0; num < 2 && **endpos != '\0'; num++) - { - for (i=0; - (*endpos)[i] != ' ' && (*endpos)[i] != '\t' && - (*endpos)[i] != '\0'; - i++); - *endpos += i; - - for (i=0; (*endpos)[i] == ' ' || (*endpos)[i] == '\t'; i++); - *endpos += i; - } - } - else - *endpos = tmppos; - } - - return (ret); -} - - -static mode_t -gftp_parse_vms_attribs (char **src, mode_t mask) -{ - char *endpos; - mode_t ret; - - if (*src == NULL) - return (0); - - if ((endpos = strchr (*src, ',')) != NULL) - *endpos = '\0'; - - ret = 0; - if (strchr (*src, 'R') != NULL) - ret |= S_IRUSR | S_IRGRP | S_IROTH; - if (strchr (*src, 'W') != NULL) - ret |= S_IWUSR | S_IWGRP | S_IWOTH; - if (strchr (*src, 'E') != NULL) - ret |= S_IXUSR | S_IXGRP | S_IXOTH; - - *src = endpos + 1; - - return (ret & mask); -} - - -static int -gftp_parse_ls_vms (gftp_request * request, int fd, char *str, gftp_file * fle) -{ - char *curpos, *endpos, tempstr[1024]; - int multiline; - ssize_t len; - - /* .PINE-DEBUG1;1 9 21-AUG-2002 20:06 [MYERSRG] (RWED,RWED,,) */ - /* WWW.DIR;1 1 23-NOV-1999 05:47 [MYERSRG] (RWE,RWE,RE,E) */ - - /* Multiline VMS - $MAIN.TPU$JOURNAL;1 - 1/18 8-JUN-2004 13:04:14 [NUCLEAR,FISSION] (RWED,RWED,RE,) - TCPIP$FTP_SERVER.LOG;29 - 0/18 8-JUN-2004 14:42:04 [NUCLEAR,FISSION] (RWED,RWED,RE,) - TCPIP$FTP_SERVER.LOG;28 - 5/18 8-JUN-2004 13:05:11 [NUCLEAR,FISSION] (RWED,RWED,RE,) - TCPIP$FTP_SERVER.LOG;27 - 5/18 8-JUN-2004 13:03:51 [NUCLEAR,FISSION] (RWED,RWED,RE,) */ - - if ((curpos = strchr (str, ';')) == NULL) - return (GFTP_EFATAL); - - multiline = strchr (str, ' ') == NULL; - - *curpos = '\0'; - if (strlen (str) > 4 && strcmp (curpos - 4, ".DIR") == 0) - { - fle->st_mode |= S_IFDIR; - *(curpos - 4) = '\0'; - } - - fle->file = g_strdup (str); - - if (multiline) - { - if (request->get_next_dirlist_line == NULL) - return (GFTP_EFATAL); - - len = request->get_next_dirlist_line (request, fd, tempstr, - sizeof (tempstr)); - if (len <= 0) - return ((int) len); - - for (curpos = tempstr; *curpos == ' ' || *curpos == '\t'; curpos++); - } - else - curpos = goto_next_token (curpos + 1); - - fle->size = gftp_parse_file_size (curpos) * 512; /* Is this correct? */ - - curpos = goto_next_token (curpos); - - fle->datetime = parse_vms_time (curpos, &curpos); - - if (*curpos != '[') - return (GFTP_EFATAL); - - if ((endpos = strchr (curpos, ']')) == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (endpos + 1); - if ((curpos = strchr (curpos, ',')) == NULL) - return (0); - curpos++; - - fle->st_mode = gftp_parse_vms_attribs (&curpos, S_IRWXU); - fle->st_mode |= gftp_parse_vms_attribs (&curpos, S_IRWXG); - fle->st_mode |= gftp_parse_vms_attribs (&curpos, S_IRWXO); - - fle->user = g_strdup (""); - fle->group = g_strdup (""); - - return (0); -} - - -static int -gftp_parse_ls_mvs (char *str, gftp_file * fle) -{ - char *curpos; - - /* Volume Unit Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname */ - /* SVI52A 3390 2003/12/10 8 216 FB 80 27920 PS CARDS.DELETES */ - /* SVI528 3390 2003/12/12 1 5 FB 80 24000 PO CLIST */ - - curpos = goto_next_token (str + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - fle->datetime = parse_time (curpos, &curpos); - - curpos = goto_next_token (curpos); - if (curpos == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - fle->size = gftp_parse_file_size (curpos) * 55996; - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - if (curpos == NULL) - return (GFTP_EFATAL); - - if (strncmp (curpos, "PS", 2) == 0) - fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - else if (strncmp (curpos, "PO", 2) == 0) - fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - else - return (GFTP_EFATAL); - - curpos = goto_next_token (curpos + 1); - - fle->user = g_strdup (_("unknown")); - fle->group = g_strdup (_("unknown")); - fle->file = g_strdup (curpos); - - return (0); -} - - -static int -gftp_parse_ls_eplf (char *str, gftp_file * fle) -{ - char *startpos; - int isdir = 0; - - startpos = str; - while (startpos) - { - startpos++; - switch (*startpos) - { - case '/': - isdir = 1; - break; - case 's': - fle->size = gftp_parse_file_size (startpos + 1); - break; - case 'm': - fle->datetime = strtol (startpos + 1, NULL, 10); - break; - } - startpos = strchr (startpos, ','); - } - - if ((startpos = strchr (str, 9)) == NULL) - return (GFTP_EFATAL); - - if (isdir) - fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - else - fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - fle->file = g_strdup (startpos + 1); - fle->user = g_strdup (_("unknown")); - fle->group = g_strdup (_("unknown")); - return (0); -} - - -static int -gftp_parse_ls_unix (gftp_request * request, char *str, size_t slen, - gftp_file * fle) -{ - char *endpos, *startpos, *pos, *attribs; - int cols; - - /* If there is no space between the attribs and links field, just make one */ - if (slen > 10) - str[10] = ' '; - - /* Determine the number of columns */ - cols = 0; - pos = str; - while (*pos != '\0') - { - while (*pos != '\0' && *pos != ' ' && *pos != '\t') - { - if (*pos == ':') - break; - pos++; - } - - cols++; - - if (*pos == ':') - { - cols++; - break; - } - - while (*pos == ' ' || *pos == '\t') - pos++; - } - - startpos = str; - /* Copy file attributes */ - if ((startpos = copy_token (&attribs, startpos)) == NULL) - return (GFTP_EFATAL); - - if (strlen (attribs) < 10) - return (GFTP_EFATAL); - - fle->st_mode = gftp_convert_attributes_to_mode_t (attribs); - g_free (attribs); - - if (cols >= 9) - { - /* Skip the number of links */ - startpos = goto_next_token (startpos); - - /* Copy the user that owns this file */ - if ((startpos = copy_token (&fle->user, startpos)) == NULL) - return (GFTP_EFATAL); - - /* Copy the group that owns this file */ - if ((startpos = copy_token (&fle->group, startpos)) == NULL) - return (GFTP_EFATAL); - } - else - { - fle->group = g_strdup (_("unknown")); - if (cols == 8) - { - if ((startpos = copy_token (&fle->user, startpos)) == NULL) - return (GFTP_EFATAL); - } - else - fle->user = g_strdup (_("unknown")); - startpos = goto_next_token (startpos); - } - - if (request->server_type == GFTP_DIRTYPE_CRAY) - { - /* See if this is a Cray directory listing. It has the following format: - drwx------ 2 feiliu g913 DK common 4096 Sep 24 2001 wv */ - if (cols == 11 && strstr (str, "->") == NULL) - { - startpos = goto_next_token (startpos); - startpos = goto_next_token (startpos); - } - } - - /* See if this is a block or character device. We will store the major number - in the high word and the minor number in the low word. */ - if (GFTP_IS_SPECIAL_DEVICE (fle->st_mode) && - (endpos = strchr (startpos, ',')) != NULL) - { - fle->size = (unsigned long) strtol (startpos, NULL, 10) << 16; - - startpos = endpos + 1; - while (*startpos == ' ') - startpos++; - - /* Get the minor number */ - if ((endpos = strchr (startpos, ' ')) == NULL) - return (GFTP_EFATAL); - fle->size |= strtol (startpos, NULL, 10) & 0xFF; - } - else - { - /* This is a regular file */ - if ((endpos = strchr (startpos, ' ')) == NULL) - return (GFTP_EFATAL); - fle->size = gftp_parse_file_size (startpos); - } - - /* Skip the blanks till we get to the next entry */ - startpos = endpos + 1; - while (*startpos == ' ') - startpos++; - - fle->datetime = parse_time (startpos, &startpos); - - /* Skip the blanks till we get to the next entry */ - startpos = goto_next_token (startpos); - - /* Parse the filename. If this file is a symbolic link, remove the -> part */ - if (S_ISLNK (fle->st_mode) && ((endpos = strstr (startpos, "->")) != NULL)) - *(endpos - 1) = '\0'; - - fle->file = g_strdup (startpos); - - /* Uncomment this if you want to strip the spaces off of the end of the file. - I don't want to do this by default since there are valid filenames with - spaces at the end of them. Some broken FTP servers like the Paradyne IPC - DSLAMS append a bunch of spaces at the end of the file. - for (endpos = fle->file + strlen (fle->file) - 1; - *endpos == ' '; - *endpos-- = '\0'); - */ - - return (0); -} - - -static int -gftp_parse_ls_nt (char *str, gftp_file * fle) -{ - char *startpos; - - startpos = str; - fle->datetime = parse_time (startpos, &startpos); - - fle->user = g_strdup (_("unknown")); - fle->group = g_strdup (_("unknown")); - - startpos = goto_next_token (startpos); - - if (startpos[0] == '<') - fle->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - else - { - fle->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - fle->size = gftp_parse_file_size (startpos); - } - - startpos = goto_next_token (startpos); - fle->file = g_strdup (startpos); - return (0); -} - - -static int -gftp_parse_ls_novell (char *str, gftp_file * fle) -{ - char *startpos; - - if (str[12] != ' ') - return (GFTP_EFATAL); - - str[12] = '\0'; - fle->st_mode = gftp_convert_attributes_to_mode_t (str); - startpos = str + 13; - - while ((*startpos == ' ' || *startpos == '\t') && *startpos != '\0') - startpos++; - - if ((startpos = copy_token (&fle->user, startpos)) == NULL) - return (GFTP_EFATAL); - - fle->group = g_strdup (_("unknown")); - - while (*startpos != '\0' && !isdigit (*startpos)) - startpos++; - - fle->size = gftp_parse_file_size (startpos); - - startpos = goto_next_token (startpos); - fle->datetime = parse_time (startpos, &startpos); - - startpos = goto_next_token (startpos); - fle->file = g_strdup (startpos); - return (0); -} - - -int -gftp_parse_ls (gftp_request * request, const char *lsoutput, gftp_file * fle, - int fd) -{ - char *str, *endpos, tmpchar; - int result, is_vms; - size_t len; - - g_return_val_if_fail (lsoutput != NULL, GFTP_EFATAL); - g_return_val_if_fail (fle != NULL, GFTP_EFATAL); - - str = g_strdup (lsoutput); - memset (fle, 0, sizeof (*fle)); - - len = strlen (str); - if (len > 0 && str[len - 1] == '\n') - str[--len] = '\0'; - if (len > 0 && str[len - 1] == '\r') - str[--len] = '\0'; - - switch (request->server_type) - { - case GFTP_DIRTYPE_CRAY: - case GFTP_DIRTYPE_UNIX: - result = gftp_parse_ls_unix (request, str, len, fle); - break; - case GFTP_DIRTYPE_EPLF: - result = gftp_parse_ls_eplf (str, fle); - break; - case GFTP_DIRTYPE_NOVELL: - result = gftp_parse_ls_novell (str, fle); - break; - case GFTP_DIRTYPE_DOS: - result = gftp_parse_ls_nt (str, fle); - break; - case GFTP_DIRTYPE_VMS: - result = gftp_parse_ls_vms (request, fd, str, fle); - break; - case GFTP_DIRTYPE_MVS: - result = gftp_parse_ls_mvs (str, fle); - break; - default: /* autodetect */ - if (*lsoutput == '+') - result = gftp_parse_ls_eplf (str, fle); - else if (isdigit ((int) str[0]) && str[2] == '-') - result = gftp_parse_ls_nt (str, fle); - else if (str[1] == ' ' && str[2] == '[') - result = gftp_parse_ls_novell (str, fle); - else - { - if ((endpos = strchr (str, ' ')) != NULL) - { - /* If the first token in the string has a ; in it, then */ - /* we'll assume that this is a VMS directory listing */ - tmpchar = *endpos; - *endpos = '\0'; - is_vms = strchr (str, ';') != NULL; - *endpos = tmpchar; - } - else - is_vms = 0; - - if (is_vms) - result = gftp_parse_ls_vms (request, fd, str, fle); - else - result = gftp_parse_ls_unix (request, str, len, fle); - } - break; - } - g_free (str); - - return (result); -} - - static GHashTable * gftp_gen_dir_hash (gftp_request * request, int *ret) { @@ -2322,280 +1342,6 @@ } -#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) -static int -get_port (struct addrinfo *addr) -{ - struct sockaddr_in * saddr; - int port; - - if (addr->ai_family == AF_INET) - { - saddr = (struct sockaddr_in *) addr->ai_addr; - port = ntohs (saddr->sin_port); - } - else - port = 0; - - return (port); -} - - -int -gftp_connect_server_with_getaddr (gftp_request * request, char *service, - char *proxy_hostname, unsigned int proxy_port) -{ - struct addrinfo *hostp, *current_hostp; - char *connect_host, *disphost; - struct addrinfo hints, *res; - intptr_t enable_ipv6; - unsigned int port; - int ret, sock = -1; - char serv[8]; - - if ((ret = gftp_need_proxy (request, service, proxy_hostname, - proxy_port)) < 0) - return (ret); - else - request->use_proxy = ret; - - gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6); - - memset (&hints, 0, sizeof (hints)); - hints.ai_flags = AI_CANONNAME; - - hints.ai_family = enable_ipv6 ? PF_UNSPEC : AF_INET; - hints.ai_socktype = SOCK_STREAM; - - if (request->use_proxy) - { - connect_host = proxy_hostname; - port = proxy_port; - } - else - { - connect_host = request->hostname; - port = request->port; - } - - if (port == 0) - strcpy (serv, service); - else - snprintf (serv, sizeof (serv), "%d", port); - - request->logging_function (gftp_logging_misc, request, - _("Looking up %s\n"), connect_host); - if ((ret = getaddrinfo (connect_host, serv, &hints, - &hostp)) != 0) - { - request->logging_function (gftp_logging_error, request, - _("Cannot look up hostname %s: %s\n"), - connect_host, gai_strerror (ret)); - return (GFTP_ERETRYABLE); - } - - disphost = connect_host; - for (res = hostp; res != NULL; res = res->ai_next) - { - disphost = res->ai_canonname ? res->ai_canonname : connect_host; - port = get_port (res); - if (!request->use_proxy) - request->port = port; - - if ((sock = socket (res->ai_family, res->ai_socktype, - res->ai_protocol)) < 0) - { - request->logging_function (gftp_logging_error, request, - _("Failed to create a socket: %s\n"), - g_strerror (errno)); - continue; - } - - request->logging_function (gftp_logging_misc, request, - _("Trying %s:%d\n"), disphost, port); - - if (connect (sock, res->ai_addr, res->ai_addrlen) == -1) - { - request->logging_function (gftp_logging_error, request, - _("Cannot connect to %s: %s\n"), - disphost, g_strerror (errno)); - close (sock); - continue; - } - - current_hostp = res; - request->ai_family = res->ai_family; - break; - } - - if (res == NULL) - { - if (hostp != NULL) - freeaddrinfo (hostp); - - return (GFTP_ERETRYABLE); - } - - request->remote_addr_len = current_hostp->ai_addrlen; - request->remote_addr = g_malloc0 (request->remote_addr_len); - memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr, - request->remote_addr_len); - - request->logging_function (gftp_logging_misc, request, - _("Connected to %s:%d\n"), connect_host, port); - - return (sock); -} -#endif - - -int -gftp_connect_server_legacy (gftp_request * request, char *service, - char *proxy_hostname, unsigned int proxy_port) -{ - struct sockaddr_in remote_address; - char *connect_host, *disphost; - struct hostent host, *hostp; - struct servent serv_struct; - int ret, sock, curhost; - unsigned int port; - - if ((ret = gftp_need_proxy (request, service, proxy_hostname, - proxy_port)) < 0) - return (ret); - - request->use_proxy = ret; - if (request->use_proxy == 1) - hostp = NULL; - - request->ai_family = AF_INET; - if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - request->logging_function (gftp_logging_error, request, - _("Failed to create a IPv4 socket: %s\n"), - g_strerror (errno)); - return (GFTP_ERETRYABLE); - } - - memset (&remote_address, 0, sizeof (remote_address)); - remote_address.sin_family = AF_INET; - - if (request->use_proxy) - { - connect_host = proxy_hostname; - port = proxy_port; - } - else - { - connect_host = request->hostname; - port = request->port; - } - - if (port == 0) - { - if (!r_getservbyname (service, "tcp", &serv_struct, NULL)) - { - request->logging_function (gftp_logging_error, request, - _("Cannot look up service name %s/tcp. Please check your services file\n"), - service); - close (sock); - return (GFTP_EFATAL); - } - - port = ntohs (serv_struct.s_port); - - if (!request->use_proxy) - request->port = port; - } - - remote_address.sin_port = htons (port); - - request->logging_function (gftp_logging_misc, request, - _("Looking up %s\n"), connect_host); - - if (!(hostp = r_gethostbyname (connect_host, &host, NULL))) - { - request->logging_function (gftp_logging_error, request, - _("Cannot look up hostname %s: %s\n"), - connect_host, g_strerror (errno)); - close (sock); - return (GFTP_ERETRYABLE); - } - - disphost = NULL; - for (curhost = 0; - host.h_addr_list[curhost] != NULL; - curhost++) - { - disphost = host.h_name; - memcpy (&remote_address.sin_addr, - host.h_addr_list[curhost], - host.h_length); - request->logging_function (gftp_logging_misc, request, - _("Trying %s:%d\n"), - host.h_name, port); - - if (connect (sock, (struct sockaddr *) &remote_address, - sizeof (remote_address)) == -1) - { - request->logging_function (gftp_logging_error, request, - _("Cannot connect to %s: %s\n"), - connect_host, g_strerror (errno)); - } - break; - } - - if (host.h_addr_list[curhost] == NULL) - { - close (sock); - return (GFTP_ERETRYABLE); - } - - return (sock); -} - - -int -gftp_connect_server (gftp_request * request, char *service, - char *proxy_hostname, unsigned int proxy_port) -{ - int sock; - -#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) - sock = gftp_connect_server_with_getaddr (request, service, proxy_hostname, - proxy_port); -#else - sock = gftp_connect_server_legacy (request, service, proxy_hostname, - proxy_port); -#endif - - if (sock < 0) - return (sock); - - if (fcntl (sock, F_SETFD, 1) == -1) - { - request->logging_function (gftp_logging_error, request, - _("Error: Cannot set close on exec flag: %s\n"), - g_strerror (errno)); - close (sock); - return (GFTP_ERETRYABLE); - } - - if (gftp_fd_set_sockblocking (request, sock, 1) < 0) - { - close (sock); - return (GFTP_ERETRYABLE); - } - - request->datafd = sock; - - if (request->post_connect != NULL) - return (request->post_connect (request)); - - return (0); -} - - int gftp_set_config_options (gftp_request * request) { @@ -2649,345 +1395,6 @@ void -gftp_free_getline_buffer (gftp_getline_buffer ** rbuf) -{ - g_free ((*rbuf)->buffer); - g_free (*rbuf); - *rbuf = NULL; -} - - -ssize_t -gftp_get_line (gftp_request * request, gftp_getline_buffer ** rbuf, - char * str, size_t len, int fd) -{ - ssize_t (*read_function) (gftp_request * request, void *ptr, size_t size, - int fd); - char *pos, *nextpos; - size_t rlen, nslen; - int end_of_buffer; - ssize_t ret; - - if (request == NULL || request->read_function == NULL) - read_function = gftp_fd_read; - else - read_function = request->read_function; - - if (*rbuf == NULL) - { - *rbuf = g_malloc0 (sizeof (**rbuf)); - (*rbuf)->max_bufsize = len; - (*rbuf)->buffer = g_malloc0 ((gulong) ((*rbuf)->max_bufsize + 1)); - - if ((ret = read_function (request, (*rbuf)->buffer, - (*rbuf)->max_bufsize, fd)) <= 0) - { - gftp_free_getline_buffer (rbuf); - return (ret); - } - (*rbuf)->buffer[ret] = '\0'; - (*rbuf)->cur_bufsize = ret; - (*rbuf)->curpos = (*rbuf)->buffer; - } - - ret = 0; - while (1) - { - pos = strchr ((*rbuf)->curpos, '\n'); - end_of_buffer = (*rbuf)->curpos == (*rbuf)->buffer && - ((*rbuf)->max_bufsize == (*rbuf)->cur_bufsize || (*rbuf)->eof); - - if ((*rbuf)->cur_bufsize > 0 && (pos != NULL || end_of_buffer)) - { - if (pos != NULL) - { - nslen = pos - (*rbuf)->curpos + 1; - nextpos = pos + 1; - if (pos > (*rbuf)->curpos && *(pos - 1) == '\r') - pos--; - *pos = '\0'; - } - else - { - nslen = (*rbuf)->cur_bufsize; - nextpos = NULL; - - /* This is not an overflow since we allocated one extra byte to - buffer above */ - ((*rbuf)->buffer)[nslen] = '\0'; - } - - strncpy (str, (*rbuf)->curpos, len); - str[len - 1] = '\0'; - (*rbuf)->cur_bufsize -= nslen; - - if (nextpos != NULL) - (*rbuf)->curpos = nextpos; - else - (*rbuf)->cur_bufsize = 0; - - ret = nslen; - break; - } - else - { - if ((*rbuf)->cur_bufsize == 0 || *(*rbuf)->curpos == '\0') - { - rlen = (*rbuf)->max_bufsize; - pos = (*rbuf)->buffer; - } - else - { - memmove ((*rbuf)->buffer, (*rbuf)->curpos, (*rbuf)->cur_bufsize); - pos = (*rbuf)->buffer + (*rbuf)->cur_bufsize; - rlen = (*rbuf)->max_bufsize - (*rbuf)->cur_bufsize; - } - - (*rbuf)->curpos = (*rbuf)->buffer; - - if ((*rbuf)->eof) - ret = 0; - else - { - ret = read_function (request, pos, rlen, fd); - if (ret < 0) - { - gftp_free_getline_buffer (rbuf); - return (ret); - } - } - - if (ret == 0) - { - if ((*rbuf)->cur_bufsize == 0) - { - gftp_free_getline_buffer (rbuf); - return (ret); - } - - (*rbuf)->eof = 1; - } - - (*rbuf)->cur_bufsize += ret; - (*rbuf)->buffer[(*rbuf)->cur_bufsize] = '\0'; - } - } - - return (ret); -} - - -ssize_t -gftp_fd_read (gftp_request * request, void *ptr, size_t size, int fd) -{ - intptr_t network_timeout; - struct timeval tv; - fd_set fset; - ssize_t ret; - int s_ret; - - g_return_val_if_fail (fd >= 0, GFTP_EFATAL); - - gftp_lookup_request_option (request, "network_timeout", &network_timeout); - - errno = 0; - ret = 0; - FD_ZERO (&fset); - - do - { - FD_SET (fd, &fset); - tv.tv_sec = network_timeout; - tv.tv_usec = 0; - s_ret = select (fd + 1, &fset, NULL, NULL, &tv); - if (s_ret == -1 && (errno == EINTR || errno == EAGAIN)) - { - if (request != NULL && request->cancel) - { - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - continue; - } - else if (s_ret <= 0) - { - if (request != NULL) - { - request->logging_function (gftp_logging_error, request, - _("Connection to %s timed out\n"), - request->hostname); - gftp_disconnect (request); - } - - return (GFTP_ERETRYABLE); - } - - if ((ret = read (fd, ptr, size)) < 0) - { - if (errno == EINTR || errno == EAGAIN) - { - if (request != NULL && request->cancel) - { - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - continue; - } - - if (request != NULL) - { - request->logging_function (gftp_logging_error, request, - _("Error: Could not read from socket: %s\n"), - g_strerror (errno)); - gftp_disconnect (request); - } - - return (GFTP_ERETRYABLE); - } - - break; - } - while (1); - - return (ret); -} - - -ssize_t -gftp_fd_write (gftp_request * request, const char *ptr, size_t size, int fd) -{ - intptr_t network_timeout; - struct timeval tv; - int ret, s_ret; - ssize_t w_ret; - fd_set fset; - - g_return_val_if_fail (fd >= 0, GFTP_EFATAL); - - gftp_lookup_request_option (request, "network_timeout", &network_timeout); - - errno = 0; - ret = 0; - FD_ZERO (&fset); - - do - { - FD_SET (fd, &fset); - tv.tv_sec = network_timeout; - tv.tv_usec = 0; - s_ret = select (fd + 1, NULL, &fset, NULL, &tv); - if (s_ret == -1 && (errno == EINTR || errno == EAGAIN)) - { - if (request != NULL && request->cancel) - { - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - continue; - } - else if (s_ret <= 0) - { - if (request != NULL) - { - request->logging_function (gftp_logging_error, request, - _("Connection to %s timed out\n"), - request->hostname); - gftp_disconnect (request); - } - - return (GFTP_ERETRYABLE); - } - - w_ret = write (fd, ptr, size); - if (w_ret < 0) - { - if (errno == EINTR || errno == EAGAIN) - { - if (request != NULL && request->cancel) - { - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - continue; - } - - if (request != NULL) - { - request->logging_function (gftp_logging_error, request, - _("Error: Could not write to socket: %s\n"), - g_strerror (errno)); - gftp_disconnect (request); - } - - return (GFTP_ERETRYABLE); - } - - ptr += w_ret; - size -= w_ret; - ret += w_ret; - } - while (size > 0); - - return (ret); -} - - -ssize_t -gftp_writefmt (gftp_request * request, int fd, const char *fmt, ...) -{ - char *tempstr; - va_list argp; - ssize_t ret; - - va_start (argp, fmt); - tempstr = g_strdup_vprintf (fmt, argp); - va_end (argp); - - ret = request->write_function (request, tempstr, strlen (tempstr), fd); - g_free (tempstr); - return (ret); -} - - -int -gftp_fd_set_sockblocking (gftp_request * request, int fd, int non_blocking) -{ - int flags; - - g_return_val_if_fail (fd >= 0, GFTP_EFATAL); - - if ((flags = fcntl (fd, F_GETFL, 0)) < 0) - { - request->logging_function (gftp_logging_error, request, - _("Cannot get socket flags: %s\n"), - g_strerror (errno)); - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - if (non_blocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if (fcntl (fd, F_SETFL, flags) < 0) - { - request->logging_function (gftp_logging_error, request, - _("Cannot set socket to non-blocking: %s\n"), - g_strerror (errno)); - gftp_disconnect (request); - return (GFTP_ERETRYABLE); - } - - return (0); -} - - -void gftp_swap_socks (gftp_request * dest, gftp_request * source) { g_return_if_fail (dest != NULL); diff -r 9a6571938f89 -r c7d7a081cd9c lib/socket-connect.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/socket-connect.c Tue Mar 04 12:28:40 2008 +0000 @@ -0,0 +1,401 @@ +/*****************************************************************************/ +/* socket-connect.c - contains functions for connecting to a server */ +/* Copyright (C) 1998-2008 Brian Masney */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ +/*****************************************************************************/ + +#include "gftp.h" +static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $"; + +/* FIXME - clean up this function */ +static int +gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname, + unsigned int proxy_port) +{ + gftp_config_list_vars * proxy_hosts; + gftp_proxy_hosts * hostname; + size_t hostlen, domlen; + unsigned char addy[4]; + struct sockaddr *addr; + GList * templist; + gint32 netaddr; + char *pos; +#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) + struct addrinfo hints, *hostp; + unsigned int port; + int errnum; + char serv[8]; +#else + struct hostent host, *hostp; +#endif + + gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts); + + if (proxy_hostname == NULL || *proxy_hostname == '\0') + return (0); + else if (proxy_hosts->list == NULL) + return (proxy_hostname != NULL && + *proxy_hostname != '\0'); + + hostp = NULL; +#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) + memset (&hints, 0, sizeof (hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + port = request->use_proxy ? proxy_port : request->port; + if (port == 0) + strcpy (serv, service); + else + snprintf (serv, sizeof (serv), "%d", port); + + request->logging_function (gftp_logging_misc, request, + _("Looking up %s\n"), request->hostname); + + if ((errnum = getaddrinfo (request->hostname, serv, &hints, + &hostp)) != 0) + { + request->logging_function (gftp_logging_error, request, + _("Cannot look up hostname %s: %s\n"), + request->hostname, gai_strerror (errnum)); + return (GFTP_ERETRYABLE); + } + + addr = hostp->ai_addr; + +#else /* !HAVE_GETADDRINFO */ + request->logging_function (gftp_logging_misc, request, + _("Looking up %s\n"), request->hostname); + + if (!(hostp = r_gethostbyname (request->hostname, &host, NULL))) + { + request->logging_function (gftp_logging_error, request, + _("Cannot look up hostname %s: %s\n"), + request->hostname, g_strerror (errno)); + return (GFTP_ERETRYABLE); + } + + addr = (struct sockaddr *) host.h_addr_list[0]; + +#endif /* HAVE_GETADDRINFO */ + + templist = proxy_hosts->list; + while (templist != NULL) + { + hostname = templist->data; + if (hostname->domain != NULL) + { + hostlen = strlen (request->hostname); + domlen = strlen (hostname->domain); + if (hostlen > domlen) + { + pos = request->hostname + hostlen - domlen; + if (strcmp (hostname->domain, pos) == 0) + return (0); + } + } + + if (hostname->ipv4_network_address != 0) + { + memcpy (addy, addr, sizeof (*addy)); + netaddr = + (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) | + ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) & + hostname->ipv4_netmask; + if (netaddr == hostname->ipv4_network_address) + return (0); + } + templist = templist->next; + } + + return (proxy_hostname != NULL && *proxy_hostname != '\0'); +} + + +#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) +static int +get_port (struct addrinfo *addr) +{ + struct sockaddr_in * saddr; + int port; + + if (addr->ai_family == AF_INET) + { + saddr = (struct sockaddr_in *) addr->ai_addr; + port = ntohs (saddr->sin_port); + } + else + port = 0; + + return (port); +} + + +static int +gftp_connect_server_with_getaddr (gftp_request * request, char *service, + char *proxy_hostname, unsigned int proxy_port) +{ + struct addrinfo *hostp, *current_hostp; + char *connect_host, *disphost; + struct addrinfo hints, *res; + intptr_t enable_ipv6; + unsigned int port; + int ret, sock = -1; + char serv[8]; + + if ((ret = gftp_need_proxy (request, service, proxy_hostname, + proxy_port)) < 0) + return (ret); + else + request->use_proxy = ret; + + gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6); + + memset (&hints, 0, sizeof (hints)); + hints.ai_flags = AI_CANONNAME; + + hints.ai_family = enable_ipv6 ? PF_UNSPEC : AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (request->use_proxy) + { + connect_host = proxy_hostname; + port = proxy_port; + } + else + { + connect_host = request->hostname; + port = request->port; + } + + if (port == 0) + strcpy (serv, service); + else + snprintf (serv, sizeof (serv), "%d", port); + + request->logging_function (gftp_logging_misc, request, + _("Looking up %s\n"), connect_host); + if ((ret = getaddrinfo (connect_host, serv, &hints, + &hostp)) != 0) + { + request->logging_function (gftp_logging_error, request, + _("Cannot look up hostname %s: %s\n"), + connect_host, gai_strerror (ret)); + return (GFTP_ERETRYABLE); + } + + disphost = connect_host; + for (res = hostp; res != NULL; res = res->ai_next) + { + disphost = res->ai_canonname ? res->ai_canonname : connect_host; + port = get_port (res); + if (!request->use_proxy) + request->port = port; + + if ((sock = socket (res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + { + request->logging_function (gftp_logging_error, request, + _("Failed to create a socket: %s\n"), + g_strerror (errno)); + continue; + } + + request->logging_function (gftp_logging_misc, request, + _("Trying %s:%d\n"), disphost, port); + + if (connect (sock, res->ai_addr, res->ai_addrlen) == -1) + { + request->logging_function (gftp_logging_error, request, + _("Cannot connect to %s: %s\n"), + disphost, g_strerror (errno)); + close (sock); + continue; + } + + current_hostp = res; + request->ai_family = res->ai_family; + break; + } + + if (res == NULL) + { + if (hostp != NULL) + freeaddrinfo (hostp); + + return (GFTP_ERETRYABLE); + } + + request->remote_addr_len = current_hostp->ai_addrlen; + request->remote_addr = g_malloc0 (request->remote_addr_len); + memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr, + request->remote_addr_len); + + request->logging_function (gftp_logging_misc, request, + _("Connected to %s:%d\n"), connect_host, port); + + return (sock); +} +#endif + + +static int +gftp_connect_server_legacy (gftp_request * request, char *service, + char *proxy_hostname, unsigned int proxy_port) +{ + struct sockaddr_in remote_address; + char *connect_host, *disphost; + struct hostent host, *hostp; + struct servent serv_struct; + int ret, sock, curhost; + unsigned int port; + + if ((ret = gftp_need_proxy (request, service, proxy_hostname, + proxy_port)) < 0) + return (ret); + + request->use_proxy = ret; + if (request->use_proxy == 1) + hostp = NULL; + + request->ai_family = AF_INET; + if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + request->logging_function (gftp_logging_error, request, + _("Failed to create a IPv4 socket: %s\n"), + g_strerror (errno)); + return (GFTP_ERETRYABLE); + } + + memset (&remote_address, 0, sizeof (remote_address)); + remote_address.sin_family = AF_INET; + + if (request->use_proxy) + { + connect_host = proxy_hostname; + port = proxy_port; + } + else + { + connect_host = request->hostname; + port = request->port; + } + + if (port == 0) + { + if (!r_getservbyname (service, "tcp", &serv_struct, NULL)) + { + request->logging_function (gftp_logging_error, request, + _("Cannot look up service name %s/tcp. Please check your services file\n"), + service); + close (sock); + return (GFTP_EFATAL); + } + + port = ntohs (serv_struct.s_port); + + if (!request->use_proxy) + request->port = port; + } + + remote_address.sin_port = htons (port); + + request->logging_function (gftp_logging_misc, request, + _("Looking up %s\n"), connect_host); + + if (!(hostp = r_gethostbyname (connect_host, &host, NULL))) + { + request->logging_function (gftp_logging_error, request, + _("Cannot look up hostname %s: %s\n"), + connect_host, g_strerror (errno)); + close (sock); + return (GFTP_ERETRYABLE); + } + + disphost = NULL; + for (curhost = 0; + host.h_addr_list[curhost] != NULL; + curhost++) + { + disphost = host.h_name; + memcpy (&remote_address.sin_addr, + host.h_addr_list[curhost], + host.h_length); + request->logging_function (gftp_logging_misc, request, + _("Trying %s:%d\n"), + host.h_name, port); + + if (connect (sock, (struct sockaddr *) &remote_address, + sizeof (remote_address)) == -1) + { + request->logging_function (gftp_logging_error, request, + _("Cannot connect to %s: %s\n"), + connect_host, g_strerror (errno)); + } + break; + } + + if (host.h_addr_list[curhost] == NULL) + { + close (sock); + return (GFTP_ERETRYABLE); + } + + return (sock); +} + + +int +gftp_connect_server (gftp_request * request, char *service, + char *proxy_hostname, unsigned int proxy_port) +{ + int sock; + +#if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR) + sock = gftp_connect_server_with_getaddr (request, service, proxy_hostname, + proxy_port); +#else + sock = gftp_connect_server_legacy (request, service, proxy_hostname, + proxy_port); +#endif + + if (sock < 0) + return (sock); + + if (fcntl (sock, F_SETFD, 1) == -1) + { + request->logging_function (gftp_logging_error, request, + _("Error: Cannot set close on exec flag: %s\n"), + g_strerror (errno)); + close (sock); + return (GFTP_ERETRYABLE); + } + + if (gftp_fd_set_sockblocking (request, sock, 1) < 0) + { + close (sock); + return (GFTP_ERETRYABLE); + } + + request->datafd = sock; + + if (request->post_connect != NULL) + return (request->post_connect (request)); + + return (0); +} + diff -r 9a6571938f89 -r c7d7a081cd9c lib/sockutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/sockutils.c Tue Mar 04 12:28:40 2008 +0000 @@ -0,0 +1,360 @@ +/*****************************************************************************/ +/* sockutils.c - various utilities for dealing with sockets */ +/* Copyright (C) 1998-2008 Brian Masney */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ +/*****************************************************************************/ + +#include "gftp.h" +static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $"; + +ssize_t +gftp_get_line (gftp_request * request, gftp_getline_buffer ** rbuf, + char * str, size_t len, int fd) +{ + ssize_t (*read_function) (gftp_request * request, void *ptr, size_t size, + int fd); + char *pos, *nextpos; + size_t rlen, nslen; + int end_of_buffer; + ssize_t ret; + + if (request == NULL || request->read_function == NULL) + read_function = gftp_fd_read; + else + read_function = request->read_function; + + if (*rbuf == NULL) + { + *rbuf = g_malloc0 (sizeof (**rbuf)); + (*rbuf)->max_bufsize = len; + (*rbuf)->buffer = g_malloc0 ((gulong) ((*rbuf)->max_bufsize + 1)); + + if ((ret = read_function (request, (*rbuf)->buffer, + (*rbuf)->max_bufsize, fd)) <= 0) + { + gftp_free_getline_buffer (rbuf); + return (ret); + } + (*rbuf)->buffer[ret] = '\0'; + (*rbuf)->cur_bufsize = ret; + (*rbuf)->curpos = (*rbuf)->buffer; + } + + ret = 0; + while (1) + { + pos = strchr ((*rbuf)->curpos, '\n'); + end_of_buffer = (*rbuf)->curpos == (*rbuf)->buffer && + ((*rbuf)->max_bufsize == (*rbuf)->cur_bufsize || (*rbuf)->eof); + + if ((*rbuf)->cur_bufsize > 0 && (pos != NULL || end_of_buffer)) + { + if (pos != NULL) + { + nslen = pos - (*rbuf)->curpos + 1; + nextpos = pos + 1; + if (pos > (*rbuf)->curpos && *(pos - 1) == '\r') + pos--; + *pos = '\0'; + } + else + { + nslen = (*rbuf)->cur_bufsize; + nextpos = NULL; + + /* This is not an overflow since we allocated one extra byte to + buffer above */ + ((*rbuf)->buffer)[nslen] = '\0'; + } + + strncpy (str, (*rbuf)->curpos, len); + str[len - 1] = '\0'; + (*rbuf)->cur_bufsize -= nslen; + + if (nextpos != NULL) + (*rbuf)->curpos = nextpos; + else + (*rbuf)->cur_bufsize = 0; + + ret = nslen; + break; + } + else + { + if ((*rbuf)->cur_bufsize == 0 || *(*rbuf)->curpos == '\0') + { + rlen = (*rbuf)->max_bufsize; + pos = (*rbuf)->buffer; + } + else + { + memmove ((*rbuf)->buffer, (*rbuf)->curpos, (*rbuf)->cur_bufsize); + pos = (*rbuf)->buffer + (*rbuf)->cur_bufsize; + rlen = (*rbuf)->max_bufsize - (*rbuf)->cur_bufsize; + } + + (*rbuf)->curpos = (*rbuf)->buffer; + + if ((*rbuf)->eof) + ret = 0; + else + { + ret = read_function (request, pos, rlen, fd); + if (ret < 0) + { + gftp_free_getline_buffer (rbuf); + return (ret); + } + } + + if (ret == 0) + { + if ((*rbuf)->cur_bufsize == 0) + { + gftp_free_getline_buffer (rbuf); + return (ret); + } + + (*rbuf)->eof = 1; + } + + (*rbuf)->cur_bufsize += ret; + (*rbuf)->buffer[(*rbuf)->cur_bufsize] = '\0'; + } + } + + return (ret); +} + + +void +gftp_free_getline_buffer (gftp_getline_buffer ** rbuf) +{ + g_free ((*rbuf)->buffer); + g_free (*rbuf); + *rbuf = NULL; +} + + +ssize_t +gftp_fd_read (gftp_request * request, void *ptr, size_t size, int fd) +{ + intptr_t network_timeout; + struct timeval tv; + fd_set fset; + ssize_t ret; + int s_ret; + + g_return_val_if_fail (fd >= 0, GFTP_EFATAL); + + gftp_lookup_request_option (request, "network_timeout", &network_timeout); + + errno = 0; + ret = 0; + FD_ZERO (&fset); + + do + { + FD_SET (fd, &fset); + tv.tv_sec = network_timeout; + tv.tv_usec = 0; + s_ret = select (fd + 1, &fset, NULL, NULL, &tv); + if (s_ret == -1 && (errno == EINTR || errno == EAGAIN)) + { + if (request != NULL && request->cancel) + { + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + continue; + } + else if (s_ret <= 0) + { + if (request != NULL) + { + request->logging_function (gftp_logging_error, request, + _("Connection to %s timed out\n"), + request->hostname); + gftp_disconnect (request); + } + + return (GFTP_ERETRYABLE); + } + + if ((ret = read (fd, ptr, size)) < 0) + { + if (errno == EINTR || errno == EAGAIN) + { + if (request != NULL && request->cancel) + { + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + continue; + } + + if (request != NULL) + { + request->logging_function (gftp_logging_error, request, + _("Error: Could not read from socket: %s\n"), + g_strerror (errno)); + gftp_disconnect (request); + } + + return (GFTP_ERETRYABLE); + } + + break; + } + while (1); + + return (ret); +} + + +ssize_t +gftp_fd_write (gftp_request * request, const char *ptr, size_t size, int fd) +{ + intptr_t network_timeout; + struct timeval tv; + int ret, s_ret; + ssize_t w_ret; + fd_set fset; + + g_return_val_if_fail (fd >= 0, GFTP_EFATAL); + + gftp_lookup_request_option (request, "network_timeout", &network_timeout); + + errno = 0; + ret = 0; + FD_ZERO (&fset); + + do + { + FD_SET (fd, &fset); + tv.tv_sec = network_timeout; + tv.tv_usec = 0; + s_ret = select (fd + 1, NULL, &fset, NULL, &tv); + if (s_ret == -1 && (errno == EINTR || errno == EAGAIN)) + { + if (request != NULL && request->cancel) + { + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + continue; + } + else if (s_ret <= 0) + { + if (request != NULL) + { + request->logging_function (gftp_logging_error, request, + _("Connection to %s timed out\n"), + request->hostname); + gftp_disconnect (request); + } + + return (GFTP_ERETRYABLE); + } + + w_ret = write (fd, ptr, size); + if (w_ret < 0) + { + if (errno == EINTR || errno == EAGAIN) + { + if (request != NULL && request->cancel) + { + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + continue; + } + + if (request != NULL) + { + request->logging_function (gftp_logging_error, request, + _("Error: Could not write to socket: %s\n"), + g_strerror (errno)); + gftp_disconnect (request); + } + + return (GFTP_ERETRYABLE); + } + + ptr += w_ret; + size -= w_ret; + ret += w_ret; + } + while (size > 0); + + return (ret); +} + + +ssize_t +gftp_writefmt (gftp_request * request, int fd, const char *fmt, ...) +{ + char *tempstr; + va_list argp; + ssize_t ret; + + va_start (argp, fmt); + tempstr = g_strdup_vprintf (fmt, argp); + va_end (argp); + + ret = request->write_function (request, tempstr, strlen (tempstr), fd); + g_free (tempstr); + return (ret); +} + + +int +gftp_fd_set_sockblocking (gftp_request * request, int fd, int non_blocking) +{ + int flags; + + g_return_val_if_fail (fd >= 0, GFTP_EFATAL); + + if ((flags = fcntl (fd, F_GETFL, 0)) < 0) + { + request->logging_function (gftp_logging_error, request, + _("Cannot get socket flags: %s\n"), + g_strerror (errno)); + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + if (non_blocking) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + + if (fcntl (fd, F_SETFL, flags) < 0) + { + request->logging_function (gftp_logging_error, request, + _("Cannot set socket to non-blocking: %s\n"), + g_strerror (errno)); + gftp_disconnect (request); + return (GFTP_ERETRYABLE); + } + + return (0); +} +