view lib/misc.c @ 58:c01d91c10f6c

2002-11-20 Brian Masney <masneyb@gftp.org> * lib/protocols.c lib/gftp.h - added gftp_get_line(), gftp_read(), gftp_write(), gftp_writefmt(), and gftp_set_sockblocking() functions. Added struct_gftp_getline_buffer for gftp_get_line function() * lib/cache.c lib/gftp.h lib/local.c lib/misc.c lib/protocols.c lib/rfc2068.c lib/rfc959.c lib/ssh.c lib/sshv2.c - *_get_file() returns off_t instead of long. *_{get,put}_next_file_chunk returns ssize_t instead of size_t. Added *_set_config_options function to gftp_request structure and protocol files. Use the new network functions documented above. Convert usage of ANSI C IO (FILE *) to standard BSD sockets so that I can use timeouts properly with select * lib/misc.c (ssh_start_login_sequence) - use gftp_set_sockblock(), gftp_read() and gftp_write() functions * lib/protocols.c - move some protocol specific code to the protocol specific files * lib/local.c - log succesful messages to gftp_logging_misc instead of gftp_logging_error * lib/cache.c - log some more error conditions to the user * lib/rfc959.c - added rfc959_getcwd(). In, rfc959_accept_active_connection(), set set socket to blocking mode before calling accept() * src/text/gftk-text.c - If we get no files in gftp_text_ls(), return instead of segfaulting * src/gtk/gftp-gtk.c - expand the port field in the toolbar to be 45 pixels wide * src/text/gftp-text.c src/gtk/misc-gtk.c src/gtk/transfer.c src/gtk/view_dialog.c - changes for conversion of request->{sock,data} from ANSI C IO (FILE *) to standard BSD sockets
author masneyb
date Thu, 21 Nov 2002 00:33:51 +0000
parents a12bcbc2fce4
children 618423504fe0
line wrap: on
line source

