transfer.c
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:67k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*****************************************************************************/
  2. /*  transfer.c - functions to handle transfering files                       */
  3. /*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
  4. /*                                                                           */
  5. /*  This program is free software; you can redistribute it and/or modify     */
  6. /*  it under the terms of the GNU General Public License as published by     */
  7. /*  the Free Software Foundation; either version 2 of the License, or        */
  8. /*  (at your option) any later version.                                      */
  9. /*                                                                           */
  10. /*  This program is distributed in the hope that it will be useful,          */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  13. /*  GNU General Public License for more details.                             */
  14. /*                                                                           */
  15. /*  You should have received a copy of the GNU General Public License        */
  16. /*  along with this program; if not, write to the Free Software              */
  17. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  18. /*****************************************************************************/
  19. #include <gftp-gtk.h>
  20. static const char cvsid[] = "$Id: transfer.c,v 1.24 2002/12/05 00:43:07 masneyb Exp $";
  21. static GtkWidget * dialog;
  22. static void 
  23. wakeup_main_thread (gpointer data, gint source, GdkInputCondition condition)
  24. {
  25.   gftp_request * request;
  26.   char c;
  27.  
  28.   request = data; 
  29.   if (request->wakeup_main_thread[0] > 0)
  30.     read (request->wakeup_main_thread[0], &c, 1);
  31. }
  32. static gint
  33. setup_wakeup_main_thread (gftp_request * request)
  34. {
  35.   gint handler;
  36.   if (socketpair (AF_UNIX, SOCK_STREAM, 0, request->wakeup_main_thread) == 0)
  37.     {
  38.       handler = gdk_input_add (request->wakeup_main_thread[0], 
  39.                                GDK_INPUT_READ, wakeup_main_thread, request);
  40.     }
  41.   else
  42.     {
  43.       request->wakeup_main_thread[0] = 0;
  44.       request->wakeup_main_thread[1] = 0;
  45.       handler = 0;
  46.     }
  47.   return (handler);
  48. }
  49. static void
  50. teardown_wakeup_main_thread (gftp_request * request, gint handler)
  51. {
  52.   if (request->wakeup_main_thread[0] > 0 && request->wakeup_main_thread[1] > 0)
  53.     {
  54.       gdk_input_remove (handler);
  55.       close (request->wakeup_main_thread[0]);
  56.       close (request->wakeup_main_thread[1]);
  57.       request->wakeup_main_thread[0] = 0;
  58.       request->wakeup_main_thread[1] = 0;
  59.     }
  60. }
  61. static void *
  62. getdir_thread (void * data)
  63. {
  64.   int sj, havedotdot, got;
  65.   gftp_request * request;
  66.   gftp_file * fle;
  67.   GList * files;
  68.   request = data;
  69.   
  70.   if (request->use_threads)
  71.     {
  72.       sj = sigsetjmp (jmp_environment, 1);
  73.       use_jmp_environment = 1;
  74.     }
  75.   else
  76.     sj = 0;
  77.   files = NULL;
  78.   if (sj == 0 || sj == 2)
  79.     {
  80.       if (gftp_list_files (request) != 0 || !GFTP_IS_CONNECTED (request))
  81.         {
  82.           if (request->use_threads)
  83.             use_jmp_environment = 0;
  84.           request->stopable = 0;
  85.           if (request->wakeup_main_thread[1] > 0)
  86.             write (request->wakeup_main_thread[1], " ", 1);
  87.           return (NULL);
  88.         }
  89.       request->gotbytes = 0; 
  90.       havedotdot = 0; 
  91.       fle = g_malloc0 (sizeof (*fle));
  92.       while ((got = gftp_get_next_file (request, NULL, fle)) > 0)
  93.         { 
  94.           request->gotbytes += got;
  95.           if (strcmp (fle->file, ".") == 0)
  96.             {
  97.               gftp_file_destroy (fle);
  98.               continue;
  99.             }
  100.           else if (strcmp (fle->file, "..") == 0)
  101.             havedotdot = 1;
  102.           files = g_list_append (files, fle);
  103.           fle = g_malloc0 (sizeof (*fle));
  104.         }
  105.       g_free (fle);
  106.       if (!GFTP_IS_CONNECTED (request))
  107.         {
  108.           if (request->use_threads)
  109.             use_jmp_environment = 0;
  110.           request->stopable = 0;
  111.           if (request->wakeup_main_thread[1] > 0)
  112.             write (request->wakeup_main_thread[1], " ", 1);
  113.           return (NULL);
  114.         }
  115.       gftp_end_transfer (request); 
  116.       request->gotbytes = -1; 
  117.       if (!havedotdot)
  118.         {
  119.           fle = g_malloc0 (sizeof (*fle));
  120.           fle->file = g_malloc (3);
  121.           strcpy (fle->file, "..");
  122.           fle->user = g_malloc0 (1);
  123.           fle->group = g_malloc0 (1);
  124.           fle->attribs = g_malloc0 (1);
  125.           *fle->attribs = '';
  126.           fle->isdir = 1;
  127.           files = g_list_prepend (files, fle);
  128.         }
  129.     }
  130.   if (request->use_threads)
  131.     use_jmp_environment = 0;
  132.   request->stopable = 0;
  133.   if (request->wakeup_main_thread[1] > 0)
  134.     write (request->wakeup_main_thread[1], " ", 1);
  135.   return (files);
  136. }
  137. int
  138. ftp_list_files (gftp_window_data * wdata, int usecache)
  139. {
  140.   guint handler;
  141.   void *success;
  142.   gtk_label_set (GTK_LABEL (wdata->hoststxt), _("Receiving file names..."));
  143.   wdata->show_selected = 0;
  144.   if (wdata->files == NULL)
  145.     {
  146.       if (check_reconnect (wdata) < 0)
  147.         return (0);
  148.       gtk_clist_freeze (GTK_CLIST (wdata->listbox));
  149.       wdata->request->stopable = 1;
  150.       if (wdata->request->use_threads)
  151.         {
  152.           gtk_widget_set_sensitive (stop_btn, 1);
  153.           handler = setup_wakeup_main_thread (wdata->request);
  154.           pthread_create (&wdata->tid, NULL, getdir_thread, wdata->request);
  155.           while (wdata->request->stopable)
  156.             {
  157.               GDK_THREADS_LEAVE ();
  158. #if GTK_MAJOR_VERSION == 1
  159.               g_main_iteration (TRUE);
  160. #else
  161.               g_main_context_iteration (NULL, TRUE);
  162. #endif
  163.             }
  164.           teardown_wakeup_main_thread (wdata->request, handler);
  165.           pthread_join (wdata->tid, &success);
  166.           gtk_widget_set_sensitive (stop_btn, 0);
  167.         }
  168.       else
  169.         success = getdir_thread (wdata->request);
  170.       wdata->files = success;
  171.       gtk_clist_thaw (GTK_CLIST (wdata->listbox));
  172.       memset (&wdata->tid, 0, sizeof (wdata->tid));
  173.     }
  174.   
  175.   if (wdata->files == NULL || !GFTP_IS_CONNECTED (wdata->request))
  176.     {
  177.       disconnect (wdata);
  178.       return (0);
  179.     }
  180.   wdata->sorted = 0;
  181.   sortrows (GTK_CLIST (wdata->listbox), *wdata->sortcol, (gpointer) wdata);
  182.   if (IS_NONE_SELECTED (wdata))
  183.     gtk_clist_select_row (GTK_CLIST (wdata->listbox), 0, 0);
  184.   return (1);
  185. }
  186. static void
  187. try_connect_again (gftp_request * request, gftp_dialog_data * ddata)
  188. {
  189.   gftp_set_password (request, gtk_entry_get_text (GTK_ENTRY (ddata->edit)));
  190.   request->stopable = 0;
  191. }
  192. static void
  193. dont_connect_again (gftp_request * request, gftp_dialog_data * ddata)
  194. {
  195.   request->stopable = 0;
  196. }
  197. static void *
  198. connect_thread (void *data)
  199. {
  200.   static int conn_num;
  201.   gftp_request * request;
  202.   int ret, sj;
  203.   request = data;
  204.   conn_num = 0;
  205.   if (request->use_threads)
  206.     {
  207.       sj = sigsetjmp (jmp_environment, 1);
  208.       use_jmp_environment = 1;
  209.     }
  210.   else
  211.     sj = 0;
  212.   ret = 0;
  213.   if (sj != 0)
  214.     {
  215.       ret = 0;
  216.       gftp_disconnect (request);
  217.     }
  218.   while (sj != 1 && (request->retries == 0 || conn_num < request->retries))
  219.     {
  220.       conn_num++;
  221.       if (request->network_timeout > 0)
  222.         alarm (request->network_timeout);
  223.       ret = gftp_connect (request) == 0;
  224.       alarm (0);
  225.       if (ret)
  226.         break;
  227.       else if (request->retries == 0 || conn_num < request->retries)
  228.         {
  229.           request->logging_function (gftp_logging_misc, request->user_data,
  230.                      _("Waiting %d seconds until trying to connect againn"),
  231.      request->sleep_time);
  232.           alarm (request->sleep_time);
  233.           pause ();
  234.         }  
  235.     }
  236.   if (request->use_threads)
  237.     use_jmp_environment = 0;
  238.   request->stopable = 0;
  239.   if (request->wakeup_main_thread[1] > 0)
  240.     write (request->wakeup_main_thread[1], " ", 1);
  241.   return ((void *) ret);
  242. }
  243. int
  244. ftp_connect (gftp_window_data * wdata, gftp_request * request, int getdir)
  245. {
  246.   int success;
  247.   guint handler;
  248.   void *ret;
  249.   ret = 0;
  250.   if (wdata->request == request)
  251.     {
  252.       gtk_label_set (GTK_LABEL (wdata->hoststxt), _("Connecting..."));
  253.     }
  254.   if (request->need_userpass && request->username != NULL &&
  255.       *request->username != '' &&
  256.       (request->password == NULL || *request->password == ''))
  257.     {
  258.       if (wdata && wdata->request == request)
  259.         {
  260.           request->stopable = 1;
  261.           MakeEditDialog (_("Enter Password"),
  262.                           _("Please enter your password for this site"), NULL,
  263.                           0, NULL, gftp_dialog_button_connect, 
  264.                           try_connect_again, request, 
  265.                           dont_connect_again, request);
  266.           while (request->stopable)
  267.             {
  268.               GDK_THREADS_LEAVE ();
  269. #if GTK_MAJOR_VERSION == 1
  270.               g_main_iteration (TRUE);
  271. #else
  272.               g_main_context_iteration (NULL, TRUE);
  273. #endif
  274.             }
  275.           if (GFTP_GET_PASSWORD (request) == NULL || 
  276.               *GFTP_GET_PASSWORD (request) == '')
  277.             return (0);
  278.         }
  279.       else
  280.         gftp_set_password (request, "");
  281.     }
  282.   if (wdata && wdata->request == request && request->use_threads)
  283.     {
  284.       request->stopable = 1;
  285.       if (wdata)       
  286.         gtk_clist_freeze (GTK_CLIST (wdata->listbox));
  287.       gtk_widget_set_sensitive (stop_btn, 1);
  288.       pthread_create (&wdata->tid, NULL, connect_thread, request);
  289.       handler = setup_wakeup_main_thread (wdata->request);
  290.       while (request->stopable)
  291.         {
  292.           GDK_THREADS_LEAVE ();
  293. #if GTK_MAJOR_VERSION == 1
  294.           g_main_iteration (TRUE);
  295. #else
  296.           g_main_context_iteration (NULL, TRUE);
  297. #endif
  298.         }
  299.       pthread_join (wdata->tid, &ret);
  300.       teardown_wakeup_main_thread (wdata->request, handler);
  301.       gtk_widget_set_sensitive (stop_btn, 0);
  302.       if (wdata)
  303.         gtk_clist_thaw (GTK_CLIST (wdata->listbox));
  304.     }
  305.   else
  306.     ret = connect_thread (request);
  307.   success = (int) ret;
  308.   memset (&wdata->tid, 0, sizeof (wdata->tid));
  309.   if (!GFTP_IS_CONNECTED (wdata->request))
  310.     disconnect (wdata);
  311.   else if (success)
  312.     {
  313.       ftp_list_files (wdata, 1);
  314.       if (!GFTP_IS_CONNECTED (wdata->request))
  315.         disconnect (wdata);
  316.     }
  317.   return (success);
  318. }
  319. void 
  320. get_files (gpointer data)
  321. {
  322.   transfer_window_files (&window2, &window1);
  323. }
  324. void
  325. put_files (gpointer data)
  326. {
  327.   transfer_window_files (&window1, &window2);
  328. }
  329. void
  330. transfer_window_files (gftp_window_data * fromwdata, gftp_window_data * towdata)
  331. {
  332.   gftp_file * tempfle, * newfle;
  333.   GList * templist, * filelist;
  334.   gftp_transfer * transfer;
  335.   guint timeout_num;
  336.   void *ret;
  337.   int num;
  338.   if (!check_status (_("Transfer Files"), fromwdata, 1, 0, 1,
  339.        towdata->request->put_file != NULL && fromwdata->request->get_file != NULL))
  340.     return;
  341.   if (!GFTP_IS_CONNECTED (fromwdata->request) || 
  342.       !GFTP_IS_CONNECTED (towdata->request))
  343.     {
  344.       ftp_log (gftp_logging_misc, NULL,
  345.                _("Retrieve Files: Not connected to a remote siten"));
  346.       return;
  347.     }
  348.   if (check_reconnect (fromwdata) < 0 || check_reconnect (towdata) < 0)
  349.     return;
  350.   transfer = g_malloc0 (sizeof (*transfer));
  351.   transfer->fromreq = copy_request (fromwdata->request);
  352.   transfer->toreq = copy_request (towdata->request);
  353.   transfer->transfer_direction = fromwdata == &window2 ? 
  354.                            GFTP_DIRECTION_DOWNLOAD : GFTP_DIRECTION_UPLOAD;
  355.   transfer->fromwdata = fromwdata;
  356.   transfer->towdata = towdata;
  357.   num = 0;
  358.   templist = GTK_CLIST (fromwdata->listbox)->selection;
  359.   filelist = fromwdata->files;
  360.   while (templist != NULL)
  361.     {
  362.       templist = get_next_selection (templist, &filelist, &num);
  363.       tempfle = filelist->data;
  364.       if (strcmp (tempfle->file, "..") != 0)
  365.         {
  366.           newfle = copy_fdata (tempfle);
  367.           transfer->files = g_list_append (transfer->files, newfle);
  368.         }
  369.     }
  370.   if (transfer->files != NULL)
  371.     {
  372.       gftp_swap_socks (transfer->fromreq, fromwdata->request);
  373.       gftp_swap_socks (transfer->toreq, towdata->request);
  374.       if (transfer->fromreq->use_threads || 
  375.           (transfer->toreq && transfer->toreq->use_threads))
  376.         {
  377.           transfer->fromreq->stopable = 1;
  378.           pthread_create (&fromwdata->tid, NULL, do_getdir_thread, transfer);
  379.           timeout_num = gtk_timeout_add (100, progress_timeout, transfer);
  380.           while (transfer->fromreq->stopable)
  381.             {
  382.               GDK_THREADS_LEAVE ();
  383. #if GTK_MAJOR_VERSION == 1
  384.               g_main_iteration (TRUE);
  385. #else
  386.               g_main_context_iteration (NULL, TRUE);
  387. #endif
  388.             }
  389.           gtk_timeout_remove (timeout_num);
  390.           transfer->numfiles = transfer->numdirs = -1; 
  391.           update_directory_download_progress (transfer);
  392.           pthread_join (fromwdata->tid, &ret);
  393.         }
  394.       else
  395.         ret = do_getdir_thread (transfer);
  396.       if (!GFTP_IS_CONNECTED (transfer->fromreq))
  397.         {
  398.           disconnect (fromwdata);
  399.           return;
  400.         } 
  401.       if (!GFTP_IS_CONNECTED (transfer->toreq))
  402.         {
  403.           disconnect (towdata);
  404.           return;
  405.         } 
  406.       gftp_swap_socks (fromwdata->request, transfer->fromreq);
  407.       gftp_swap_socks (towdata->request, transfer->toreq);
  408.     }
  409.   if (transfer->files != NULL)
  410.     {
  411.       add_file_transfer (transfer->fromreq, transfer->toreq, 
  412.                          transfer->fromwdata, transfer->towdata, 
  413.                          transfer->files, 0);
  414.       g_free (transfer);
  415.     }
  416.   else
  417.     {
  418.       if (transfer->statmutex)
  419.         pthread_mutex_destroy (transfer->statmutex);
  420.       if (transfer->structmutex)
  421.         pthread_mutex_destroy (transfer->structmutex);
  422.       free_tdata (transfer);
  423.     }
  424. }
  425. void *
  426. do_getdir_thread (void * data)
  427. {
  428.   gftp_transfer * transfer;
  429.   int success, sj;
  430.   transfer = data;
  431.   if (transfer->fromreq->use_threads || 
  432.       (transfer->toreq && transfer->toreq->use_threads))
  433.     {
  434.       sj = sigsetjmp (jmp_environment, 1);
  435.       use_jmp_environment = 1;
  436.     }
  437.   else
  438.     sj = 0;
  439.   success = 0;
  440.   if (sj == 0)
  441.     success = gftp_get_all_subdirs (transfer, NULL) == 0;
  442.   else
  443.     {
  444.       gftp_disconnect (transfer->fromreq);
  445.       if (transfer->toreq)
  446.         gftp_disconnect (transfer->toreq);
  447.       transfer->fromreq->logging_function (gftp_logging_error,
  448.                                            transfer->fromreq->user_data,
  449.                                            _("Operation canceledn"));
  450.     }
  451.   if (transfer->fromreq->use_threads || 
  452.       (transfer->toreq && transfer->toreq->use_threads))
  453.     use_jmp_environment = 0;
  454.   transfer->fromreq->stopable = 0;
  455.   return ((void *) success);
  456. }
  457. static void
  458. gftp_gtk_calc_kbs (gftp_transfer * tdata, ssize_t num_read)
  459. {
  460.   unsigned long waitusecs;
  461.   double difftime, curkbs;
  462.   gftp_file * tempfle;
  463.   struct timeval tv;
  464.   unsigned long toadd;
  465.   gettimeofday (&tv, NULL);
  466.   pthread_mutex_lock (tdata->statmutex);
  467.   tempfle = tdata->curfle->data;
  468.   tdata->trans_bytes += num_read;
  469.   tdata->curtrans += num_read;
  470.   tdata->stalled = 0;
  471.   difftime = (tv.tv_sec - tdata->starttime.tv_sec) + ((double) (tv.tv_usec - tdata->starttime.tv_usec) / 1000000.0);
  472.   if (difftime <= 0)
  473.     tdata->kbs = (double) tdata->trans_bytes / 1024.0;
  474.   else
  475.     tdata->kbs = (double) tdata->trans_bytes / 1024.0 / difftime;
  476.   difftime = (tv.tv_sec - tdata->lasttime.tv_sec) + ((double) (tv.tv_usec - tdata->lasttime.tv_usec) / 1000000.0);
  477.   if (difftime <= 0)
  478.     curkbs = (double) (num_read / 1024.0);
  479.   else
  480.     curkbs = (double) (num_read / 1024.0 / difftime);
  481.   if (tdata->fromreq->maxkbs > 0 &&
  482.       curkbs > tdata->fromreq->maxkbs)
  483.     {
  484.       waitusecs = (double) num_read / 1024.0 / tdata->fromreq->maxkbs * 1000000.0 - difftime;
  485.       if (waitusecs > 0)
  486.         {
  487.           pthread_mutex_unlock (tdata->statmutex);
  488.           difftime += ((double) waitusecs / 1000000.0);
  489.           usleep (waitusecs);
  490.           pthread_mutex_lock (tdata->statmutex);
  491.         }
  492.     }
  493.   /* I don't call gettimeofday (&tdata->lasttime) here because this will use
  494.      less system resources. This will be close enough for what we need */
  495.   difftime += tdata->lasttime.tv_usec / 1000000.0;
  496.   toadd = (long) difftime;
  497.   difftime -= toadd;
  498.   tdata->lasttime.tv_sec += toadd;
  499.   tdata->lasttime.tv_usec = difftime * 1000000.0;
  500.   pthread_mutex_unlock (tdata->statmutex);
  501. }
  502. static int
  503. get_status (gftp_transfer * tdata, ssize_t num_read)
  504. {
  505.   gftp_file * tempfle;
  506.   struct timeval tv;
  507.   pthread_mutex_lock (tdata->structmutex);
  508.   if (tdata->curfle == NULL)
  509.     {
  510.       pthread_mutex_unlock (tdata->structmutex);
  511.       return (-1);
  512.     }
  513.   tempfle = tdata->curfle->data;
  514.   pthread_mutex_unlock (tdata->structmutex);
  515.   gftp_disconnect (tdata->fromreq);
  516.   gftp_disconnect (tdata->toreq);
  517.   if (num_read < 0 || tdata->skip_file)
  518.     {
  519.       if (tdata->fromreq->retries != 0 && tdata->current_file_retries >= tdata->fromreq->retries)
  520.         {
  521.           tdata->fromreq->logging_function (gftp_logging_error, 
  522.                    tdata->fromreq->user_data,
  523.                    _("Error: Remote site %s disconnected. Max retries reached...giving upn"),
  524.                    tdata->fromreq->hostname != NULL ? 
  525.                          tdata->fromreq->hostname : tdata->toreq->hostname);
  526.           return (-1);
  527.         }
  528.       else
  529.         {
  530.           tdata->fromreq->logging_function (gftp_logging_error, 
  531.                      tdata->fromreq->user_data,
  532.                      _("Error: Remote site %s disconnected. Will reconnect in %d secondsn"),
  533.                      tdata->fromreq->hostname != NULL ? 
  534.                            tdata->fromreq->hostname : tdata->toreq->hostname, 
  535.                      tdata->fromreq->sleep_time);
  536.         }
  537.       while (tdata->fromreq->retries == 0 || 
  538.              tdata->current_file_retries <= tdata->fromreq->retries)
  539.         {
  540.           if (!tdata->skip_file)
  541.             {
  542.               tv.tv_sec = tdata->fromreq->sleep_time;
  543.               tv.tv_usec = 0;
  544.               select (0, NULL, NULL, NULL, &tv);
  545.             }
  546.           if (gftp_connect (tdata->fromreq) == 0 &&
  547.               gftp_connect (tdata->toreq) == 0)
  548.             {
  549.               pthread_mutex_lock (tdata->structmutex);
  550.               tdata->resumed_bytes = tdata->resumed_bytes + tdata->trans_bytes - tdata->curresumed - tdata->curtrans;
  551.               tdata->trans_bytes = 0;
  552.               if (tdata->skip_file)
  553.                 {
  554.                   tdata->total_bytes -= tempfle->size;
  555.                   tdata->curtrans = 0;
  556.                   tdata->curfle = tdata->curfle->next;
  557.                   tdata->next_file = 1;
  558.                   tdata->skip_file = 0;
  559.                   tdata->cancel = 0;
  560.                   tdata->fromreq->cancel = 0;
  561.                   tdata->toreq->cancel = 0;
  562.                 }
  563.               else
  564.                 {
  565.                   tempfle->transfer_action = GFTP_TRANS_ACTION_RESUME;
  566.                   tempfle->startsize = tdata->curtrans + tdata->curresumed;
  567.                   /* We decrement this here because it will be incremented in 
  568.                      the loop again */
  569.                   tdata->curresumed = 0;
  570.                   tdata->current_file_number--; /* Decrement this because it 
  571.                                                    will be incremented when we 
  572.                                                    continue in the loop */
  573.                 }
  574.               gettimeofday (&tdata->starttime, NULL);
  575.               pthread_mutex_unlock (tdata->structmutex);
  576.               return (1);
  577.             }
  578.           else
  579.             tdata->current_file_retries++;
  580.         }
  581.     }
  582.   else if (tdata->cancel)
  583.     return (-1);
  584.   return (0);
  585. }
  586. static mode_t
  587. parse_attribs (char *attribs)
  588. {
  589.   mode_t mode;
  590.   int cur;
  591.   cur = 0;
  592.   if (attribs[1] == 'r')
  593.     cur += 4;
  594.   if (attribs[2] == 'w')
  595.     cur += 2;
  596.   if (attribs[3] == 'x' ||
  597.       attribs[3] == 's')
  598.     cur += 1;
  599.   mode = cur;
  600.   cur = 0;
  601.   if (attribs[4] == 'r')
  602.     cur += 4;
  603.   if (attribs[5] == 'w')
  604.     cur += 2;
  605.   if (attribs[6] == 'x' ||
  606.       attribs[6] == 's')
  607.     cur += 1;
  608.   mode = (mode * 10) + cur;
  609.   cur = 0;
  610.   if (attribs[7] == 'r')
  611.     cur += 4;
  612.   if (attribs[8] == 'w')
  613.     cur += 2;
  614.   if (attribs[9] == 'x' ||
  615.       attribs[9] == 's')
  616.     cur += 1;
  617.   mode = (mode * 10) + cur;
  618.   return (mode);
  619. }
  620. void * 
  621. gftp_gtk_transfer_files (void *data)
  622. {
  623.   int i, mode, dl_type, tofd, fromfd, old_from_datatype;
  624.   gftp_transfer * transfer;
  625.   char *tempstr, buf[8192];
  626.   off_t fromsize, total;
  627.   gftp_file * curfle; 
  628.   ssize_t num_read;
  629.   pthread_detach (pthread_self ());
  630.   transfer = data;
  631.   transfer->curfle = transfer->files;
  632.   gettimeofday (&transfer->starttime, NULL);
  633.   memcpy (&transfer->lasttime, &transfer->starttime, 
  634.           sizeof (transfer->lasttime));
  635.   dl_type = transfer->fromreq->data_type;
  636.   old_from_datatype = transfer->fromreq->data_type;
  637.   while (transfer->curfle != NULL)
  638.     {
  639.       pthread_mutex_lock (transfer->structmutex);
  640.       curfle = transfer->curfle->data;
  641.       transfer->current_file_number++; 
  642.       pthread_mutex_unlock (transfer->structmutex);
  643.  
  644.       if (curfle->transfer_action == GFTP_TRANS_ACTION_SKIP)
  645.         {
  646.           pthread_mutex_lock (transfer->structmutex);
  647.           transfer->next_file = 1;
  648.           transfer->curfle = transfer->curfle->next;
  649.           pthread_mutex_unlock (transfer->structmutex);
  650.           continue;
  651.         }
  652.       fromsize = -1;
  653.       if (gftp_connect (transfer->fromreq) == 0 &&
  654.           gftp_connect (transfer->toreq) == 0)
  655.         {
  656.           if (curfle->isdir)
  657.             {
  658.               if (transfer->toreq->mkdir != NULL)
  659.                 {
  660.                   transfer->toreq->mkdir (transfer->toreq, curfle->destfile);
  661.                   if (!GFTP_IS_CONNECTED (transfer->toreq))
  662.                     break;
  663.                 }
  664.               pthread_mutex_lock (transfer->structmutex);
  665.               transfer->next_file = 1;
  666.               transfer->curfle = transfer->curfle->next;
  667.               pthread_mutex_unlock (transfer->structmutex);
  668.               continue;
  669.             }
  670.           if (transfer->fromreq->maxkbs > 0)
  671.             {
  672.               transfer->fromreq->logging_function (gftp_logging_misc, 
  673.                             transfer->fromreq->user_data, 
  674.                             _("File transfer will be throttled to %.2f KB/sn"),
  675.                             transfer->fromreq->maxkbs);
  676.             }
  677.           if (curfle->is_fd)
  678.             {
  679.               if (transfer->transfer_direction == GFTP_DIRECTION_DOWNLOAD)
  680.                 {
  681.                   tofd = curfle->fd;
  682.                   fromfd = -1;
  683.                 }
  684.               else
  685.                 {
  686.                   tofd = -1;
  687.                   fromfd = curfle->fd;
  688.                 }
  689.             }
  690.           else
  691.             {
  692.               tofd = -1;
  693.               fromfd = -1;
  694.             }
  695.           if (curfle->size == 0)
  696.             {
  697.               curfle->size = gftp_get_file_size (transfer->fromreq, curfle->file);
  698.               transfer->total_bytes += curfle->size;
  699.             }
  700.           if (GFTP_IS_CONNECTED (transfer->fromreq) &&
  701.               GFTP_IS_CONNECTED (transfer->toreq))
  702.             {
  703.               if (!curfle->ascii && old_from_datatype == GFTP_TYPE_BINARY)
  704.                 dl_type = GFTP_TYPE_BINARY;
  705.               else
  706.                 dl_type = GFTP_GET_DATA_TYPE (transfer->fromreq) == GFTP_TYPE_ASCII || curfle->ascii ? GFTP_TYPE_ASCII : GFTP_TYPE_BINARY;
  707.               if (dl_type != transfer->fromreq->data_type)
  708.                 {
  709.                    if (gftp_set_data_type (transfer->fromreq, dl_type) != 0)
  710.                      gftp_disconnect (transfer->fromreq);
  711.                  }
  712.               if (dl_type != transfer->toreq->data_type)
  713.                 {
  714.                    if (gftp_set_data_type (transfer->toreq, dl_type) != 0)
  715.                      gftp_disconnect (transfer->toreq);
  716.                  }
  717.             }
  718.           if (GFTP_IS_CONNECTED (transfer->fromreq) &&
  719.               GFTP_IS_CONNECTED (transfer->toreq))
  720.             {
  721.               fromsize = gftp_transfer_file (transfer->fromreq, curfle->file, 
  722.                           fromfd,
  723.                           curfle->transfer_action == GFTP_TRANS_ACTION_RESUME ?
  724.                                                     curfle->startsize : 0,
  725.                           transfer->toreq, curfle->destfile, tofd,
  726.                           curfle->transfer_action == GFTP_TRANS_ACTION_RESUME ?
  727.                                                     curfle->startsize : 0);
  728.             }
  729.         }
  730.       if (!GFTP_IS_CONNECTED (transfer->fromreq) || 
  731.           !GFTP_IS_CONNECTED (transfer->toreq))
  732.         {
  733.           transfer->fromreq->logging_function (gftp_logging_misc, 
  734.                          transfer->fromreq->user_data, 
  735.                          _("Error: Remote site disconnected after trying to transfer filen"));
  736.           num_read = -1;
  737.         }
  738.       else if (fromsize < 0)
  739.         {
  740.           if (curfle->is_fd)
  741.             {
  742.               if (transfer->transfer_direction == GFTP_DIRECTION_DOWNLOAD)
  743.                 transfer->toreq->datafd = -1;
  744.               else
  745.                 transfer->fromreq->datafd = -1;
  746.             }
  747.           pthread_mutex_lock (transfer->structmutex);
  748.           curfle->transfer_action = GFTP_TRANS_ACTION_SKIP;
  749.           transfer->next_file = 1;
  750.           transfer->curfle = transfer->curfle->next;
  751.           pthread_mutex_unlock (transfer->structmutex);
  752.           continue;
  753.         }
  754.       else
  755.         {
  756.           pthread_mutex_lock (transfer->structmutex);
  757.           transfer->curtrans = 0;
  758.           transfer->curresumed = curfle->transfer_action == GFTP_TRANS_ACTION_RESUME ? curfle->startsize : 0;
  759.           transfer->resumed_bytes += transfer->curresumed;
  760.           pthread_mutex_unlock (transfer->structmutex);
  761.   
  762.           total = 0;
  763.           i = 0;
  764.           while (!transfer->cancel && 
  765.                  (num_read = gftp_get_next_file_chunk (transfer->fromreq,
  766.                                                        buf, sizeof (buf))) > 0)
  767.             {
  768.               total += num_read;
  769.               gftp_gtk_calc_kbs (transfer, num_read);
  770.               if (dl_type == GFTP_TYPE_ASCII)
  771.                 tempstr = gftp_convert_ascii (buf, &num_read, 1);
  772.               else
  773.                 tempstr = buf;
  774.               if (gftp_put_next_file_chunk (transfer->toreq, tempstr, 
  775.                                             num_read) < 0)
  776.                 {
  777.                   num_read = -1;
  778.                   break;
  779.                 }
  780.               /* We don't have to free tempstr for a download because new 
  781.                  memory is not allocated for it in that case */
  782.               if (dl_type == GFTP_TYPE_ASCII &&
  783.                   transfer->transfer_direction == GFTP_DIRECTION_UPLOAD)
  784.                 g_free (tempstr);
  785.             }
  786.         }
  787.       if (transfer->cancel)
  788.         {
  789.           if (gftp_abort_transfer (transfer->fromreq) != 0)
  790.             gftp_disconnect (transfer->fromreq);
  791.           if (gftp_abort_transfer (transfer->toreq) != 0)
  792.             gftp_disconnect (transfer->toreq);
  793.         }
  794.       else if (num_read < 0)
  795.         {
  796.           transfer->fromreq->logging_function (gftp_logging_misc, 
  797.                                         transfer->fromreq->user_data, 
  798.                                         _("Could not download %s from %sn"), 
  799.                                         curfle->file,
  800.                                         transfer->fromreq->hostname);
  801.           if (get_status (transfer, num_read) == 1)
  802.             continue;
  803.           break;
  804.         }
  805.       else
  806.         {
  807.           /* FIXME - this needs cleaned up. NOTE: view/edit file will be 
  808.              broken if the file has to be resumed */
  809.           if (curfle->is_fd)
  810.             {
  811.               if (transfer->transfer_direction == GFTP_DIRECTION_DOWNLOAD)
  812.                 transfer->toreq->datafd = -1;
  813.               else
  814.                 transfer->fromreq->datafd = -1;
  815.             }
  816.           if (gftp_end_transfer (transfer->fromreq) != 0)
  817.             {
  818.               if (get_status (transfer, -1) == 1)
  819.                 continue;
  820.               break;
  821.             }
  822.           gftp_end_transfer (transfer->toreq);
  823.           transfer->fromreq->logging_function (gftp_logging_misc, 
  824.                          transfer->fromreq->user_data, 
  825.                          _("Successfully transferred %s at %.2f KB/sn"),
  826.                          curfle->file, transfer->kbs);
  827.         }
  828.       if (!curfle->is_fd)
  829.         {
  830.           if (curfle->attribs)
  831.             {
  832.               mode = parse_attribs (curfle->attribs);
  833.               if (mode != 0)
  834.                 gftp_chmod (transfer->toreq, curfle->destfile,
  835.                             parse_attribs (curfle->attribs));
  836.             }
  837.           if (curfle->datetime != 0)
  838.             gftp_set_file_time (transfer->toreq, curfle->destfile,
  839.                                 curfle->datetime);
  840.         }
  841.       pthread_mutex_lock (transfer->structmutex);
  842.       transfer->next_file = 1;
  843.       curfle->transfer_done = 1;
  844.       transfer->curfle = transfer->curfle->next;
  845.       pthread_mutex_unlock (transfer->structmutex);
  846.       if (transfer->cancel && !transfer->skip_file)
  847.         break;
  848.       transfer->cancel = 0;
  849.       transfer->fromreq->cancel = 0;
  850.       transfer->toreq->cancel = 0;
  851.     }
  852.   transfer->done = 1; 
  853.   return (NULL);
  854. }
  855. void
  856. add_file_transfer (gftp_request * fromreq, gftp_request * toreq,
  857.                    gftp_window_data * fromwdata, gftp_window_data * towdata, 
  858.                    GList * files, int copy_req)
  859. {
  860.   gftp_curtrans_data * transdata;
  861.   GList * templist, *curfle;
  862.   gftp_transfer * tdata;
  863.   gftp_file * tempfle;
  864.   char *pos, *text[2];
  865.   int dialog;
  866.   for (templist = files; templist != NULL; templist = templist->next)
  867.     { 
  868.       tempfle = templist->data;
  869.       if (tempfle->startsize > 0)
  870.         break;
  871.     }
  872.   dialog = templist != NULL;
  873.   if (append_file_transfers)
  874.     {
  875.       pthread_mutex_lock (&transfer_mutex);
  876.       for (templist = file_transfers; templist != NULL; templist = templist->next)
  877.         {
  878.           tdata = templist->data;
  879.           pthread_mutex_lock (tdata->structmutex);
  880.           if (compare_request (tdata->fromreq, fromreq, 0) &&
  881.               compare_request (tdata->toreq, toreq, 0) &&
  882.               tdata->curfle != NULL)
  883.             {
  884.               if (!copy_req)
  885.                 {
  886.                   gftp_request_destroy (fromreq, 1);
  887.                   gftp_request_destroy (toreq, 1);
  888.                 }
  889.               fromreq = NULL;
  890.               toreq = NULL;
  891.               for (curfle = tdata->curfle; 
  892.                    curfle != NULL && curfle->next != NULL; 
  893.                    curfle = curfle->next);
  894.               if (curfle == NULL)
  895.                 {
  896.                   curfle = files;
  897.                   files->prev = NULL;
  898.                 }
  899.               else
  900.                 {
  901.                   curfle->next = files;
  902.                   files->prev = curfle;
  903.                 }
  904.               for (curfle = files; curfle != NULL; curfle = curfle->next)
  905.                 {
  906.                   tempfle = curfle->data;
  907.                   if (tempfle->isdir)
  908.                     tdata->numdirs++;
  909.                   else
  910.                     tdata->numfiles++;
  911.                   if ((pos = strrchr (tempfle->file, '/')) == NULL)
  912.                     pos = tempfle->file;
  913.                   else
  914.                     pos++;
  915.                   text[0] = pos;
  916.                   if (tempfle->transfer_action == GFTP_TRANS_ACTION_SKIP)
  917.                     text[1] = _("Skipped");
  918.                   else
  919.                     {
  920.                       tdata->total_bytes += tempfle->size;
  921.                       text[1] = _("Waiting...");
  922.                     }
  923.                   tempfle->node = gtk_ctree_insert_node (GTK_CTREE (dlwdw),  
  924.                                                          tdata->node, NULL, text, 5,
  925.                                                          NULL, NULL, NULL, NULL, 
  926.                                                          FALSE, FALSE);
  927.                   transdata = g_malloc (sizeof (*transdata));
  928.                   transdata->transfer = tdata;
  929.                   transdata->curfle = curfle;
  930.                   gtk_ctree_node_set_row_data (GTK_CTREE (dlwdw), tempfle->node, 
  931.                                                transdata);
  932.                 }
  933.               pthread_mutex_unlock (tdata->structmutex);
  934.               break; 
  935.             }
  936.           pthread_mutex_unlock (tdata->structmutex);
  937.         }
  938.       pthread_mutex_unlock (&transfer_mutex);
  939.     }
  940.   else
  941.     templist = NULL;
  942.     
  943.   if (templist == NULL)
  944.     {
  945.       tdata = g_malloc0 (sizeof (*tdata));
  946.       if (copy_req)
  947.         {
  948.           tdata->fromreq = copy_request (fromreq);
  949.           tdata->toreq = copy_request (toreq); 
  950.         }
  951.       else
  952.         {
  953.           tdata->fromreq = fromreq;
  954.           tdata->toreq = toreq; 
  955.         } 
  956.       tdata->transfer_direction = fromwdata && fromwdata == &window1 ?
  957.                             GFTP_DIRECTION_UPLOAD : GFTP_DIRECTION_DOWNLOAD;
  958.       tdata->fromwdata = fromwdata;
  959.       tdata->towdata = towdata;
  960.       if (!dialog)
  961.         tdata->show = tdata->ready = 1;
  962.       tdata->files = files;
  963.       for (curfle = files; curfle != NULL; curfle = curfle->next)
  964.         {
  965.           tempfle = curfle->data;
  966.           if (tempfle->isdir)
  967.             tdata->numdirs++;
  968.           else
  969.             tdata->numfiles++;
  970.         }
  971.       tdata->structmutex = g_malloc (sizeof (pthread_mutex_t));
  972.       pthread_mutex_init (tdata->structmutex, NULL);
  973.       tdata->statmutex = g_malloc (sizeof (pthread_mutex_t));
  974.       pthread_mutex_init (tdata->statmutex, NULL);
  975.       pthread_mutex_lock (&transfer_mutex);
  976.       file_transfers = g_list_append (file_transfers, tdata);
  977.       pthread_mutex_unlock (&transfer_mutex);
  978.       if (dialog)
  979.         gftp_gtk_ask_transfer (tdata);
  980.     }
  981. }
  982. static void
  983. remove_file (char *filename)
  984. {
  985.   if (unlink (filename) == 0)
  986.     ftp_log (gftp_logging_misc, NULL, _("Successfully removed %sn"),
  987.              filename);
  988.   else
  989.     ftp_log (gftp_logging_error, NULL,
  990.              _("Error: Could not remove file %s: %sn"), filename,
  991.              g_strerror (errno));
  992. }
  993. static void
  994. free_edit_data (gftp_viewedit_data * ve_proc)
  995. {
  996.   int i;
  997.   if (ve_proc->filename)
  998.     g_free (ve_proc->filename);
  999.   if (ve_proc->remote_filename)
  1000.     g_free (ve_proc->remote_filename);
  1001.   for (i = 0; ve_proc->argv[i] != NULL; i++)
  1002.     g_free (ve_proc->argv[i]);
  1003.   g_free (ve_proc->argv);
  1004.   g_free (ve_proc);
  1005. }
  1006. static void
  1007. dont_upload (gftp_viewedit_data * ve_proc, gftp_dialog_data * ddata)
  1008. {
  1009.   remove_file (ve_proc->filename);
  1010.   free_edit_data (ve_proc);
  1011. }
  1012. static void
  1013. do_upload (gftp_viewedit_data * ve_proc, gftp_dialog_data * ddata)
  1014. {
  1015.   gftp_file * tempfle;
  1016.   GList * newfile;
  1017.   tempfle = g_malloc0 (sizeof (*tempfle));
  1018.   tempfle->destfile = ve_proc->remote_filename;
  1019.   ve_proc->remote_filename = NULL;
  1020.   tempfle->file = ve_proc->filename;
  1021.   ve_proc->filename = NULL;
  1022.   tempfle->done_rm = 1;
  1023.   newfile = g_list_append (NULL, tempfle);
  1024.   add_file_transfer (ve_proc->fromwdata->request, ve_proc->towdata->request,
  1025.                      ve_proc->fromwdata, ve_proc->towdata, newfile, 1);
  1026.   free_edit_data (ve_proc);
  1027. }
  1028. static void
  1029. check_done_process (void)
  1030. {
  1031.   gftp_viewedit_data * ve_proc;
  1032.   GList * curdata, *deldata;
  1033.   struct stat st;
  1034.   int ret;
  1035.   char *str;
  1036.   pid_t pid;
  1037.   viewedit_process_done = 0;
  1038.   while ((pid = waitpid (-1, &ret, WNOHANG)) > 0)
  1039.     {
  1040.       curdata = viewedit_processes;
  1041.       while (curdata != NULL)
  1042.         {
  1043.   ve_proc = curdata->data;
  1044.           deldata = curdata;
  1045.           curdata = curdata->next;
  1046.   if (ve_proc->pid == pid)
  1047.     {
  1048.       viewedit_processes = g_list_remove_link (viewedit_processes, 
  1049.                                                        deldata);
  1050.       if (ret != 0)
  1051. ftp_log (gftp_logging_error, NULL,
  1052.  _("Error: Child %d returned %dn"), pid, ret);
  1053.       else
  1054. ftp_log (gftp_logging_misc, NULL,
  1055.  _("Child %d returned successfullyn"), pid);
  1056.       if (!ve_proc->view && !ve_proc->dontupload)
  1057. {
  1058.   /* We was editing the file. Upload it */
  1059.   if (stat (ve_proc->filename, &st) == -1)
  1060.     ftp_log (gftp_logging_error, NULL,
  1061.          _("Error: Cannot get information about file %s: %sn"),
  1062.  ve_proc->filename, g_strerror (errno));
  1063.   else if (st.st_mtime == ve_proc->st.st_mtime)
  1064.                     {
  1065.       ftp_log (gftp_logging_misc, NULL,
  1066.           _("File %s was not changedn"),
  1067.        ve_proc->filename);
  1068.                       remove_file (ve_proc->filename);
  1069.                     }
  1070.   else
  1071.     {
  1072.       memcpy (&ve_proc->st, &st, sizeof (ve_proc->st));
  1073.       str = g_strdup_printf (
  1074. _("File %s has changed.nWould you like to upload it?"),
  1075.                         ve_proc->remote_filename);
  1076.       MakeYesNoDialog (_("Edit File"), str, 
  1077.                                        do_upload, ve_proc, 
  1078.                                        dont_upload, ve_proc);
  1079.       g_free (str);
  1080.       continue;
  1081.     }
  1082. }
  1083.               free_edit_data (ve_proc);
  1084.       continue;
  1085.     }
  1086. }
  1087.     }
  1088. }
  1089. static void
  1090. on_next_transfer (gftp_transfer * tdata)
  1091. {
  1092.   gftp_file * tempfle;
  1093.   int fd;
  1094.   tdata->next_file = 0;
  1095.   for (; tdata->updfle != tdata->curfle; tdata->updfle = tdata->updfle->next)
  1096.     {
  1097.       tempfle = tdata->updfle->data;
  1098.       if (tempfle->is_fd)
  1099.         fd = tempfle->fd;
  1100.       else
  1101.         fd = 0;
  1102.       if (tempfle->done_view)
  1103.         {
  1104.           if (tempfle->transfer_action != GFTP_TRANS_ACTION_SKIP)
  1105.             view_file (tempfle->destfile, fd, 1, tempfle->done_rm, 1, 0,
  1106.                        tempfle->file, NULL);
  1107.           if (tempfle->is_fd)
  1108.             {
  1109.               close (tempfle->fd);
  1110.               tempfle->fd = -1;
  1111.             }
  1112.         }
  1113.       else if (tempfle->done_edit)
  1114.         {
  1115.           if (tempfle->transfer_action != GFTP_TRANS_ACTION_SKIP)
  1116.     view_file (tempfle->destfile, fd, 0, tempfle->done_rm, 1, 0,
  1117.                        tempfle->file, NULL);
  1118.           if (tempfle->is_fd)
  1119.             {
  1120.               close (tempfle->fd);
  1121.               tempfle->fd = -1;
  1122.             }
  1123.         }
  1124.       else if (tempfle->done_rm)
  1125. tdata->fromreq->rmfile (tdata->fromreq, tempfle->file);
  1126.       
  1127.       if (tempfle->transfer_action == GFTP_TRANS_ACTION_SKIP)
  1128.         gtk_ctree_node_set_text (GTK_CTREE (dlwdw), tempfle->node, 1,
  1129.             _("Skipped"));
  1130.       else
  1131.         gtk_ctree_node_set_text (GTK_CTREE (dlwdw), tempfle->node, 1,
  1132.             _("Finished"));
  1133.     }
  1134.   if (refresh_files && tdata->curfle && tdata->curfle->next &&
  1135.       compare_request (tdata->toreq, 
  1136.                        ((gftp_window_data *) tdata->towdata)->request, 1))
  1137.     refresh (tdata->towdata);
  1138. }
  1139. static void
  1140. get_trans_password (gftp_request * request, gftp_dialog_data * ddata)
  1141. {
  1142.   gftp_set_password (request, gtk_entry_get_text (GTK_ENTRY (ddata->edit)));
  1143.   request->stopable = 0;
  1144. }
  1145. static void
  1146. cancel_get_trans_password (gftp_transfer * tdata, gftp_dialog_data * ddata)
  1147. {
  1148.   if (tdata->fromreq->stopable == 0)
  1149.     return;
  1150.   pthread_mutex_lock (tdata->structmutex);
  1151.   if (tdata->started)
  1152.     {
  1153.       tdata->cancel = 1;
  1154.       tdata->fromreq->cancel = 1;
  1155.       tdata->toreq->cancel = 1;
  1156.     }
  1157.   else
  1158.     tdata->done = 1;
  1159.   tdata->fromreq->stopable = 0;
  1160.   tdata->toreq->stopable = 0;
  1161.   pthread_mutex_unlock (tdata->structmutex);
  1162.   ftp_log (gftp_logging_misc, NULL, _("Stopping the transfer of %sn"),
  1163.    ((gftp_file *) tdata->curfle->data)->file);
  1164. }
  1165. static void
  1166. show_transfer (gftp_transfer * tdata)
  1167. {
  1168.   GdkPixmap * closedir_pixmap, * opendir_pixmap;
  1169.   GdkBitmap * closedir_bitmap, * opendir_bitmap;
  1170.   gftp_curtrans_data * transdata;
  1171.   gftp_file * tempfle;
  1172.   char *pos, *text[2];
  1173.   GList * templist;
  1174.   gftp_get_pixmap (dlwdw, "open_dir.xpm", &opendir_pixmap, &opendir_bitmap);
  1175.   gftp_get_pixmap (dlwdw, "dir.xpm", &closedir_pixmap, &closedir_bitmap);
  1176.   text[0] = GFTP_GET_HOSTNAME (tdata->fromreq);
  1177.   text[1] = _("Waiting...");
  1178.   tdata->node = gtk_ctree_insert_node (GTK_CTREE (dlwdw), NULL, NULL, text, 5,
  1179.                                        closedir_pixmap, closedir_bitmap, 
  1180.                                        opendir_pixmap, opendir_bitmap, 
  1181.                                        FALSE, 
  1182.                                        tdata->numdirs + tdata->numfiles < 50);
  1183.   transdata = g_malloc (sizeof (*transdata));
  1184.   transdata->transfer = tdata;
  1185.   transdata->curfle = NULL;
  1186.   gtk_ctree_node_set_row_data (GTK_CTREE (dlwdw), tdata->node, transdata);
  1187.   tdata->show = 0;
  1188.   tdata->curfle = tdata->updfle = tdata->files;
  1189.   tdata->total_bytes = 0;
  1190.   for (templist = tdata->files; templist != NULL; templist = templist->next)
  1191.     {
  1192.       tempfle = templist->data;
  1193.       if ((pos = strrchr (tempfle->file, '/')) == NULL)
  1194. pos = tempfle->file;
  1195.       else
  1196. pos++;
  1197.       text[0] = pos;
  1198.       if (tempfle->transfer_action == GFTP_TRANS_ACTION_SKIP)
  1199.         text[1] = _("Skipped");
  1200.       else
  1201.         {
  1202.           tdata->total_bytes += tempfle->size;
  1203.           text[1] = _("Waiting...");
  1204.         }
  1205.       tempfle->node = gtk_ctree_insert_node (GTK_CTREE (dlwdw), tdata->node, 
  1206.                                              NULL, text, 5, NULL, NULL, NULL, 
  1207.                                              NULL, FALSE, FALSE);
  1208.       transdata = g_malloc (sizeof (*transdata));
  1209.       transdata->transfer = tdata;
  1210.       transdata->curfle = templist;
  1211.       gtk_ctree_node_set_row_data (GTK_CTREE (dlwdw), tempfle->node, transdata);
  1212.     }
  1213.   if (!tdata->toreq->stopable && tdata->toreq->need_userpass &&
  1214.       (tdata->toreq->password == NULL || *tdata->toreq->password == ''))
  1215.     {
  1216.       tdata->toreq->stopable = 1;
  1217.       MakeEditDialog (_("Enter Password"),
  1218.       _("Please enter your password for this site"), NULL, 0,
  1219.       NULL, gftp_dialog_button_connect, 
  1220.                       get_trans_password, tdata->toreq,
  1221.       cancel_get_trans_password, tdata);
  1222.     }
  1223.   if (!tdata->fromreq->stopable && tdata->fromreq->need_userpass &&
  1224.       (tdata->fromreq->password == NULL || *tdata->fromreq->password == ''))
  1225.     {
  1226.       tdata->fromreq->stopable = 1;
  1227.       MakeEditDialog (_("Enter Password"),
  1228.       _("Please enter your password for this site"), NULL, 0,
  1229.       NULL, gftp_dialog_button_connect, 
  1230.                       get_trans_password, tdata->fromreq,
  1231.       cancel_get_trans_password, tdata);
  1232.     }
  1233. }
  1234. static void
  1235. transfer_done (GList * node)
  1236. {
  1237.   gftp_curtrans_data * transdata;
  1238.   gftp_request * fromreq;
  1239.   gftp_transfer * tdata;
  1240.   gftp_file * tempfle;
  1241.   GList * templist;
  1242.   tdata = node->data;
  1243.   if (tdata->started)
  1244.     {
  1245.       fromreq = tdata->fromwdata != NULL ? ((gftp_window_data *) tdata->fromwdata)->request : NULL;
  1246.       if (!tdata->fromreq->stopable && tdata->fromwdata &&
  1247.           ((fromreq->sockfd < 0 && fromreq->cached) || fromreq->always_connected) &&
  1248.           (tdata->fromreq->sockfd > 0 || tdata->fromreq->always_connected) &&
  1249.           compare_request (tdata->fromreq, fromreq, 0))
  1250. {
  1251.           gftp_swap_socks (((gftp_window_data *) tdata->towdata)->request, 
  1252.                            tdata->toreq);
  1253.           gftp_swap_socks (((gftp_window_data *) tdata->fromwdata)->request, 
  1254.                            tdata->fromreq);
  1255. }
  1256.       else
  1257.         {
  1258.   gftp_disconnect (tdata->fromreq);
  1259.           gftp_disconnect (tdata->toreq);
  1260.         }
  1261.       if (tdata->towdata != NULL && compare_request (tdata->toreq, 
  1262.                            ((gftp_window_data *) tdata->towdata)->request, 1)) 
  1263. refresh (tdata->towdata);
  1264.       transfer_in_progress--;
  1265.     }
  1266.   if (!tdata->show && tdata->started)
  1267.     {
  1268.       transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), tdata->node);
  1269.       if (transdata != NULL)
  1270.         g_free (transdata);
  1271.       for (templist = tdata->files; templist != NULL; templist = templist->next)
  1272.         {
  1273.           tempfle = templist->data;
  1274.           transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), tempfle->node);
  1275.           if (transdata != NULL)
  1276.             g_free (transdata);
  1277.         }
  1278.           
  1279.       gtk_ctree_remove_node (GTK_CTREE (dlwdw), tdata->node);
  1280.     }
  1281.   pthread_mutex_lock (&transfer_mutex);
  1282.   file_transfers = g_list_remove_link (file_transfers, node);
  1283.   pthread_mutex_unlock (&transfer_mutex);
  1284.   pthread_mutex_destroy (tdata->structmutex);
  1285.   pthread_mutex_destroy (tdata->statmutex);
  1286.   free_tdata (tdata);
  1287. }
  1288. static void
  1289. create_transfer (gftp_transfer * tdata)
  1290. {
  1291.   pthread_t tid;
  1292.   if (!tdata->fromreq->stopable)
  1293.     {
  1294.       if (tdata->fromwdata && 
  1295.           (((gftp_window_data *) tdata->fromwdata)->request->sockfd > 0 ||
  1296.            ((gftp_window_data *) tdata->fromwdata)->request->always_connected) && 
  1297.           !((gftp_window_data *) tdata->fromwdata)->request->stopable &&
  1298.           compare_request (tdata->fromreq, ((gftp_window_data *) tdata->fromwdata)->request, 0))
  1299. {
  1300.           gftp_swap_socks (tdata->toreq, 
  1301.                            ((gftp_window_data *) tdata->towdata)->request);
  1302.           gftp_swap_socks (tdata->fromreq, 
  1303.                            ((gftp_window_data *) tdata->fromwdata)->request);
  1304.   update_window_info ();
  1305. }
  1306.       transfer_in_progress++;
  1307.       tdata->started = 1;
  1308.       tdata->stalled = 1;
  1309.       gtk_ctree_node_set_text (GTK_CTREE (dlwdw), tdata->node, 1,
  1310.        _("Connecting..."));
  1311.       pthread_create (&tid, NULL, gftp_gtk_transfer_files, tdata);
  1312.     }
  1313. }
  1314. static void
  1315. update_file_status (gftp_transfer * tdata)
  1316. {
  1317.   char totstr[100], dlstr[100], gotstr[50], ofstr[50];
  1318.   int hours, mins, secs, pcent, st;
  1319.   double remaining;
  1320.   gftp_file * tempfle;
  1321.   struct timeval tv;
  1322.   pthread_mutex_lock (tdata->statmutex);
  1323.   tempfle = tdata->curfle->data;
  1324.   gettimeofday (&tv, NULL);
  1325.   if ((remaining = (double) (tv.tv_sec - tdata->starttime.tv_sec) + ((double) (tv.tv_usec - tdata->starttime.tv_usec) / 1000000.0)) == 0)
  1326.     remaining = 1.0;
  1327.   remaining = ((double) (tdata->total_bytes - tdata->trans_bytes - tdata->resumed_bytes)) / 1024.0 / tdata->kbs;
  1328.   hours = (off_t) remaining / 3600;
  1329.   remaining -= hours * 3600;
  1330.   mins = (off_t) remaining / 60;
  1331.   remaining -= mins * 60;
  1332.   secs = (off_t) remaining;
  1333.   if (hours < 0 || mins < 0 || secs < 0)
  1334.     {
  1335.       pthread_mutex_unlock (tdata->statmutex);
  1336.       return;
  1337.     }
  1338.   pcent = (int) ((double) (tdata->trans_bytes + tdata->resumed_bytes) / (double) tdata->total_bytes * 100.0);
  1339.   if (pcent < 0 || pcent > 100)
  1340.     pcent = 0;
  1341.   g_snprintf (totstr, sizeof (totstr),
  1342. _("%d%% complete, %02d:%02d:%02d est. time remaining. (File %ld of %ld)"),
  1343. pcent, hours, mins, secs, tdata->current_file_number,
  1344. tdata->numdirs + tdata->numfiles);
  1345.   *dlstr = '';
  1346.   if (!tdata->stalled)
  1347.     {
  1348.       insert_commas (tdata->curtrans + tdata->curresumed, gotstr, sizeof (gotstr));
  1349.       insert_commas (tempfle->size, ofstr, sizeof (ofstr));
  1350.       st = 1;
  1351.       if (tv.tv_sec - tdata->lasttime.tv_sec <= 5)
  1352.         {
  1353.           if (tdata->curfle->next != NULL)
  1354.             {
  1355.               remaining = ((double) (tempfle->size - tdata->curtrans - tdata->curresumed)) / 1024.0 / tdata->kbs;
  1356.               hours = (off_t) remaining / 3600;
  1357.               remaining -= hours * 3600;
  1358.               mins = (off_t) remaining / 60;
  1359.               remaining -= mins * 60;
  1360.               secs = (off_t) remaining;
  1361.             }
  1362.           if (!(hours < 0 || mins < 0 || secs < 0))
  1363.             {
  1364.               g_snprintf (dlstr, sizeof (dlstr),
  1365.                           _("Recv %s of %s at %.2fKB/s, %02d:%02d:%02d est. time remaining"), gotstr, ofstr, tdata->kbs, hours, mins, secs);
  1366.               st = 0;
  1367.             }
  1368.         }
  1369.       if (st)
  1370.         {
  1371.           tdata->stalled = 1;
  1372.           g_snprintf (dlstr, sizeof (dlstr),
  1373.      _("Recv %s of %s, transfer stalled, unknown time remaining"),
  1374.   gotstr, ofstr);
  1375.         }
  1376.     }
  1377.   pthread_mutex_unlock (tdata->statmutex);
  1378.   gtk_ctree_node_set_text (GTK_CTREE (dlwdw), tdata->node, 1, totstr);
  1379.   if (*dlstr != '')
  1380.     gtk_ctree_node_set_text (GTK_CTREE (dlwdw), tempfle->node, 1, dlstr);
  1381. }
  1382. static void
  1383. update_window_transfer_bytes (gftp_window_data * wdata)
  1384. {
  1385.   char *tempstr, *temp1str;
  1386.   if (wdata->request->gotbytes == -1)
  1387.     {
  1388.       update_window_info ();
  1389.       wdata->request->gotbytes = 0;
  1390.     }
  1391.   else
  1392.     {
  1393.       tempstr = insert_commas (wdata->request->gotbytes, NULL, 0);
  1394.       temp1str = g_strdup_printf (_("Retrieving file names...%s bytes"), 
  1395.                                   tempstr);
  1396.       gtk_label_set (GTK_LABEL (wdata->hoststxt), temp1str);
  1397.       g_free (tempstr);
  1398.       g_free (temp1str);
  1399.     }
  1400. }
  1401. gint
  1402. update_downloads (gpointer data)
  1403. {
  1404.   GList * templist, * next;
  1405.   gftp_transfer * tdata;
  1406.   if (file_transfer_logs != NULL)
  1407.     display_cached_logs ();
  1408.   if (window1.request->gotbytes != 0)
  1409.     update_window_transfer_bytes (&window1);
  1410.   if (window2.request->gotbytes != 0)
  1411.     update_window_transfer_bytes (&window2);
  1412.   if (viewedit_process_done)
  1413.     check_done_process ();
  1414.   for (templist = file_transfers; templist != NULL;)
  1415.     {
  1416.       tdata = templist->data;
  1417.       if (tdata->ready)
  1418.         {
  1419.           pthread_mutex_lock (tdata->structmutex);
  1420.   if (tdata->next_file)
  1421.     on_next_transfer (tdata);
  1422.         else if (tdata->show) 
  1423.     show_transfer (tdata);
  1424.   else if (tdata->done)
  1425.     {
  1426.       next = templist->next;
  1427.               pthread_mutex_unlock (tdata->structmutex);
  1428.       transfer_done (templist);
  1429.       templist = next;
  1430.       continue;
  1431.     }
  1432.   if (tdata->curfle != NULL)
  1433.     {
  1434.       if (!tdata->started && start_file_transfers &&
  1435.                   (transfer_in_progress == 0 || !do_one_transfer_at_a_time))
  1436.                 create_transfer (tdata);
  1437.       if (tdata->started)
  1438.                 update_file_status (tdata);
  1439.     }
  1440.           pthread_mutex_unlock (tdata->structmutex);
  1441.         }
  1442.       templist = templist->next;
  1443.     }
  1444.   gtk_timeout_add (500, update_downloads, NULL);
  1445.   return (0);
  1446. }
  1447. void
  1448. start_transfer (gpointer data)
  1449. {
  1450.   gftp_curtrans_data * transdata;
  1451.   GtkCTreeNode * node;
  1452.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1453.     {
  1454.       ftp_log (gftp_logging_misc, NULL,
  1455.        _("There are no file transfers selectedn"));
  1456.       return;
  1457.     }
  1458.   node = GTK_CLIST (dlwdw)->selection->data;
  1459.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1460.   pthread_mutex_lock (transdata->transfer->structmutex);
  1461.   if (!transdata->transfer->started)
  1462.     create_transfer (transdata->transfer);
  1463.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1464. }
  1465. void
  1466. stop_transfer (gpointer data)
  1467. {
  1468.   gftp_curtrans_data * transdata;
  1469.   GtkCTreeNode * node;
  1470.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1471.     {
  1472.       ftp_log (gftp_logging_misc, NULL,
  1473.       _("There are no file transfers selectedn"));
  1474.       return;
  1475.     }
  1476.   node = GTK_CLIST (dlwdw)->selection->data;
  1477.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1478.   pthread_mutex_lock (transdata->transfer->structmutex);
  1479.   if (transdata->transfer->started)
  1480.     {
  1481.       transdata->transfer->cancel = 1;
  1482.       transdata->transfer->fromreq->cancel = 1;
  1483.       transdata->transfer->toreq->cancel = 1;
  1484.       transdata->transfer->skip_file = 0;
  1485.     }
  1486.   else
  1487.     transdata->transfer->done = 1;
  1488.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1489.   ftp_log (gftp_logging_misc, NULL, _("Stopping the transfer on host %sn"),
  1490.    transdata->transfer->fromreq->hostname);
  1491. }
  1492. void
  1493. skip_transfer (gpointer data)
  1494. {
  1495.   gftp_curtrans_data * transdata;
  1496.   GtkCTreeNode * node;
  1497.   gftp_file * curfle;
  1498.   char *file;
  1499.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1500.     {
  1501.       ftp_log (gftp_logging_misc, NULL,
  1502.       _("There are no file transfers selectedn"));
  1503.       return;
  1504.     }
  1505.   node = GTK_CLIST (dlwdw)->selection->data;
  1506.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1507.   pthread_mutex_lock (transdata->transfer->structmutex);
  1508.   if (transdata->transfer->curfle != NULL)
  1509.     {
  1510.       curfle = transdata->transfer->curfle->data;
  1511.       if (transdata->transfer->started)
  1512.         {
  1513.           transdata->transfer->cancel = 1;
  1514.           transdata->transfer->fromreq->cancel = 1;
  1515.           transdata->transfer->toreq->cancel = 1;
  1516.           transdata->transfer->skip_file = 1;
  1517.         }
  1518.       curfle->transfer_action = GFTP_TRANS_ACTION_SKIP;
  1519.       file = curfle->file;
  1520.     }
  1521.   else
  1522.     file = NULL;
  1523.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1524.   ftp_log (gftp_logging_misc, NULL, _("Skipping file %s on host %sn"), 
  1525.            file, transdata->transfer->fromreq->hostname);
  1526. }
  1527. void
  1528. remove_file_transfer (gpointer data)
  1529. {
  1530.   gftp_curtrans_data * transdata;
  1531.   GtkCTreeNode * node;
  1532.   gftp_file * curfle;
  1533.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1534.     {
  1535.       ftp_log (gftp_logging_misc, NULL,
  1536.               _("There are no file transfers selectedn"));
  1537.       return;
  1538.     }
  1539.   node = GTK_CLIST (dlwdw)->selection->data;
  1540.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1541.   if (transdata->curfle == NULL || transdata->curfle->data == NULL)
  1542.     return;
  1543.   curfle = transdata->curfle->data;
  1544.   if (curfle->transfer_action & GFTP_TRANS_ACTION_SKIP)
  1545.     return;
  1546.   pthread_mutex_lock (transdata->transfer->structmutex);
  1547.   curfle->transfer_action = GFTP_TRANS_ACTION_SKIP;
  1548.   if (transdata->transfer->started &&
  1549.       transdata->curfle == transdata->transfer->curfle)
  1550.     {
  1551.       transdata->transfer->cancel = 1;
  1552.       transdata->transfer->fromreq->cancel = 1;
  1553.       transdata->transfer->toreq->cancel = 1;
  1554.       transdata->transfer->skip_file = 1;
  1555.     }
  1556.   else if (transdata->curfle != transdata->transfer->curfle &&
  1557.            !curfle->transfer_done)
  1558.     {
  1559.       gtk_ctree_node_set_text (GTK_CTREE (dlwdw), curfle->node, 1,
  1560.                                _("Skipped"));
  1561.       transdata->transfer->total_bytes -= curfle->size;
  1562.     }
  1563.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1564.   ftp_log (gftp_logging_misc, NULL, _("Skipping file %s on host %sn"),
  1565.            curfle->file, transdata->transfer->fromreq->hostname);
  1566. }
  1567. void
  1568. move_transfer_up (gpointer data)
  1569. {
  1570.   GList * firstentry, * secentry, * lastentry;
  1571.   gftp_curtrans_data * transdata;
  1572.   GtkCTreeNode * node;
  1573.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1574.     {
  1575.       ftp_log (gftp_logging_misc, NULL,
  1576.       _("There are no file transfers selectedn"));
  1577.       return;
  1578.     }
  1579.   node = GTK_CLIST (dlwdw)->selection->data;
  1580.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1581.   if (transdata->curfle == NULL)
  1582.     return;
  1583.   pthread_mutex_lock (transdata->transfer->structmutex);
  1584.   if (transdata->curfle->prev != NULL && (!transdata->transfer->started ||
  1585.       (transdata->transfer->curfle != transdata->curfle && 
  1586.        transdata->transfer->curfle != transdata->curfle->prev)))
  1587.     {
  1588.       if (transdata->curfle->prev->prev == NULL)
  1589.         {
  1590.           firstentry = transdata->curfle->prev;
  1591.           lastentry = transdata->curfle->next;
  1592.           transdata->transfer->files = transdata->curfle;
  1593.           transdata->curfle->next = firstentry;
  1594.           transdata->transfer->files->prev = NULL;
  1595.           firstentry->prev = transdata->curfle;
  1596.           firstentry->next = lastentry;
  1597.           if (lastentry != NULL)
  1598.             lastentry->prev = firstentry;
  1599.         }
  1600.       else
  1601.         {
  1602.           firstentry = transdata->curfle->prev->prev;
  1603.           secentry = transdata->curfle->prev;
  1604.           lastentry = transdata->curfle->next;
  1605.           firstentry->next = transdata->curfle;
  1606.           transdata->curfle->prev = firstentry;
  1607.           transdata->curfle->next = secentry;
  1608.           secentry->prev = transdata->curfle;
  1609.           secentry->next = lastentry;
  1610.           if (lastentry != NULL)
  1611.             lastentry->prev = secentry;
  1612.         }
  1613.       gtk_ctree_move (GTK_CTREE (dlwdw), 
  1614.                       ((gftp_file *) transdata->curfle->data)->node,
  1615.                       transdata->transfer->node, 
  1616.                       transdata->curfle->next != NULL ?
  1617.                           ((gftp_file *) transdata->curfle->next->data)->node :
  1618.                           NULL);
  1619.     }
  1620.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1621. }
  1622. void
  1623. move_transfer_down (gpointer data)
  1624. {
  1625.   GList * firstentry, * secentry, * lastentry;
  1626.   gftp_curtrans_data * transdata;
  1627.   GtkCTreeNode * node;
  1628.   if (GTK_CLIST (dlwdw)->selection == NULL)
  1629.     {
  1630.       ftp_log (gftp_logging_misc, NULL,
  1631.       _("There are no file transfers selectedn"));
  1632.       return;
  1633.     }
  1634.   node = GTK_CLIST (dlwdw)->selection->data;
  1635.   transdata = gtk_ctree_node_get_row_data (GTK_CTREE (dlwdw), node);
  1636.   if (transdata->curfle == NULL)
  1637.     return;
  1638.   pthread_mutex_lock (transdata->transfer->structmutex);
  1639.   if (transdata->curfle->next != NULL && (!transdata->transfer->started ||
  1640.       (transdata->transfer->curfle != transdata->curfle && 
  1641.        transdata->transfer->curfle != transdata->curfle->next)))
  1642.     {
  1643.       if (transdata->curfle->prev == NULL)
  1644.         {
  1645.           firstentry = transdata->curfle->next;
  1646.           lastentry = transdata->curfle->next->next;
  1647.           transdata->transfer->files = firstentry;
  1648.           transdata->transfer->files->prev = NULL;
  1649.           transdata->transfer->files->next = transdata->curfle;
  1650.           transdata->curfle->prev = transdata->transfer->files;
  1651.           transdata->curfle->next = lastentry;
  1652.           if (lastentry != NULL)
  1653.             lastentry->prev = transdata->curfle;
  1654.         }
  1655.       else
  1656.         {
  1657.           firstentry = transdata->curfle->prev;
  1658.           secentry = transdata->curfle->next;
  1659.           lastentry = transdata->curfle->next->next;
  1660.           firstentry->next = secentry;
  1661.           secentry->prev = firstentry;
  1662.           secentry->next = transdata->curfle;
  1663.           transdata->curfle->prev = secentry;
  1664.           transdata->curfle->next = lastentry;
  1665.           if (lastentry != NULL)
  1666.             lastentry->prev = transdata->curfle;
  1667.         }
  1668.       gtk_ctree_move (GTK_CTREE (dlwdw), 
  1669.                       ((gftp_file *) transdata->curfle->data)->node,
  1670.                       transdata->transfer->node, 
  1671.                       transdata->curfle->next != NULL ?
  1672.                           ((gftp_file *) transdata->curfle->next->data)->node :
  1673.                           NULL);
  1674.     }
  1675.   pthread_mutex_unlock (transdata->transfer->structmutex);
  1676. }
  1677. static void
  1678. trans_selectall (GtkWidget * widget, gpointer data)
  1679. {
  1680.   gftp_transfer * tdata;
  1681.   tdata = data;
  1682.   gtk_clist_select_all (GTK_CLIST (tdata->clist));
  1683. }
  1684. static void
  1685. trans_unselectall (GtkWidget * widget, gpointer data)
  1686. {
  1687.   gftp_transfer * tdata;
  1688.   tdata = data;
  1689.   gtk_clist_unselect_all (GTK_CLIST (tdata->clist));
  1690. }
  1691. static void
  1692. overwrite (GtkWidget * widget, gpointer data)
  1693. {
  1694.   GList * templist, * filelist;
  1695.   gftp_transfer * tdata;
  1696.   gftp_file * tempfle;
  1697.   int curpos;
  1698.   tdata = data;
  1699.   curpos = 0;
  1700.   filelist = tdata->files;
  1701.   templist = GTK_CLIST (tdata->clist)->selection;
  1702.   while (templist != NULL)
  1703.     {
  1704.       templist = get_next_selection (templist, &filelist, &curpos);
  1705.       tempfle = filelist->data;
  1706.       tempfle->transfer_action = GFTP_TRANS_ACTION_OVERWRITE;
  1707.       gtk_clist_set_text (GTK_CLIST (tdata->clist), curpos, 3, _("Overwrite"));
  1708.     }
  1709. }
  1710. static void
  1711. resume (GtkWidget * widget, gpointer data)
  1712. {
  1713.   GList * templist, * filelist;
  1714.   gftp_transfer * tdata;
  1715.   gftp_file * tempfle;
  1716.   int curpos;
  1717.   tdata = data;
  1718.   curpos = 0;
  1719.   filelist = tdata->files;
  1720.   templist = GTK_CLIST (tdata->clist)->selection;
  1721.   while (templist != NULL)
  1722.     {
  1723.       templist = get_next_selection (templist, &filelist, &curpos);
  1724.       tempfle = filelist->data;
  1725.       tempfle->transfer_action = GFTP_TRANS_ACTION_RESUME;
  1726.       gtk_clist_set_text (GTK_CLIST (tdata->clist), curpos, 3, _("Resume"));
  1727.     }
  1728. }
  1729. static void
  1730. skip (GtkWidget * widget, gpointer data)
  1731. {
  1732.   GList * templist, * filelist;
  1733.   gftp_transfer * tdata;
  1734.   gftp_file * tempfle;
  1735.   int curpos;
  1736.   tdata = data;
  1737.   curpos = 0;
  1738.   filelist = tdata->files;
  1739.   templist = GTK_CLIST (tdata->clist)->selection;
  1740.   while (templist != NULL)
  1741.     {
  1742.       templist = get_next_selection (templist, &filelist, &curpos);
  1743.       tempfle = filelist->data;
  1744.       tempfle->transfer_action = GFTP_TRANS_ACTION_SKIP;
  1745.       gtk_clist_set_text (GTK_CLIST (tdata->clist), curpos, 3, _("Skip"));
  1746.     }
  1747. }
  1748. static void
  1749. ok (GtkWidget * widget, gpointer data)
  1750. {
  1751.   gftp_transfer * tdata;
  1752.   gftp_file * tempfle;
  1753.   GList * templist;
  1754.   tdata = data;
  1755.   pthread_mutex_lock ((pthread_mutex_t *) tdata->structmutex);
  1756.   for (templist = tdata->files; templist != NULL; templist = templist->next)
  1757.     {
  1758.       tempfle = templist->data;
  1759.       if (tempfle->transfer_action != GFTP_TRANS_ACTION_SKIP)
  1760.         break;
  1761.     }
  1762.   if (templist == NULL)
  1763.     {
  1764.       tdata->show = 0; 
  1765.       tdata->ready = tdata->done = 1;
  1766.     }
  1767.   else
  1768.     tdata->show = tdata->ready = 1;
  1769.   pthread_mutex_unlock ((pthread_mutex_t *) tdata->structmutex);
  1770. }
  1771. static void
  1772. cancel (GtkWidget * widget, gpointer data)
  1773. {
  1774.   gftp_transfer * tdata;
  1775.   tdata = data;
  1776.   pthread_mutex_lock ((pthread_mutex_t *) tdata->structmutex);
  1777.   tdata->show = 0;
  1778.   tdata->done = tdata->ready = 1;
  1779.   pthread_mutex_unlock ((pthread_mutex_t *) tdata->structmutex);
  1780. }
  1781. #if GTK_MAJOR_VERSION > 1
  1782. static void
  1783. transfer_action (GtkWidget * widget, gint response, gpointer user_data)
  1784. {
  1785.   switch (response)
  1786.     {
  1787.       case GTK_RESPONSE_OK:
  1788.         ok (widget, user_data);
  1789.         gtk_widget_destroy (widget);
  1790.         break;
  1791.       case GTK_RESPONSE_CANCEL:
  1792.         cancel (widget, user_data);
  1793.         /* no break */
  1794.       default:
  1795.         gtk_widget_destroy (widget);
  1796.     }
  1797. }   
  1798. #endif
  1799. void
  1800. gftp_gtk_ask_transfer (gftp_transfer * tdata)
  1801. {
  1802.   char *dltitles[4], *add_data[4] = { NULL, NULL, NULL, NULL },
  1803.        tempstr[50], temp1str[50], *pos, *title;
  1804.   GtkWidget * tempwid, * scroll, * hbox;
  1805.   gftp_file * tempfle;
  1806.   GList * templist;
  1807.   size_t len;
  1808.   int i;
  1809.   dltitles[0] = _("Filename");
  1810.   dltitles[1] = _("Local Size");
  1811.   dltitles[2] = _("Remote Size");
  1812.   dltitles[3] = _("Action");
  1813.   title = tdata->transfer_direction == GFTP_DIRECTION_DOWNLOAD ?  
  1814.                                _("Download Files") : _("Upload Files");
  1815. #if GTK_MAJOR_VERSION == 1
  1816.   dialog = gtk_dialog_new ();
  1817.   gtk_grab_add (dialog);
  1818.   gtk_window_set_title (GTK_WINDOW (dialog), title);
  1819.   gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
  1820.   gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 35);
  1821.   gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dialog)->action_area), TRUE);
  1822.   gtk_signal_connect_object (GTK_OBJECT (dialog), "delete_event",
  1823.                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
  1824.                              GTK_OBJECT (dialog));
  1825. #else
  1826.   dialog = gtk_dialog_new_with_buttons (title, NULL, 0, 
  1827.                                         GTK_STOCK_OK,
  1828.                                         GTK_RESPONSE_OK,
  1829.                                         GTK_STOCK_CANCEL,
  1830.                                         GTK_RESPONSE_CANCEL,
  1831.                                         NULL);
  1832. #endif
  1833.   gtk_window_set_wmclass (GTK_WINDOW(dialog), "transfer", "gFTP");
  1834.   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
  1835.   gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 10);
  1836.   gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 5);
  1837.   tempwid = gtk_label_new (_("The following file(s) exist on both the local and remote computernPlease select what you would like to do"));
  1838.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), tempwid, FALSE,
  1839.       FALSE, 0);
  1840.   gtk_widget_show (tempwid);
  1841.   scroll = gtk_scrolled_window_new (NULL, NULL);
  1842.   gtk_widget_set_size_request (scroll, 450, 200);
  1843.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
  1844.   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  1845.   tdata->clist = gtk_clist_new_with_titles (4, dltitles);
  1846.   gtk_container_add (GTK_CONTAINER (scroll), tdata->clist);
  1847. #if GTK_MAJOR_VERSION == 1
  1848.   gtk_clist_set_selection_mode (GTK_CLIST (tdata->clist),
  1849. GTK_SELECTION_EXTENDED);
  1850. #else
  1851.   gtk_clist_set_selection_mode (GTK_CLIST (tdata->clist),
  1852. GTK_SELECTION_MULTIPLE);
  1853. #endif
  1854.   gtk_clist_set_column_width (GTK_CLIST (tdata->clist), 0, 100);
  1855.   gtk_clist_set_column_justification (GTK_CLIST (tdata->clist), 1,
  1856.       GTK_JUSTIFY_RIGHT);
  1857.   gtk_clist_set_column_width (GTK_CLIST (tdata->clist), 1, 85);
  1858.   gtk_clist_set_column_justification (GTK_CLIST (tdata->clist), 2,
  1859.       GTK_JUSTIFY_RIGHT);
  1860.   gtk_clist_set_column_width (GTK_CLIST (tdata->clist), 2, 85);
  1861.   gtk_clist_set_column_width (GTK_CLIST (tdata->clist), 3, 85);
  1862.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), scroll, TRUE, TRUE,
  1863.       0);
  1864.   gtk_widget_show (tdata->clist);
  1865.   gtk_widget_show (scroll);
  1866.   for (templist = tdata->files; templist != NULL; 
  1867.        templist = templist->next)
  1868.     {
  1869.       tempfle = templist->data;
  1870.       if (tempfle->startsize == 0 || tempfle->isdir)
  1871.         {
  1872.            tempfle->shown = 0;
  1873.            continue;
  1874.         }
  1875.       tempfle->shown = 1;
  1876.       pos = tempfle->destfile;
  1877.       len = strlen (GFTP_GET_DIRECTORY (tdata->toreq));
  1878.       if (strncmp (pos, GFTP_GET_DIRECTORY (tdata->toreq), len) == 0)
  1879.         pos = tempfle->destfile + len + 1;
  1880.       add_data[0] = pos;
  1881.       if (overwrite_by_default)
  1882.         add_data[3] = _("Overwrite");
  1883.       else
  1884.         {
  1885.           if (tempfle->startsize >= tempfle->size)
  1886.             {
  1887.               add_data[3] = _("Skip");
  1888.               tempfle->transfer_action = GFTP_TRANS_ACTION_SKIP;
  1889.             }
  1890.           else
  1891.             {
  1892.               add_data[3] = _("Resume");
  1893.               tempfle->transfer_action = GFTP_TRANS_ACTION_RESUME;
  1894.             }
  1895.         }
  1896.       if (tdata->transfer_direction == GFTP_DIRECTION_DOWNLOAD)
  1897.         {
  1898.           add_data[2] = insert_commas (tempfle->size, tempstr,
  1899.                                        sizeof (tempstr));
  1900.           add_data[1] = insert_commas (tempfle->startsize, temp1str,
  1901.                                        sizeof (temp1str));
  1902.         }
  1903.       else
  1904.         {
  1905.           add_data[1] = insert_commas (tempfle->size, tempstr,
  1906.                                        sizeof (tempstr));
  1907.           add_data[2] = insert_commas (tempfle->startsize, temp1str,
  1908.                                        sizeof (temp1str));
  1909.         }
  1910.       i = gtk_clist_append (GTK_CLIST (tdata->clist), add_data);
  1911.       gtk_clist_set_row_data (GTK_CLIST (tdata->clist), i, tempfle);
  1912.     }
  1913.   gtk_clist_select_all (GTK_CLIST (tdata->clist));
  1914.   hbox = gtk_hbox_new (TRUE, 20);
  1915.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
  1916.   gtk_widget_show (hbox);
  1917.   tempwid = gtk_button_new_with_label (_("Overwrite"));
  1918.   gtk_box_pack_start (GTK_BOX (hbox), tempwid, TRUE, TRUE, 0);
  1919.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked",
  1920.       GTK_SIGNAL_FUNC (overwrite), (gpointer) tdata);
  1921.   gtk_widget_show (tempwid);
  1922.   tempwid = gtk_button_new_with_label (_("Resume"));
  1923.   gtk_box_pack_start (GTK_BOX (hbox), tempwid, TRUE, TRUE, 0);
  1924.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked",
  1925.       GTK_SIGNAL_FUNC (resume), (gpointer) tdata);
  1926.   gtk_widget_show (tempwid);
  1927.   tempwid = gtk_button_new_with_label (_("Skip File"));
  1928.   gtk_box_pack_start (GTK_BOX (hbox), tempwid, TRUE, TRUE, 0);
  1929.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked", GTK_SIGNAL_FUNC (skip),
  1930.       (gpointer) tdata);
  1931.   gtk_widget_show (tempwid);
  1932.   hbox = gtk_hbox_new (TRUE, 20);
  1933.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
  1934.   gtk_widget_show (hbox);
  1935.   tempwid = gtk_button_new_with_label (_("Select All"));
  1936.   gtk_box_pack_start (GTK_BOX (hbox), tempwid, TRUE, TRUE, 0);
  1937.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked",
  1938.       GTK_SIGNAL_FUNC (trans_selectall), (gpointer) tdata);
  1939.   gtk_widget_show (tempwid);
  1940.   tempwid = gtk_button_new_with_label (_("Deselect All"));
  1941.   gtk_box_pack_start (GTK_BOX (hbox), tempwid, TRUE, TRUE, 0);
  1942.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked",
  1943.       GTK_SIGNAL_FUNC (trans_unselectall), (gpointer) tdata);
  1944.   gtk_widget_show (tempwid);
  1945. #if GTK_MAJOR_VERSION == 1
  1946.   tempwid = gtk_button_new_with_label (_("OK"));
  1947.   GTK_WIDGET_SET_FLAGS (tempwid, GTK_CAN_DEFAULT);
  1948.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), tempwid,
  1949.       TRUE, TRUE, 0);
  1950.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked", GTK_SIGNAL_FUNC (ok),
  1951.       (gpointer) tdata);
  1952.   gtk_signal_connect_object (GTK_OBJECT (tempwid), "clicked",
  1953.      GTK_SIGNAL_FUNC (gtk_widget_destroy),
  1954.      GTK_OBJECT (dialog));
  1955.   gtk_widget_grab_default (tempwid);
  1956.   gtk_widget_show (tempwid);
  1957.   tempwid = gtk_button_new_with_label (_("  Cancel  "));
  1958.   GTK_WIDGET_SET_FLAGS (tempwid, GTK_CAN_DEFAULT);
  1959.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), tempwid,
  1960.       TRUE, TRUE, 0);
  1961.   gtk_signal_connect (GTK_OBJECT (tempwid), "clicked",
  1962.       GTK_SIGNAL_FUNC (cancel), (gpointer) tdata);
  1963.   gtk_signal_connect_object (GTK_OBJECT (tempwid), "clicked",
  1964.      GTK_SIGNAL_FUNC (gtk_widget_destroy),
  1965.      GTK_OBJECT (dialog));
  1966.   gtk_widget_show (tempwid);
  1967. #else
  1968.   g_signal_connect (GTK_OBJECT (dialog), "response",
  1969.                     G_CALLBACK (transfer_action), (gpointer) tdata);
  1970. #endif
  1971.   gtk_widget_show (dialog);
  1972.   dialog = NULL;
  1973. }