/*****************************************************************************/
/*  misc.c - general purpose routines                                        */
/*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
/*                                                                           */
/*  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"
#include "options.h"
static const char cvsid[] = "$Id$";

char *
insert_commas (off_t number, char *dest_str, size_t dest_len)
{
  char *frompos, *topos, src[50], *dest;
  int len, num, rem, i;

  if (dest_str != NULL)
    *dest_str = '\0';
  len = (number > 0 ? log10 (number) : 0) + 2;

  if (len <= 0) 
    {
      if (dest_str != NULL)
        strncpy (dest_str, "0", dest_len);
      else
        dest_str = g_strdup ("0");
      return (dest_str);
    }

  len += len / 3;
  if (dest_str != NULL && len > dest_len)
    {
      
      for (i=0; i<dest_len - 1; i++)
        dest_str[i] = 'X';
      dest_str[dest_len - 1] = '\0';
      return (dest_str);
    }

  if (dest_str == NULL)
    dest = g_malloc0 (len);
  else
    dest = dest_str;

#if defined (_LARGEFILE_SOURCE)
  g_snprintf (src, sizeof (src), "%lld", number);
#else
  g_snprintf (src, sizeof (src), "%ld", number);
#endif

  num = strlen (src) / 3 - 1;
  rem = strlen (src) % 3;
  frompos = src;
  topos = dest;
  for (i = 0; i < rem; i++)
    *topos++ = *frompos++;

  if (*frompos != '\0')
    {
      if (rem != 0)
	*topos++ = ',';
      while (num > 0)
	{
	  for (i = 0; i < 3; i++)
	    *topos++ = *frompos++;
	  *topos++ = ',';
	  num--;
	}
      for (i = 0; i < 3; i++)
	*topos++ = *frompos++;
    }
  *topos = '\0';
  return (dest);
}


long
file_countlf (int filefd, long endpos)
{
  char tempstr[255];
  long num, mypos;
  ssize_t n;
  int i;

  mypos = num = 0;
  lseek (filefd, 0, SEEK_SET);
  while ((n = read (filefd, tempstr, sizeof (tempstr))) > 0)
    {
      for (i = 0; i < n; i++)
	{
	  if ((tempstr[i] == '\n') && (i > 0) && (tempstr[i - 1] != '\r')
	      && (endpos == 0 || mypos + i <= endpos))
	    ++num;
	}
      mypos += n;
    }
  lseek (filefd, 0, SEEK_SET);
  return (num);
}


char *
alltrim (char *str)
{
  char *pos, *newpos;
  int diff;

  pos = str + strlen (str) - 1;
  while (pos >= str && *pos == ' ')
    *pos-- = '\0';

  pos = str;
  diff = 0;
  while (*pos++ == ' ')
    diff++;

  if (diff == 0)
    return (str);

  pos = str + diff;
  newpos = str;
  while (*pos != '\0')
    *newpos++ = *pos++;
  *newpos = '\0';

  return (str);
}


char *
expand_path (const char *src)
{
  char *str, *pos, *endpos, *prevpos, *newstr, *tempstr, tempchar;
  struct passwd *pw;

  pw = NULL;
  str = g_malloc (strlen (src) + 1);
  strcpy (str, src);

  if (*str == '~')
    {
      if (*(str + 1) == '/' || *(str + 1) == '\0')
	pw = getpwuid (geteuid ());
      else
	{
          if ((pos = strchr (str, '/')) != NULL)
	    *pos = '\0';

	  pw = getpwnam (str + 1);

          if (pos != NULL)
            *pos = '/';
	}
    }

  endpos = str;
  newstr = NULL;
  while ((pos = strchr (endpos, '/')) != NULL)
    {
      pos++;
      while (*pos == '/')
        pos++;
      if ((endpos = strchr (pos, '/')) == NULL)
	endpos = pos + strlen (pos);
      tempchar = *endpos;
      *endpos = '\0';
      if (strcmp (pos, "..") == 0)
	{
	  *(pos - 1) = '\0';
	  if (newstr != NULL && (prevpos = strrchr (newstr, '/')) != NULL)
	    *prevpos = '\0';
	}
      else if (strcmp (pos, ".") != 0)
	{
	  if (newstr == NULL)
	    newstr = g_strdup (pos - 1);
	  else
	    {
	      tempstr = g_strconcat (newstr, pos - 1, NULL);
	      g_free (newstr);
	      newstr = tempstr;
	    }
	}
      *endpos = tempchar;
      if (*endpos == '\0')
	break;
      endpos = pos + 1;
    }

  if (newstr == NULL || *newstr == '\0')
    {
      if (newstr != NULL)
	g_free (newstr);
      newstr = g_malloc0 (2);
      *newstr = '/';
    }

  g_free (str);

  if (pw != NULL)
    {
      if ((pos = strchr (newstr, '/')) == NULL)
	{
	  str = g_malloc (strlen (pw->pw_dir) + 1);
	  strcpy (str, pw->pw_dir);
	}
      else
	str = g_strconcat (pw->pw_dir, pos, NULL);

      g_free (newstr);
      newstr = str;
    }

  return (newstr);
}


void
remove_double_slashes (char *string)
{
  char *newpos, *oldpos;

  oldpos = newpos = string;
  while (*oldpos != '\0')
    {
      *newpos++ = *oldpos++;
      if (*oldpos == '\0')
	break;
      while (*(newpos - 1) == '/' && *(oldpos) == '/')
	oldpos++;
    }
  *newpos = '\0';
  if (string[strlen (string) - 1] == '/')
    string[strlen (string) - 1] = '\0';
}


void
make_nonnull (char **str)
{
  if (*str == NULL)
    *str = g_malloc0 (1);
}


int
copyfile (char *source, char *dest)
{
  int srcfd, destfd;
  char buf[8192];
  ssize_t n;

  if ((srcfd = open (source, O_RDONLY)) == -1)
    {
      printf (_("Error: Cannot open local file %s: %s\n"),
              source, g_strerror (errno));
      exit (1);
    }

  if ((destfd = open (dest, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
    {
      printf (_("Error: Cannot open local file %s: %s\n"),
              dest, g_strerror (errno));
      close (srcfd);
      exit (1);
    }

  while ((n = read (srcfd, buf, sizeof (buf))) > 0)
    {
      if (write (destfd, buf, n) == -1)
        {
          printf (_("Error: Could not write to socket: %s\n"), 
                  g_strerror (errno));
          exit (1);
        }
    }

  if (n == -1)
    {
      printf (_("Error: Could not read from socket: %s\n"), g_strerror (errno));
      exit (1);
    }

  close (srcfd);
  close (destfd);

  return (1);
}


int
gftp_match_filespec (char *filename, char *filespec)
{
  char *filepos, *wcpos, *pos, *newpos, search_str[20];
  size_t len, curlen;
  
  if (filename == NULL || *filename == '\0' || 
      filespec == NULL || *filespec == '\0') 
    return(1);

  filepos = filename;
  wcpos = filespec;
  while(1) 
    {
      if (*wcpos == '\0') 
        return (1);
      else if (*filepos == '\0') 
        return(0);
      else if(*wcpos == '?') 
        {
          wcpos++;
          filepos++;
        }
      else if(*wcpos == '*' && *(wcpos+1) == '\0') 
        return(1);
      else if(*wcpos == '*') 
        {
          len = sizeof (search_str);
          for (pos = wcpos + 1, newpos = search_str, curlen = 0;
               *pos != '*' && *pos != '?' && *pos != '\0' && curlen < len;
               curlen++, *newpos++ = *pos++);
          *newpos = '\0';

          if ((filepos = strstr (filepos, search_str)) == NULL)
            return(0);
          wcpos += curlen + 1;
          filepos += curlen;
        }
      else if(*wcpos++ != *filepos++) 
        return(0);
    }
  return (1);
}


int
gftp_parse_command_line (int *argc, char ***argv)
{
  if (*argc > 1)
    {
      if (strcmp (argv[0][1], "--help") == 0 || strcmp (argv[0][1], "-h") == 0)
	gftp_usage ();
      else if (strcmp (argv[0][1], "--version") == 0 || strcmp (argv[0][1], "-v") == 0)
	{
	  printf ("%s\n", version);
	  exit (0);
	}
    }
  return (0);
}


void
gftp_usage (void)
{
  printf (_("usage: gftp [[ftp://][user:[pass]@]ftp-site[:port][/directory]]\n"));
  exit (0);
}


char *
get_xpm_path (char *filename, int quit_on_err)
{
  char *tempstr, *exfile;

  tempstr = g_strconcat (BASE_CONF_DIR, "/", filename, NULL);
  exfile = expand_path (tempstr);
  g_free (tempstr);
  if (access (exfile, F_OK) != 0)
    {
      g_free (exfile);
      tempstr = g_strconcat (SHARE_DIR, "/", filename, NULL);
      exfile = expand_path (tempstr);
      g_free (tempstr);
      if (access (exfile, F_OK) != 0)
	{
	  g_free (exfile);
	  exfile = g_strconcat ("/usr/share/icons/", filename, NULL);
	  if (access (exfile, F_OK) != 0)
	    {
	      g_free (exfile);
	      if (!quit_on_err)
		return (NULL);
	      printf (_("gFTP Error: Cannot find file %s in %s or %s\n"),
		      filename, SHARE_DIR, BASE_CONF_DIR);
	      exit (-1);
	    }
	}
    }
  return (exfile);
}


gint
string_hash_compare (gconstpointer path1, gconstpointer path2)
{
  return (strcmp ((char *) path1, (char *) path2) == 0);
}


guint
string_hash_function (gconstpointer key)
{
  return (((char *) key)[0] + ((char *) key)[1] + ((char *) key)[2]);
}


void
free_file_list (GList * filelist)
{
  gftp_file * tempfle;
  GList * templist;

  templist = filelist;
  while (templist != NULL)
    {
      tempfle = templist->data;
      free_fdata (tempfle);
      templist = templist->next;
    }
  g_list_free (filelist);
}


void
free_fdata (gftp_file * fle)
{
  if (fle->file)
    g_free (fle->file);
  if (fle->user)
    g_free (fle->user);
  if (fle->group)
    g_free (fle->group);
  if (fle->attribs)
    g_free (fle->attribs);
  if (fle->destfile)
    g_free (fle->destfile);
  if (fle->fd > 0)
    close (fle->fd);
  g_free (fle);
}


gftp_file *
copy_fdata (gftp_file * fle)
{
  gftp_file * newfle;

  newfle = g_malloc0 (sizeof (*newfle));
  memcpy (newfle, fle, sizeof (*newfle));

  if (fle->file)
    {
      newfle->file = g_malloc (strlen (fle->file) + 1);
      strcpy (newfle->file, fle->file);
    }

  if (fle->user)
    {
      newfle->user = g_malloc (strlen (fle->user) + 1);
      strcpy (newfle->user, fle->user);
    }

  if (fle->group)
    {
      newfle->group = g_malloc (strlen (fle->group) + 1);
      strcpy (newfle->group, fle->group);
    }

  if (fle->attribs)
    {
      newfle->attribs = g_malloc (strlen (fle->attribs) + 1);
      strcpy (newfle->attribs, fle->attribs);
    }

  if (fle->destfile)
    {
      newfle->destfile = g_malloc (strlen (fle->destfile) + 1);
      strcpy (newfle->destfile, fle->destfile);
    }
  return (newfle);
}


void
swap_socks (gftp_request * dest, gftp_request * source)
{
  dest->sockfd = source->sockfd;
  dest->datafd = source->datafd;
  dest->cached = 0;
  if (!source->always_connected)
    {
      source->sockfd = -1;
      source->datafd = -1;
      source->cached = 1;
    }
}


int
compare_request (gftp_request * request1, gftp_request * request2,
                 int compare_dirs)
{
  char *strarr[3][2];
  int i, ret;

  ret = 1;
  if (strcmp (request1->protocol_name, request2->protocol_name) == 0 &&
      request1->port == request2->port)
    {
      strarr[0][0] = request1->hostname;
      strarr[0][1] = request2->hostname;
      strarr[1][0] = request1->username;
      strarr[1][1] = request2->username;
      if (compare_dirs)
        {
          strarr[2][0] = request1->directory;
          strarr[2][1] = request2->directory;
        }
      else
        strarr[2][0] = strarr[2][1] = "";

      for (i = 0; i < 3; i++)
        {
          if ((strarr[i][0] && !strarr[i][1]) ||
              (!strarr[i][0] && strarr[i][1]))
            {
              ret = 0;
              break;
            }

          if (strarr[i][0] && strarr[i][1] &&
              strcmp (strarr[i][0], strarr[i][1]) != 0)
            {
              ret = 0;
              break;
            }
        }
    }
  else
    ret = 0;
  return (ret);
}


void
free_tdata (gftp_transfer * tdata)
{
  if (tdata->statmutex)
    g_free (tdata->statmutex);
  if (tdata->structmutex)
    g_free (tdata->structmutex);
  if (tdata->fromreq != NULL)
    gftp_request_destroy (tdata->fromreq);
  if (tdata->toreq != NULL)
    gftp_request_destroy (tdata->toreq);
  free_file_list (tdata->files);
  g_free (tdata);
}


gftp_request * 
copy_request (gftp_request * req)
{
  gftp_request * newreq;

  newreq = g_malloc0 (sizeof (*newreq));
  memcpy (newreq, req, sizeof (*newreq));

  if (req->hostname)
    newreq->hostname = g_strdup (req->hostname);
  if (req->username)
    newreq->username = g_strdup (req->username);
  if (req->password)
    newreq->password = g_strdup (req->password);
  if (req->account)
    newreq->account = g_strdup (req->account);
  if (req->directory)
    newreq->directory = g_strdup (req->directory);

  newreq->url_prefix = NULL;
  newreq->protocol_name = NULL;
  newreq->sftpserv_path = NULL;
  newreq->proxy_config = NULL;
  newreq->proxy_hostname = NULL;
  newreq->proxy_username = NULL;
  newreq->proxy_password = NULL;
  newreq->proxy_account = NULL;
  newreq->last_ftp_response = NULL;
  newreq->last_dir_entry = NULL;
  newreq->sockfd = -1;
  newreq->datafd = -1;
  newreq->cachefd = -1;
  newreq->hostp = NULL;
  
  if (req->proxy_config != NULL)
    newreq->proxy_config = g_strdup (req->proxy_config);

  req->init (newreq);

  return (newreq);
}


int
ptym_open (char *pts_name)
{
  int fd;

#ifdef __sgi
  char *tempstr;

  if ((tempstr = _getpty (&fd, O_RDWR, 0600, 0)) == NULL)
    return (-1);

  strcpy (pts_name, tempstr);
  return (fd);

#else /* !__sgi */

#ifdef SYSV

  char *tempstr;

  strcpy (pts_name, "/dev/ptmx");
  if ((fd = open (pts_name, O_RDWR)) < 0)
    return (-1);

  if (grantpt (fd) < 0)
    {
      close (fd);
      return (-1);
    }

  if (unlockpt (fd) < 0)
    {
      close (fd);
      return (-1);
    }

  if ((tempstr = ptsname (fd)) == NULL)
    {
      close (fd);
      return (-1);
    }

  strcpy (pts_name, tempstr);
  return (fd);

#else /* !SYSV */

  char *pos1, *pos2;

  strcpy (pts_name, "/dev/ptyXY");
  for (pos1 = "pqrstuvwxyzPQRST"; *pos1 != '\0'; pos1++) 
    {
      pts_name[8] = *pos1;
      for (pos2 = "0123456789abcdef"; *pos2 != '\0'; pos2++)
        {
          pts_name[9] = *pos2;
          if ((fd = open (pts_name, O_RDWR)) < 0)
            continue;
          pts_name[5] = 't';
          return (fd);
        }
    }
  return (-1);

#endif

#endif

}


int
ptys_open (int fdm, char *pts_name)
{
  int fds;

#if !defined (SYSV) && !defined (__sgi)

  chmod (pts_name, S_IRUSR | S_IWUSR);
  chown (pts_name, getuid (), -1);

#endif

  if ((fds = open (pts_name, O_RDWR)) < 0)
    {
      close (fdm);
      return (-1);
    }

#ifdef SYSV

  if (ioctl (fds, I_PUSH, "ptem") < 0)
    {
      close (fdm);
      close (fds);
      return (-1);
    }

  if (ioctl (fds, I_PUSH, "ldterm") < 0)
    {
      close (fdm);
      close (fds);
      return (-1);
    }

  if (ioctl (fds, I_PUSH, "ttcompat") < 0)
    {
      close (fdm);
      close (fds);
      return (-1);
    }

#endif

#if !defined(SYSV) && !defined (__sgi) && defined(TIOCSCTTY) && !defined(CIBAUD)

  if (ioctl (fds, TIOCSCTTY, (char *) 0) < 0)
    {
      close (fdm);
      return (-1);
    }

#endif

  return (fds);
}


int
tty_raw (int fd)
{
  struct termios buf;

  if (tcgetattr (fd, &buf) < 0)
    return (-1);

  buf.c_iflag |= IGNPAR;
  buf.c_iflag &= ~(ICRNL | ISTRIP | IXON | IGNCR | IXANY | IXOFF | INLCR);
  buf.c_lflag &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);
#ifdef IEXTEN
  buf.c_lflag &= ~(IEXTEN);
#endif

  buf.c_oflag &= ~(OPOST);
  buf.c_cc[VMIN] = 1;
  buf.c_cc[VTIME] = 0;

  if (tcsetattr (fd, TCSADRAIN, &buf) < 0)
    return (-1);
  return (0);
}


/* We have the caller send us a pointer to a string so we can write the port
   into it. It makes it easier so we don't have to worry about freeing it 
   later on, the caller can just send us an auto variable, The string
   should be at least 6 chars. I know this is messy... */

char **
make_ssh_exec_args (gftp_request * request, char *execname, 
                    int use_sftp_subsys, char *portstring)
{
  char **args, *oldstr, *tempstr;
  struct servent serv_struct;
  int i, j;

  args = g_malloc (sizeof (char *) * (num_ssh_extra_params + 15));

  args[0] = ssh_prog_name != NULL && *ssh_prog_name != '\0' ? 
            ssh_prog_name : "ssh";
  i = 1;
  tempstr = g_strdup (args[0]);

  if (ssh_extra_params_list != NULL)
    {
      for (j=0; ssh_extra_params_list[j] != NULL; j++)
        {
          oldstr = tempstr;
          args[i++] = ssh_extra_params_list[j];
          tempstr = g_strconcat (oldstr, " ", ssh_extra_params_list[j], NULL);
          g_free (oldstr);
        }
    }

  oldstr = tempstr;
  tempstr = g_strconcat (oldstr, " -e none", NULL);
  g_free (oldstr);
  args[i++] = "-e";
  args[i++] = "none";

  if (request->username && *request->username != '\0')
    {
      oldstr = tempstr;
      tempstr = g_strconcat (oldstr, " -l ", request->username, NULL);
      g_free (oldstr);
      args[i++] = "-l";
      args[i++] = request->username;
    }

  if (request->port != 0)
    {
      g_snprintf (portstring, 6, "%d", request->port);
      oldstr = tempstr;
      tempstr = g_strconcat (oldstr, " -p ", portstring, NULL);
      g_free (oldstr);
      args[i++] = "-p";
      args[i++] = portstring;
    }
  else
    {
      if (!r_getservbyname ("ssh", "tcp", &serv_struct, NULL))
        request->port = 22;
      else
        request->port = ntohs (serv_struct.s_port);
    }

  if (use_sftp_subsys)
    {
      oldstr = tempstr;
      tempstr = g_strconcat (oldstr, " ", request->hostname, " -s sftp", NULL);
      g_free (oldstr);
      args[i++] = request->hostname;
      args[i++] = "-s";
      args[i++] = "sftp";
      args[i] = NULL;
    }
  else
    {
      oldstr = tempstr;
      tempstr = g_strconcat (oldstr, " ", request->hostname, " \"", execname, 
                             "\"", NULL);
      g_free (oldstr);
      args[i++] = request->hostname;
      args[i++] = execname;
      args[i] = NULL;
    }

  request->logging_function (gftp_logging_misc, request->user_data, 
                             _("Running program %s\n"), tempstr);
  g_free (tempstr);
  return (args);
}


char *
ssh_start_login_sequence (gftp_request * request, int fd)
{
  size_t rem, len, diff, lastdiff;
  int wrotepw, ok;
  char *tempstr, *pwstr;
  ssize_t rd;

  rem = len = 100;
  tempstr = g_malloc0 (len);
  diff = lastdiff = 0;
  wrotepw = 0;
  ok = 1;

  if (gftp_set_sockblocking (request, request->datafd, 1) == -1)
    return (NULL);

  pwstr = g_strconcat (request->password, "\n", NULL);

  errno = 0;
  while (1)
    {
      if ((rd = gftp_read (request, tempstr + diff, rem -1, fd)) <= 0)
        {
          ok = 0;
          break;
        }
      tempstr[diff + rd] = '\0';
      rem -= rd;
      diff += rd;
      if (rem <= 1)
        {
          tempstr = g_realloc (tempstr, len + 100);
          tempstr[diff] = '\0';
          request->logging_function (gftp_logging_recv, request->user_data,
                                     "%s", tempstr + lastdiff);
          lastdiff = diff;
          len += 100;
          rem = 100;
        }

      if (!wrotepw && 
          strlen (tempstr) > 11 && strcmp (tempstr + strlen (tempstr) - 10, 
                                           "password: ") == 0)
        {
          wrotepw = 1;
          if (gftp_write (request, pwstr, strlen (pwstr), fd) < 0)
            {
              ok = 0;
              break;
            }
        }

      else if (!wrotepw && 
               (strstr (tempstr, "Enter passphrase for RSA key") != NULL ||
               strstr (tempstr, "Enter passphrase for key '") != NULL))
        {
          wrotepw = 1;
          if (gftp_write (request, pwstr, strlen (pwstr), fd) < 0)
            {
              ok = 0;
              break;
            }
        }
      else if (strlen (tempstr) >= 5 && 
               strcmp (tempstr + strlen (tempstr) - 5, "xsftp") == 0)
        break;
    }

  g_free (pwstr);
  tempstr[diff] = '\0';
  request->logging_function (gftp_logging_recv, request->user_data,
                             "%s\n", tempstr + lastdiff);

  if (!ok)
    {
      g_free (tempstr);
      return (NULL);
    }
 
  return (tempstr);
}


#ifdef G_HAVE_GINT64

gint64
hton64 (gint64 val)
{
  gint64 num;
  char *pos;

  num = 0;
  pos = (char *) &num;
  pos[0] = (val >> 56) & 0xff;
  pos[1] = (val >> 48) & 0xff;
  pos[2] = (val >> 40) & 0xff;
  pos[3] = (val >> 32) & 0xff;
  pos[4] = (val >> 24) & 0xff;
  pos[5] = (val >> 16) & 0xff;
  pos[6] = (val >> 8) & 0xff;
  pos[7] = val & 0xff;
  return (num);
}

#endif


static gint
gftp_file_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  return (strcmp (f1->file, f2->file));
}


static gint
gftp_file_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;
  gint ret;

  f1 = a;
  f2 = b;
  ret = strcmp (f1->file, f2->file);
  if (ret < 0)
    ret = 1;
  else if (ret > 0)
    ret = -1;
  return (ret);
}


static gint
gftp_user_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  return (strcmp (f1->user, f2->user));
}


static gint
gftp_user_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;
  gint ret;

  f1 = a;
  f2 = b;
  ret = strcmp (f1->user, f2->user);
  if (ret < 0)
    ret = 1;
  else if (ret > 0)
    ret = -1;
  return (ret);
}


static gint
gftp_group_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  return (strcmp (f1->group, f2->group));
}


static gint
gftp_group_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;
  gint ret;

  f1 = a;
  f2 = b;
  ret = strcmp (f1->group, f2->group);
  if (ret < 0)
    ret = 1;
  else if (ret > 0)
    ret = -1;
  return (ret);
}


static gint
gftp_attribs_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  return (strcmp (f1->attribs, f2->attribs));
}


static gint
gftp_attribs_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;
  gint ret;

  f1 = a;
  f2 = b;
  ret = strcmp (f1->attribs, f2->attribs);
  if (ret < 0)
    ret = 1;
  else if (ret > 0)
    ret = -1;
  return (ret);
}


static gint
gftp_size_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  if (f1->size < f2->size)
    return (-1);
  else if (f1->size == f2->size)
    return (0);
  else
    return (1);
}


static gint
gftp_size_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  if (f1->size < f2->size)
    return (1);
  else if (f1->size == f2->size)
    return (0);
  else
    return (-1);
}


static gint
gftp_datetime_sort_function_as (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  if (f1->datetime < f2->datetime)
    return (-1);
  else if (f1->datetime == f2->datetime)
    return (0);
  else
    return (1);
}


static gint
gftp_datetime_sort_function_ds (gconstpointer a, gconstpointer b)
{
  const gftp_file * f1, * f2;

  f1 = a;
  f2 = b;
  if (f1->datetime < f2->datetime)
    return (1);
  else if (f1->datetime == f2->datetime)
    return (0);
  else
    return (-1);
}


GList *
gftp_sort_filelist (GList * filelist, int column, int asds)
{
  GList * files, * dirs, * dotdot, * tempitem, * insitem;
  GCompareFunc sortfunc;
  gftp_file * tempfle;

  files = dirs = dotdot = NULL;

  if (column == GFTP_SORT_COL_FILE)
    sortfunc = asds ?  gftp_file_sort_function_as : gftp_file_sort_function_ds;
  else if (column == GFTP_SORT_COL_SIZE)
    sortfunc = asds ?  gftp_size_sort_function_as : gftp_size_sort_function_ds;
  else if (column == GFTP_SORT_COL_USER)
    sortfunc = asds ?  gftp_user_sort_function_as : gftp_user_sort_function_ds;
  else if (column == GFTP_SORT_COL_GROUP)
    sortfunc = asds ?
                gftp_group_sort_function_as : gftp_group_sort_function_ds;
  else if (column == GFTP_SORT_COL_DATETIME)
    sortfunc = asds ?
                gftp_datetime_sort_function_as : gftp_datetime_sort_function_ds;  else /* GFTP_SORT_COL_ATTRIBS */
    sortfunc = asds ? 
                gftp_attribs_sort_function_as : gftp_attribs_sort_function_ds;

  for (tempitem = filelist; tempitem != NULL; )
    {
      tempfle = tempitem->data;
      insitem = tempitem;
      tempitem = tempitem->next;
      insitem->next = NULL;

      if (dotdot == NULL && strcmp (tempfle->file, "..") == 0)
        dotdot = insitem;
      else if (sort_dirs_first && tempfle->isdir)
        {
          insitem->next = dirs;
          dirs = insitem;
        }
      else
        {
          insitem->next = files;
          files = insitem;
        }
    }

  if (dirs != NULL)
    dirs = g_list_sort (dirs, sortfunc);
  if (files != NULL)
    files = g_list_sort (files, sortfunc);

  filelist = dotdot;

  if (filelist == NULL)
    filelist = dirs;
  else
    filelist = g_list_concat (filelist, dirs);

  if (filelist == NULL)
    filelist = files;
  else
    filelist = g_list_concat (filelist, files);

  /* I haven't check this, but I'm pretty sure some older versions of glib
     had a bug that the prev pointer wasn't being sent to NULL */
  filelist->prev = NULL;
  return (filelist);
}