1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gfileutil.c,v 1.43 2004/09/21 08:44:31 makeinu Exp $
22  */
23 
24 #include <gtk/gtk.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <utime.h>
32 
33 #include "charset.h"
34 #include "fileutil.h"
35 #include "fr-archive.h"
36 #include "gfileutil.h"
37 #include "gimv_comment.h"
38 #include "gimv_image.h"
39 #include "gimv_thumb.h"
40 #include "gimv_thumb_cache.h"
41 #include "gtkutils.h"
42 #include "intl.h"
43 #include "prefs.h"
44 
45 #ifndef BUF_SIZE
46 #define BUF_SIZE 4096
47 #endif
48 
49 #ifndef MAX_PATH_LEN
50 #define MAX_PATH_LEN 1024
51 #endif
52 
53 
54 gchar *
add_slash(const gchar * path)55 add_slash (const gchar *path)
56 {
57    g_return_val_if_fail (path, NULL);
58 
59    if (!*path) return g_strdup ("/");
60 
61    if (path [strlen (path) - 1] == '/')
62       return g_strdup (path);
63    else
64       return g_strconcat (path, "/", NULL);
65 }
66 
67 
68 gchar *
remove_slash(const gchar * path)69 remove_slash (const gchar *path)
70 {
71    g_return_val_if_fail (path, NULL);
72    g_return_val_if_fail (*path, g_strdup (path));
73 
74    if (path[strlen (path) - 1] == '/')
75       return g_dirname (path);
76    else
77       return g_strdup (path);
78 }
79 
80 
81 gboolean getting_dir = FALSE;
82 gboolean stop_getting_dir = FALSE;
83 static gchar* tmpdir = NULL;
84 
85 
86 gchar *
get_temp_dir_name(void)87 get_temp_dir_name (void)
88 {
89    if (tmpdir) return tmpdir;
90 
91    tmpdir = g_strdup_printf ("%s%s.%d",
92                              g_get_tmp_dir (),
93                              "/gimv",
94                              getpid ());
95    return tmpdir;
96 }
97 
98 
99 void
remove_dir(const gchar * dirname)100 remove_dir (const gchar *dirname)
101 {
102    GList *node, *list;
103 
104    if (!isdir(dirname)) return;
105 
106    list = get_dir_all (dirname);
107 
108    for (node = list; node; node = g_list_next (node))
109       remove (node->data);
110 
111    if (list) {
112       remove (dirname);
113       g_list_foreach (list, (GFunc) g_free, NULL);
114       g_list_free (list);
115    }
116 }
117 
118 
119 void
remove_temp_dir(void)120 remove_temp_dir (void)
121 {
122    if (!tmpdir) return;
123 
124    remove_dir (tmpdir);
125 
126    g_free (tmpdir);
127    tmpdir = NULL;
128 }
129 
130 
131 /*
132  *  get_dir:
133  *     @ Get image files in specified directory.
134  *
135  *  dirname  : Directory to scan.
136  *  files    : Pointer to OpenFiles struct for store directory list.
137  */
138 void
get_dir(const gchar * dirname,GetDirFlags flags,GList ** filelist_ret,GList ** dirlist_ret)139 get_dir (const gchar *dirname, GetDirFlags flags,
140          GList **filelist_ret, GList **dirlist_ret)
141 {
142    DIR *dp;
143    struct dirent *entry;
144    gchar buf[MAX_PATH_LEN], *path;
145    GList *filelist = NULL, *dirlist = NULL, *list;
146 
147    g_return_if_fail (dirname && *dirname);
148 
149    getting_dir = TRUE;
150 
151    if (flags & GETDIR_DISP_STDERR)
152       fprintf (stderr, _("scandir = %s\n"), dirname);
153    else if (flags & GETDIR_DISP_STDOUT)
154       fprintf (stdout, _("scandir = %s\n"), dirname);
155 
156    if ((dp = opendir (dirname))) {
157       while ((entry = readdir (dp))) {
158          if (flags & GETDIR_ENABLE_CANCEL) {
159             while (gtk_events_pending()) gtk_main_iteration();
160             if (stop_getting_dir) break;
161          }
162 
163          /* ignore dot file */
164          if (!(flags & GETDIR_READ_DOT) && entry->d_name[0] == '.')
165             continue;
166 
167          /* get full path */
168          if (dirname [strlen (dirname) - 1] == '/')
169             g_snprintf (buf, MAX_PATH_LEN, "%s%s", dirname, entry->d_name);
170          else
171             g_snprintf (buf, MAX_PATH_LEN, "%s/%s", dirname, entry->d_name);
172 
173          /* if path is file */
174          if (!isdir (buf) || (!(flags & GETDIR_FOLLOW_SYMLINK) && islink (buf))) {
175             if (!filelist_ret) continue;
176 
177             if (!(flags & GETDIR_DETECT_EXT)
178                 || gimv_image_detect_type_by_ext (buf)
179                 || ((flags & GETDIR_GET_ARCHIVE)
180                     && fr_archive_utils_get_file_name_ext (buf)))
181             {
182                path = g_strdup (buf);
183 
184                if (flags & GETDIR_DISP_STDERR)
185                   fprintf (stderr, _("filename = %s\n"), path);
186                else if (flags & GETDIR_DISP_STDOUT)
187                   fprintf (stdout, _("filename = %s\n"), path);
188 
189                filelist = g_list_append (filelist, path);
190             }
191 
192          /* if path is dir */
193          } else if (isdir(buf)) {
194             if (dirlist_ret && strcmp(entry->d_name, ".")
195                 && strcmp(entry->d_name, ".."))
196             {
197                path = g_strdup (buf);
198 
199                if (flags & GETDIR_DISP_STDERR)
200                   fprintf (stderr, _("dirname = %s\n"), path);
201                else if (flags & GETDIR_DISP_STDOUT)
202                   fprintf (stdout, _("dirname = %s\n"), path);
203 
204                dirlist = g_list_append (dirlist, path);
205             }
206          }
207       }
208       closedir (dp);
209       if (filelist)
210          filelist = g_list_sort (filelist, gtkutil_comp_spel);
211       if (dirlist)
212          dirlist = g_list_sort (dirlist, gtkutil_comp_spel);
213    } else {
214       g_warning ("cannot open directory: %s", dirname);
215    }
216 
217    /* recursive get */
218    if (flags & GETDIR_RECURSIVE) {
219       GList *tmplist = g_list_copy (dirlist);
220       gint tmp_flags = flags | GETDIR_RECURSIVE_IS_BRANCH;
221 
222       list = tmplist;
223       while (list) {
224          GList *tmp_filelist = NULL, *tmp_dirlist = NULL;
225          if (flags & GETDIR_ENABLE_CANCEL) {
226             while (gtk_events_pending()) gtk_main_iteration();
227             if (stop_getting_dir) break;
228          }
229          get_dir ((const gchar *) list->data, tmp_flags,
230                   &tmp_filelist, &tmp_dirlist);
231          filelist = g_list_concat (filelist, tmp_filelist);
232          dirlist = g_list_concat (dirlist, tmp_dirlist);
233          list = g_list_next (list);
234       }
235       g_list_free (tmplist);
236    }
237 
238    /* return value */
239    if (filelist_ret)
240       *filelist_ret = filelist;
241    if (dirlist_ret)
242       *dirlist_ret = dirlist;
243 
244    if (!(flags & GETDIR_RECURSIVE_IS_BRANCH)) {
245       getting_dir = FALSE;
246       stop_getting_dir = FALSE;
247    }
248 }
249 
250 
251 void
get_dir_stop(void)252 get_dir_stop (void)
253 {
254    if (getting_dir)
255       stop_getting_dir = TRUE;
256 }
257 
258 
259 /*
260  *  get_dir_all:
261  *     @
262  *
263  *  dirname :
264  *  Return  :
265  */
266 GList *
get_dir_all(const gchar * dirname)267 get_dir_all (const gchar *dirname)
268 {
269    GList *filelist, *dirlist, *sub_dirlist, *node;
270    gchar *sub_dirname;
271 
272    get_dir (dirname, GETDIR_READ_DOT, &filelist, &dirlist);
273 
274    if (dirlist) {
275       node = dirlist;
276       while (node) {
277          sub_dirname = node->data;
278          sub_dirlist = get_dir_all (sub_dirname);
279          if (sub_dirlist)
280             filelist = g_list_concat (sub_dirlist, filelist);
281          node = g_list_next (node);
282       }
283       filelist = g_list_concat (filelist, dirlist);
284    }
285    return filelist;
286 }
287 
288 
289 /*
290  *  get_dir_all_file:
291  *     @
292  *
293  *  dirname :
294  *  Return  :
295  */
296 static GList *
get_dir_all_file(const gchar * dirname)297 get_dir_all_file (const gchar *dirname)
298 {
299    GList *filelist, *dirlist, *sub_dirlist, *node;
300    gchar *sub_dirname;
301 
302    get_dir (dirname, GETDIR_READ_DOT, &filelist, &dirlist);
303 
304    if (dirlist) {
305       node = dirlist;
306       while (node) {
307          sub_dirname = node->data;
308          sub_dirlist = get_dir_all_file (sub_dirname);
309          if (sub_dirlist)
310             filelist = g_list_concat (sub_dirlist, filelist);
311          node = g_list_next (node);
312       }
313    }
314    return filelist;
315 }
316 
317 
318 /*
319  *  merge from misc/misc.c in Text maid (Copyright(C) Kazuki Iwamoto).
320  */
321 gchar *
relpath2abs(const gchar * path)322 relpath2abs (const gchar *path)
323 {
324    gchar *dir, *dest;
325    gint i,j,len;
326 
327    g_return_val_if_fail (path && *path, NULL);
328 
329    if (path[0] != '/') {
330       dir = g_get_current_dir ();
331       dest = g_strjoin ("/", dir, path, NULL);
332       g_free (dir);
333    } else {
334 	   dest = g_strdup (path);
335    }
336 
337    len = strlen (dest) + 1;
338    i = 0;
339    while (i < len - 2) {
340       if (dest[i] == '/' && dest[i + 1] == '.'
341           && (dest[i + 2] == '/' || dest[i + 2] == '\0'))
342       {
343          len -= 2;
344          memmove (dest + i, dest + i + 2, len - i);
345       }
346 
347       i++;
348    }
349 
350    i = 0;
351    while (i < len - 3) {
352       if (dest[i] == '/' && dest[i + 1] == '.' && dest[i + 2] == '.'
353           && (dest[i + 3] == '/' || dest[i + 3] == '\0'))
354       {
355          len -= 3;
356          memmove (dest + i, dest + i + 3, len - i);
357          for (j = i - 1; j >= 0; j--) {
358             if (dest[j] == '/')
359                break;
360          }
361          if (j >= 0) {
362             memmove (dest + j, dest + i, len - i);
363             len -= i - j;
364             i = j;
365          }
366       }
367 
368       i++;
369    }
370 
371    return dest;
372 }
373 
374 
375 gchar *
link2abs(const gchar * path)376 link2abs (const gchar *path)
377 {
378    gchar *retval = NULL, **dirs, buf[MAX_PATH_LEN], *tmpstr;
379    gint i, num;
380 
381    g_return_val_if_fail (path && *path, NULL);
382    g_return_val_if_fail (path[0] == '/', g_strdup (path));
383 
384    if (!strcmp (path, "/")) return g_strdup (path);
385 
386    dirs = g_strsplit (path, "/", -1);
387    g_return_val_if_fail (dirs, g_strdup (path));
388 
389    retval = g_strdup("");
390    for (i = 0; dirs[i]; i++) {
391       gchar *endchr;
392 
393       if (!*dirs[i]) continue;
394 
395       tmpstr = g_strconcat (retval, "/", dirs[i], NULL);
396       g_free (retval);
397       retval = tmpstr;
398 
399       num = readlink (retval, buf, MAX_PATH_LEN);
400       if (num < 1) continue;
401 
402       buf[num] = '\0';
403       if (buf[0] == '/') {
404          g_free (retval);
405          retval = g_strdup (buf);
406       } else {
407          endchr = strrchr (retval, '/');
408          if (!endchr) {
409             g_free (retval);
410             retval = g_strdup (path);
411             break;
412          }
413          *endchr = '\0';
414          /* FIXME: what about link to link? */
415          tmpstr = g_strconcat (retval, "/", buf, NULL);
416          g_free (retval);
417          retval = tmpstr;
418       }
419    }
420 
421    g_strfreev (dirs);
422 
423    if (!retval) {
424       g_warning ("invalid link: %s\n", path);
425    } else {
426       tmpstr = relpath2abs (retval);
427       g_free (retval);
428       retval = tmpstr;
429    }
430 
431    return retval;
432 }
433 
434 
435 static gboolean
move_file_check_path(const gchar * from_path,struct stat * from_st,const gchar * dir,gboolean show_error,GtkWindow * window)436 move_file_check_path (const gchar *from_path,
437                       struct stat *from_st,
438                       const gchar *dir,
439                       gboolean show_error,
440                       GtkWindow *window)
441 {
442    gchar *from_dir, error_message[BUF_SIZE];
443    gchar *from_path_internal, *dir_internal;
444    gboolean retval = FALSE;
445 
446    from_path_internal   = charset_to_internal (from_path,
447                                                conf.charset_filename,
448                                                conf.charset_auto_detect_fn,
449                                                conf.charset_filename_mode);
450    dir_internal         = charset_to_internal (dir,
451                                                conf.charset_filename,
452                                                conf.charset_auto_detect_fn,
453                                                conf.charset_filename_mode);
454 
455    /********************
456     * check source file
457     ********************/
458    if (lstat (from_path, from_st)) {
459       if (show_error) {
460          g_snprintf (error_message, BUF_SIZE,
461                      _("Can't find source file :\n%s"),
462                      from_path_internal);
463          gtkutil_message_dialog (_("Error!!"), error_message, window);
464       }
465       goto ERROR;
466    }
467 
468    /*****************
469     * check dest dir
470     *****************/
471    if (!iswritable (dir)) {
472       if (show_error) {
473          g_snprintf (error_message, BUF_SIZE,
474                      _("Can't move file : %s\n"
475                        "Permission denied: %s\n"),
476                      from_path_internal, dir_internal);
477          gtkutil_message_dialog (_("Error!!"), error_message, window);
478       }
479       goto ERROR;
480    }
481 
482    /*******************
483     * check source dir
484     *******************/
485    from_dir = g_dirname (from_path);
486    if (!iswritable (from_dir)) {
487       if (show_error) {
488          gchar *from_dir_internal;
489 
490          from_dir_internal   = charset_to_internal (from_dir,
491                                                     conf.charset_filename,
492                                                     conf.charset_auto_detect_fn,
493                                                     conf.charset_filename_mode);
494 
495          g_snprintf (error_message, BUF_SIZE,
496                      _("Can't move file : %s\n"
497                        "Permission denied: %s\n"),
498                      from_path_internal, from_dir_internal);
499          gtkutil_message_dialog (_("Error!!"), error_message, window);
500 
501          g_free (from_dir_internal);
502       }
503       g_free (from_dir);
504       goto ERROR;
505    }
506    g_free (from_dir);
507 
508    retval = TRUE;
509 
510 ERROR:
511    g_free (from_path_internal);
512    g_free (dir_internal);
513    return retval;
514 }
515 
516 
517 static gboolean
move_file_check_over_write(const gchar * from_path,struct stat * from_st,const gchar * to_path,struct stat * to_st,gchar * new_path,gint new_path_len,ConfirmType * action,gboolean show_error,GtkWindow * window)518 move_file_check_over_write (const gchar *from_path,
519                             struct stat *from_st,
520                             const gchar *to_path,
521                             struct stat *to_st,
522                             gchar *new_path, gint new_path_len,
523                             ConfirmType *action,
524                             gboolean show_error,
525                             GtkWindow *window)
526 {
527    gchar error_message[BUF_SIZE], *to_path_internal;
528    gint exist;
529    gboolean retval = FALSE;
530 
531    if (new_path)
532       new_path[0] = '\0';
533 
534    to_path_internal   = charset_to_internal (to_path,
535                                              conf.charset_filename,
536                                              conf.charset_auto_detect_fn,
537                                              conf.charset_filename_mode);
538 
539    exist = !lstat(to_path, to_st);
540    if (exist && (!strcmp (from_path, to_path)
541                  || from_st->st_ino == to_st->st_ino))
542    {
543       if (show_error) {
544          g_snprintf (error_message, BUF_SIZE,
545                      _("Same file :\n%s"), to_path_internal);
546          gtkutil_message_dialog (_("Error!!"), error_message, window);
547       }
548       goto ERROR;
549 
550    }  else if (exist && *action == CONFIRM_ASK) {
551       if (isdir (from_path)) {
552          g_snprintf (error_message, BUF_SIZE,
553                      _("File exist : %s"), to_path_internal);
554          gtkutil_message_dialog (_("ERROR!!"), error_message, window);
555 
556       } else {
557          g_snprintf (error_message, BUF_SIZE,
558                      _("The file exists : %s\n"
559                        "Overwrite?"),
560                      to_path_internal);
561          *action = gtkutil_overwrite_confirm_dialog (_("File exist!!"), error_message,
562                                                      to_path, from_path,
563                                                      new_path, MAX_PATH_LEN,
564                                                      ConfirmDialogMultipleFlag,
565                                                      window);
566       }
567    }
568 
569    if (new_path && *new_path) {
570       retval = TRUE;
571    } else {
572       switch (*action) {
573       case CONFIRM_YES:
574       case CONFIRM_YES_TO_ALL:
575          retval = TRUE;
576       break;
577       case CONFIRM_NO:
578       case CONFIRM_CANCEL:
579          retval = FALSE;
580          break;
581       case CONFIRM_NO_TO_ALL:
582          if (exist)
583             retval = FALSE;
584          else
585             retval = TRUE;
586          break;
587       default:
588          if (!exist)
589             retval = TRUE;
590          else
591             retval = FALSE;
592          break;
593       }
594    }
595 
596 ERROR:
597    g_free (to_path_internal);
598    return retval;
599 }
600 
601 
602 /*
603  *  move_file:
604  *     @
605  *
606  *  from_path  :
607  *  dir        :
608  *  action     :
609  *  show_error :
610  *  Return     : TRUE if success to move file.
611  */
612 gboolean
move_file(const gchar * from_path,const gchar * dir,ConfirmType * action,gboolean show_error,GtkWindow * window)613 move_file (const gchar *from_path, const gchar *dir,
614            ConfirmType *action, gboolean show_error,
615            GtkWindow *window)
616 {
617    gchar *to_path, error_message[BUF_SIZE];
618    struct stat from_st, to_st, todir_st;
619    struct utimbuf ut;
620    gboolean move_file = FALSE, move_faild = FALSE, copy_success = FALSE, retval;
621    gchar *from_path_internal, *to_path_internal, new_path[MAX_PATH_LEN];
622 
623    new_path[0] = '\0';
624 
625    g_return_val_if_fail (action, FALSE);
626 
627    retval = move_file_check_path (from_path, &from_st, dir, show_error, window);
628    if (!retval) return FALSE;
629 
630    /* set dest path */
631    to_path = g_strconcat (dir, g_basename (from_path), NULL);
632 
633    move_file = move_file_check_over_write (from_path, &from_st,
634                                            to_path, &to_st,
635                                            new_path, MAX_PATH_LEN,
636                                            action, show_error,
637                                            window);
638    if (!move_file) {
639       retval = FALSE;
640       goto ERROR0;
641    }
642 
643    from_path_internal = charset_to_internal (from_path,
644                                              conf.charset_filename,
645                                              conf.charset_auto_detect_fn,
646                                              conf.charset_filename_mode);
647    if (*new_path) {
648       g_free (to_path);
649       to_path = g_strdup (new_path);
650    }
651    to_path_internal   = charset_to_internal (to_path,
652                                              conf.charset_filename,
653                                              conf.charset_auto_detect_fn,
654                                              conf.charset_filename_mode);
655 
656    /**************
657     * move file!!
658     **************/
659    stat (dir, &todir_st);
660    if (from_st.st_dev != todir_st.st_dev) {
661       copy_success = copy_file_to_file (from_path, to_path, action, show_error,
662                                         window);
663       if (copy_success) {
664          /* reset new file's time info */
665          ut.actime = from_st.st_atime;
666          ut.modtime = from_st.st_mtime;
667          utime(to_path, &ut);
668 
669          /* remove old file */
670          if (remove (from_path) < 0) {   /* faild to remove file */
671             if (show_error) {
672                g_snprintf (error_message, BUF_SIZE,
673                            _("Faild to remove file :\n"
674                              "%s"),
675                            from_path_internal);
676                gtkutil_message_dialog (_("Error!!"), error_message, window);
677             }
678             retval = FALSE;
679             goto ERROR1;
680          }
681       } else {
682          move_faild = TRUE;
683       }
684    } else {
685       move_faild = rename (from_path, to_path);
686    }
687 
688    /************************
689     * if faild to move file
690     ************************/
691    if (move_faild) {
692       if (show_error) {
693          g_snprintf (error_message, BUF_SIZE,
694                      _("Faild to move file :\n"
695                        "From : %s\n"
696                        "To : %s"),
697                      from_path_internal, to_path_internal);
698          gtkutil_message_dialog (_("Error!!"), error_message, window);
699       }
700       retval = FALSE;
701    }
702 
703 ERROR1:
704    g_free (from_path_internal);
705    g_free (to_path_internal);
706 ERROR0:
707    g_free (to_path);
708    return retval;
709 }
710 
711 
712 static gboolean
copy_dir_check_source(const gchar * from_dir,gboolean show_error,GtkWindow * window)713 copy_dir_check_source (const gchar *from_dir, gboolean show_error,
714                        GtkWindow *window)
715 {
716    gchar error_message[BUF_SIZE], *from_dir_internal;
717    gboolean retval = TRUE;
718 
719    from_dir_internal = charset_to_internal (from_dir,
720                                             conf.charset_filename,
721                                             conf.charset_auto_detect_fn,
722                                             conf.charset_filename_mode);
723 
724    if (islink (from_dir)) {   /* check path is link or not */
725       if (show_error) {
726          g_snprintf (error_message, BUF_SIZE,
727                      _("%s is link!!.\n"),
728                      from_dir_internal);
729          gtkutil_message_dialog (_("Error!!"), error_message, window);
730       }
731       retval = FALSE;
732       goto ERROR;
733    }
734 
735    if (!file_exists (from_dir)) {   /* check path exists or not */
736       if (show_error) {
737          g_snprintf (error_message, BUF_SIZE,
738                      _("Can't find source file :\n%s"),
739                      from_dir_internal);
740          gtkutil_message_dialog (_("Error!!"), error_message, window);
741       }
742       retval = FALSE;
743       goto ERROR;
744    }
745 
746    if (!isdir (from_dir)) {   /* check path is directory or not */
747       if (show_error) {
748          g_snprintf (error_message, BUF_SIZE,
749                      _("%s is not directory!!.\n"),
750                      from_dir_internal);
751          gtkutil_message_dialog (_("Error!!"), error_message, window);
752       }
753       retval = FALSE;
754       goto ERROR;
755    }
756 
757 ERROR:
758    g_free (from_dir_internal);
759    return TRUE;
760 }
761 
762 
763 static gboolean
copy_dir_check_dest(const gchar * from_path,const gchar * dirname,const gchar * to_dir,gboolean show_error,GtkWindow * window)764 copy_dir_check_dest (const gchar *from_path, const gchar *dirname,
765                      const gchar *to_dir, gboolean show_error,
766                      GtkWindow *window)
767 {
768    gchar error_message[BUF_SIZE];
769    gchar *from_path_internal, *dirname_internal, *to_dir_internal;
770    gboolean retval = TRUE;
771 
772    from_path_internal = charset_to_internal (from_path,
773                                              conf.charset_filename,
774                                              conf.charset_auto_detect_fn,
775                                              conf.charset_filename_mode);
776    dirname_internal   = charset_to_internal (dirname,
777                                              conf.charset_filename,
778                                              conf.charset_auto_detect_fn,
779                                              conf.charset_filename_mode);
780    to_dir_internal    = charset_to_internal (to_dir,
781                                              conf.charset_filename,
782                                              conf.charset_auto_detect_fn,
783                                              conf.charset_filename_mode);
784 
785    if (!iswritable (dirname)) {   /* check permission */
786       if (show_error) {
787          g_snprintf (error_message, BUF_SIZE,
788                      _("Can't copy directory : %s\n"
789                        "Permission denied: %s\n"),
790                      from_path_internal,
791                      dirname_internal);
792          gtkutil_message_dialog (_("Error!!"), error_message, window);
793       }
794       retval = FALSE;
795       goto ERROR;
796    }
797 
798    if (file_exists (to_dir)) {   /* check dest path */
799       if (show_error) {
800          g_snprintf (error_message, BUF_SIZE,
801                      _("File exists!! : %s\n"),
802                      to_dir_internal);
803          gtkutil_message_dialog (_("Error!!"), error_message, window);
804       }
805       retval = FALSE;
806       goto ERROR;
807    }
808 
809 ERROR:
810    g_free (from_path_internal);
811    g_free (dirname_internal);
812    g_free (to_dir_internal);
813 
814    return retval;
815 }
816 
817 
818 /*
819  *  copy_dir:
820  *     @
821  *
822  *  from_path  :
823  *  dir        :
824  *  action     :
825  *  show_error :
826  *  Return     : TRUE if success to copy directory.
827  */
828 static gboolean
copy_dir(const gchar * from_path,const gchar * dir,ConfirmType * action,gboolean show_error,GtkWindow * window)829 copy_dir (const gchar *from_path, const gchar *dir,
830           ConfirmType *action, gboolean show_error,
831           GtkWindow *window)
832 {
833    GtkWidget *progress_win;
834    gchar message[BUF_SIZE];
835    GList *filelist, *node;
836    gchar *from_dir, *to_dir, *to_path, *dirname;
837    ConfirmType confirm;
838    gboolean result, cancel = FALSE;
839    gfloat progress;
840    gint pos, length;
841 
842    from_dir = g_strdup (from_path);
843    if (from_dir[strlen (from_dir) - 1] == '/')
844       from_dir[strlen (from_dir) - 1] = '\0';
845 
846    dirname = g_strdup (dir);
847    if (dirname[strlen (dirname) - 1] == '/')
848       dirname[strlen (dirname) - 1] = '\0';
849 
850    to_dir = g_strconcat (dirname, "/", g_basename (from_dir), NULL);
851 
852    /*******************
853     * check source dir
854     *******************/
855    result = copy_dir_check_source (from_dir, show_error, window);
856    if (!result) goto ERROR;
857 
858    /*****************
859     * check dest dir
860     *****************/
861    result = copy_dir_check_dest (from_path, dirname, to_dir, show_error, window);
862    g_free (dirname);
863    if (!result) goto ERROR;
864 
865 
866    /****************
867     * do copy files
868     ****************/
869    filelist = node = get_dir_all_file (from_path);
870    confirm = CONFIRM_YES_TO_ALL;
871 
872    progress_win = gtkutil_create_progress_window (_("Copy directory"), "...",
873                                                   &cancel, 300, -1, window);
874    gtk_grab_add (progress_win);
875    length = g_list_length (filelist);
876 
877    while (node) {
878       guint len;
879       gchar *filename = node->data;
880       gchar *tmpstr;
881 
882       while (gtk_events_pending()) gtk_main_iteration();
883 
884       pos = g_list_position (filelist, node);
885       progress = (gfloat) pos / (gfloat) length;
886 
887       {   /********** convert charset **********/
888          gchar *filename_internal;
889 
890          filename_internal = charset_to_internal (filename,
891                                                   conf.charset_filename,
892                                                   conf.charset_auto_detect_fn,
893                                                   conf.charset_filename_mode);
894 
895          g_snprintf (message, BUF_SIZE, _("Copying %s ..."),
896                      filename_internal);
897 
898          g_free (filename_internal);
899       }
900 
901       gtkutil_progress_window_update (progress_win, _("Copying directory"),
902                                       message, NULL, progress);
903 
904       len = strlen (from_path);
905 
906       if (strlen (filename) > len) {
907          tmpstr = filename + len;
908          if (tmpstr[0] == '/') tmpstr++;
909          to_path = g_strconcat (to_dir, "/", tmpstr, NULL);
910 
911          /* realy do copy :-) */
912          mkdirs (to_path);
913          copy_file_to_file (filename, to_path, &confirm, show_error, window);
914 
915          g_free (to_path);
916       }
917 
918       node = g_list_next (node);
919    }
920 
921    gtk_grab_remove (progress_win);
922    gtk_widget_destroy (progress_win);
923 
924    g_list_foreach (filelist, (GFunc) g_free, NULL);
925    g_list_free (filelist);
926 
927    g_free (from_dir);
928    g_free (to_dir);
929 
930    return TRUE;
931 
932 ERROR:
933    g_free (from_dir);
934    g_free (to_dir);
935    return FALSE;
936 }
937 
938 
939 /*
940  *  copy_file_to_file:
941  *     @
942  *
943  *  from_path  :
944  *  to_path    :
945  *  action     :
946  *  show_error :
947  *  Return     : TRUE if success to copy file.
948  */
949 gboolean
copy_file_to_file(const gchar * from_path,const gchar * to_path,ConfirmType * action,gboolean show_error,GtkWindow * window)950 copy_file_to_file (const gchar *from_path, const gchar *to_path,
951                    ConfirmType *action, gboolean show_error,
952                    GtkWindow *window)
953 {
954    gint b;
955    gchar buf[BUFSIZ], *from_path_internal, *to_path_internal;
956    gchar error_message[BUF_SIZE];
957    FILE *from, *to;
958    struct stat from_st, to_st;
959    gint exist;
960    gchar new_path[MAX_PATH_LEN];
961 
962    new_path[0] = '\0';
963 
964    g_return_val_if_fail (action, FALSE);
965 
966    /********************
967     * check source file
968     ********************/
969    if (isdir (from_path)) {
970       return copy_dir (from_path, to_path, action, show_error, window);
971    }
972 
973    from_path_internal = charset_to_internal (from_path,
974                                              conf.charset_filename,
975                                              conf.charset_auto_detect_fn,
976                                              conf.charset_filename_mode);
977    to_path_internal   = charset_to_internal (to_path,
978                                              conf.charset_filename,
979                                              conf.charset_auto_detect_fn,
980                                              conf.charset_filename_mode);
981 
982    if (lstat (from_path, &from_st)) {
983       if (show_error) {
984          g_snprintf (error_message, BUF_SIZE,
985                      _("Can't find source file :\n%s"),
986                      from_path_internal);
987          gtkutil_message_dialog (_("Error!!"), error_message, window);
988       }
989       goto ERROR;
990    }
991 
992    /******************
993     * check dest file
994     ******************/
995    exist = !lstat(to_path, &to_st);
996    if (exist && (!strcmp (from_path, to_path)
997                  || from_st.st_ino == to_st.st_ino))
998    {
999       if (show_error) {
1000          g_snprintf (error_message, BUF_SIZE,
1001                      _("Same file :\n%s"),
1002                      to_path_internal);
1003          gtkutil_message_dialog (_("Error!!"), error_message, window);
1004       }
1005       goto ERROR;
1006 
1007    } else if (exist && *action == CONFIRM_ASK) {
1008       g_snprintf (error_message, BUF_SIZE,
1009                   _("The file exists : %s\n"
1010                     "Overwrite?"),
1011                   to_path_internal);
1012       *action = gtkutil_overwrite_confirm_dialog (_("File exist!!"), error_message,
1013                                                   to_path, from_path,
1014                                                   new_path, MAX_PATH_LEN,
1015                                                   ConfirmDialogMultipleFlag,
1016                                                   window);
1017    }
1018 
1019    if (*new_path) {
1020       g_free (to_path_internal);
1021       to_path = new_path;
1022       to_path_internal = charset_to_internal (to_path,
1023                                               conf.charset_filename,
1024                                               conf.charset_auto_detect_fn,
1025                                               conf.charset_filename_mode);
1026    } else {
1027       switch (*action) {
1028       case CONFIRM_YES:
1029       case CONFIRM_YES_TO_ALL:
1030          break;
1031       case CONFIRM_NO:
1032       case CONFIRM_CANCEL:
1033          goto ERROR;
1034          break;
1035       case CONFIRM_NO_TO_ALL:
1036          if (exist)
1037             goto ERROR;
1038          break;
1039       default:
1040          if (exist)
1041             goto ERROR;
1042          break;
1043       }
1044    }
1045 
1046    /**********
1047     * do copy
1048     **********/
1049    from = fopen (from_path, "rb");
1050    if (!from) {
1051       if (show_error) {
1052          g_snprintf (error_message, BUF_SIZE,
1053                      _("Can't open file for read :\n%s"),
1054                      to_path_internal);
1055          gtkutil_message_dialog (_("Error!!"), error_message, window);
1056       }
1057       goto ERROR;
1058    }
1059 
1060    to = fopen (to_path, "wb");
1061    if (!to) {
1062       fclose (from);
1063       if (show_error) {
1064          g_snprintf (error_message, BUF_SIZE,
1065                      _("Can't open file for write :\n%s"),
1066                      to_path_internal);
1067          gtkutil_message_dialog (_("Error!!"), error_message, window);
1068       }
1069       goto ERROR;
1070    }
1071 
1072    while ((b = fread (buf, sizeof (char), BUFSIZ, from)) > 0) {
1073       fwrite (buf, sizeof (char), b, to);
1074       if (ferror (to)) {
1075          fclose (from);
1076          fclose (to);
1077 
1078          if (show_error) {
1079             g_snprintf (error_message, BUF_SIZE,
1080                         _("An error occured while copying file :\n%s"),
1081                         to_path_internal);
1082             gtkutil_message_dialog (_("Error!!"), error_message, window);
1083          }
1084          goto ERROR;
1085       }
1086    }
1087 
1088    fclose (from);
1089    fclose (to);
1090 
1091    g_free (to_path_internal);
1092    g_free (from_path_internal);
1093    return TRUE;
1094 
1095 ERROR:
1096    g_free (to_path_internal);
1097    g_free (from_path_internal);
1098    return FALSE;
1099 }
1100 
1101 
1102 /*
1103  *  copy_file:
1104  *     @
1105  *
1106  *  from_path  :
1107  *  dir        :
1108  *  action     :
1109  *  show_error :
1110  *  Return     : TRUE if success to copy file.
1111  */
1112 gboolean
copy_file(const gchar * from_path,const gchar * dir,ConfirmType * action,gboolean show_error,GtkWindow * window)1113 copy_file (const gchar *from_path, const gchar *dir,
1114            ConfirmType *action, gboolean show_error,
1115            GtkWindow *window)
1116 {
1117    gchar *to_path;
1118    gboolean retval;
1119    gchar error_message[BUF_SIZE];
1120 
1121    g_return_val_if_fail (action, FALSE);
1122 
1123    /* check source file is directory or not */
1124    if (isdir (from_path)) {
1125       return copy_dir (from_path, dir, action, show_error, window);
1126    }
1127 
1128    /*****************
1129     * check dest dir
1130     *****************/
1131    if (!iswritable (dir)) {
1132       if (show_error) {
1133          gchar *from_path_internal, *dir_internal;
1134 
1135          from_path_internal = charset_to_internal (from_path,
1136                                                    conf.charset_filename,
1137                                                    conf.charset_auto_detect_fn,
1138                                                    conf.charset_filename_mode);
1139          dir_internal = charset_to_internal (dir,
1140                                              conf.charset_filename,
1141                                              conf.charset_auto_detect_fn,
1142                                              conf.charset_filename_mode);
1143          g_snprintf (error_message, BUF_SIZE,
1144                      _("Can't copy file : %s\n"
1145                        "Permission denied: %s\n"),
1146                      from_path_internal, dir_internal);
1147 
1148          gtkutil_message_dialog (_("Error!!"), error_message, window);
1149 
1150          g_free (from_path_internal);
1151          g_free (dir_internal);
1152       }
1153       return FALSE;
1154    }
1155 
1156    to_path = g_strconcat (dir, g_basename (from_path), NULL);
1157    retval = copy_file_to_file (from_path, to_path, action, show_error, window);
1158    g_free (to_path);
1159 
1160    return retval;
1161 }
1162 
1163 
1164 /*
1165  *  link_file:
1166  *     @
1167  *
1168  *  from_path  :
1169  *  dir        :
1170  *  action     :
1171  *  show_error :
1172  *  Return     : TRUE if success to link file.
1173  */
1174 gboolean
link_file(const gchar * from_path,const gchar * dir,gboolean show_error,GtkWindow * window)1175 link_file (const gchar *from_path, const gchar *dir,
1176            gboolean show_error, GtkWindow *window)
1177 {
1178    gchar *to_path, *to_path_internal, *from_path_internal, *dir_internal;
1179    struct stat from_st, to_st;
1180    gboolean link_faild;
1181    gchar error_message[BUF_SIZE];
1182 
1183    from_path_internal = charset_to_internal (from_path,
1184                                              conf.charset_filename,
1185                                              conf.charset_auto_detect_fn,
1186                                              conf.charset_filename_mode);
1187    dir_internal = charset_to_internal (dir,
1188                                        conf.charset_filename,
1189                                        conf.charset_auto_detect_fn,
1190                                        conf.charset_filename_mode);
1191 
1192    /********************
1193     * check source file
1194     ********************/
1195    if (lstat (from_path, &from_st)) {
1196       if (show_error) {
1197          g_snprintf (error_message, BUF_SIZE,
1198                      _("Can't find source file :\n%s"),
1199                      from_path_internal);
1200          gtkutil_message_dialog (_("Error!!"), error_message, window);
1201       }
1202       goto ERROR0;
1203    }
1204 
1205    /*****************
1206     * check dest dir
1207     *****************/
1208    if (!iswritable (dir)) {
1209       if (show_error) {
1210          g_snprintf (error_message, BUF_SIZE,
1211                      _("Can't create link : %s\n"
1212                        "Permission denied: %s\n"),
1213                      from_path_internal, dir_internal);
1214          gtkutil_message_dialog (_("Error!!"), error_message, window);
1215       }
1216       goto ERROR0;
1217    }
1218 
1219    to_path = g_strconcat(dir_internal, g_basename(from_path), NULL);
1220    to_path_internal = charset_to_internal (to_path,
1221                                            conf.charset_filename,
1222                                            conf.charset_auto_detect_fn,
1223                                            conf.charset_filename_mode);
1224 
1225    /******************
1226     * check dest path
1227     ******************/
1228    if (!lstat (to_path, &to_st)) {
1229       if (show_error) {
1230          g_snprintf (error_message, BUF_SIZE,
1231                      _("File exist : %s"),
1232                      to_path_internal);
1233          gtkutil_message_dialog (_("Error!!"), error_message, window);
1234       }
1235       goto ERROR1;
1236    }
1237 
1238    link_faild = symlink(from_path, to_path);
1239 
1240    if (link_faild) {
1241       if (show_error) {
1242          g_snprintf (error_message, BUF_SIZE,
1243                      _("Faild to create link :\n"
1244                        "From : %s\n"
1245                        "To : %s"),
1246                      from_path_internal, to_path_internal);
1247          gtkutil_message_dialog (_("Error!!"), error_message, window);
1248       }
1249       goto ERROR1;
1250    }
1251 
1252    g_free (to_path);
1253    g_free (to_path_internal);
1254    g_free (from_path_internal);
1255    g_free (dir_internal);
1256    return TRUE;
1257 
1258 ERROR1:
1259    g_free (to_path);
1260    g_free (to_path_internal);
1261 ERROR0:
1262    g_free (from_path_internal);
1263    g_free (dir_internal);
1264    return FALSE;
1265 }
1266 
1267 
1268 
1269 static gchar *
get_dest_cache_dir(const gchar * src_file,const gchar * dest_dir,const gchar * cache_type)1270 get_dest_cache_dir (const gchar *src_file,
1271                     const gchar *dest_dir,
1272                     const gchar *cache_type)
1273 {
1274    gchar *dest_file, *dest_cache_dir;
1275 
1276    if (!src_file || !dest_dir || !cache_type) return NULL;
1277 
1278    dest_file = g_strconcat (dest_dir, g_basename (src_file), NULL);
1279    dest_cache_dir = gimv_thumb_cache_get_path (dest_file, cache_type);
1280 
1281    if (dest_cache_dir) {
1282       gchar *endchr;
1283 
1284       endchr = strrchr (dest_cache_dir, '/');
1285       if (endchr) {
1286          *(endchr + 1) = '\0';
1287          mkdirs (dest_cache_dir);
1288       } else {
1289          g_free (dest_cache_dir);
1290          dest_cache_dir = NULL;
1291       }
1292    }
1293    g_free (dest_file);
1294 
1295    return dest_cache_dir;
1296 }
1297 
1298 
1299 static gchar *
get_dest_comment_dir(const gchar * src_file,const gchar * dest_dir)1300 get_dest_comment_dir (const gchar *src_file,
1301                       const gchar *dest_dir)
1302 {
1303    gchar *dest_file, *dest_comment_dir;
1304 
1305    if (!src_file || !dest_dir) return NULL;
1306 
1307    dest_file = g_strconcat (dest_dir, g_basename (src_file), NULL);
1308    dest_comment_dir = gimv_comment_get_path (dest_file);
1309 
1310    if (dest_comment_dir) {
1311       gchar *endchr;
1312 
1313       endchr = strrchr (dest_comment_dir, '/');
1314       if (endchr) {
1315          *(endchr + 1) = '\0';
1316          mkdirs (dest_comment_dir);
1317       } else {
1318          g_free (dest_comment_dir);
1319          dest_comment_dir = NULL;
1320       }
1321    }
1322    g_free (dest_file);
1323 
1324    return dest_comment_dir;
1325 }
1326 
1327 
1328 static gboolean
do_file_operate(const gchar * src_file,const gchar * dest_dir,ConfirmType * over_write,FileOperateType action,GtkWidget * progress_win,gfloat progress,GtkWindow * window)1329 do_file_operate (const gchar *src_file,
1330                  const gchar *dest_dir,
1331                  ConfirmType *over_write,
1332                  FileOperateType action,
1333                  GtkWidget *progress_win,
1334                  gfloat progress,
1335                  GtkWindow *window)
1336 {
1337    gchar *src_cache, *dest_cache_dir;
1338    gchar *src_comment, *dest_comment_dir;
1339    gchar *cache_type;
1340    gchar *src_file_internal;
1341    struct stat src_st, dest_st;
1342    ConfirmType cache_over_write = CONFIRM_YES_TO_ALL;
1343    gboolean success = TRUE, delete_src = FALSE, result;
1344    gchar message[BUF_SIZE];
1345 
1346    /* FIXME!! */ /* get cache file & dir */
1347    src_cache        = gimv_thumb_find_thumbcache (src_file, &cache_type);
1348    dest_cache_dir   = get_dest_cache_dir (src_file, dest_dir, cache_type);
1349    src_comment      = gimv_comment_find_file (src_file);
1350    dest_comment_dir = get_dest_comment_dir (src_file, dest_dir);
1351 
1352    /* if move to different file system, change to copy */
1353    lstat (src_file, &src_st);
1354    lstat (dest_dir, &dest_st);
1355    if (src_st.st_dev != dest_st.st_dev && action == FILE_MOVE ) {
1356       action = FILE_COPY;
1357       delete_src = TRUE;
1358    }
1359 
1360    src_file_internal = charset_to_internal (src_file,
1361                                             conf.charset_filename,
1362                                             conf.charset_auto_detect_fn,
1363                                             conf.charset_filename_mode);
1364 
1365    switch (action) {
1366    case FILE_MOVE:
1367       g_snprintf (message, BUF_SIZE,
1368                   _("Moving %s ..."), src_file_internal);
1369       gtkutil_progress_window_update (progress_win, _("Moving files"),
1370                                       message, NULL, progress);
1371       result = move_file (src_file, dest_dir, over_write, TRUE, window);
1372 
1373       if (!result)
1374          success = FALSE;
1375 
1376       /* FIXME!! */ /* move cache file */
1377       if (result && src_cache && dest_cache_dir)
1378          move_file (src_cache, dest_cache_dir, &cache_over_write, FALSE, window);
1379       if (result && src_comment && dest_comment_dir)
1380          move_file (src_comment, dest_comment_dir, &cache_over_write, FALSE, window);
1381 
1382       break;
1383 
1384    case FILE_COPY:
1385    {
1386       gboolean delete_src_cache = FALSE, delete_src_comment = FALSE;
1387 
1388       g_snprintf (message, BUF_SIZE,
1389                   _("Copying %s ..."), src_file_internal);
1390       gtkutil_progress_window_update (progress_win, _("Copying files"),
1391                                       message, NULL, progress);
1392       result = copy_file (src_file, dest_dir, over_write, TRUE, window);
1393 
1394       if (!result)
1395          success = FALSE;
1396 
1397       /* FIXME!! */ /* copy cache file */
1398       if (result && src_cache && dest_cache_dir) {
1399          if (copy_file (src_cache, dest_cache_dir, &cache_over_write, FALSE, window))
1400             delete_src_cache = TRUE;
1401       }
1402       if (result && src_comment && dest_comment_dir) {
1403          if (copy_file (src_comment, dest_comment_dir, &cache_over_write, FALSE, window))
1404             delete_src_comment = TRUE;
1405       }
1406 
1407       /* FIXME: delete src? */
1408       if (result && delete_src) {
1409          GList *delete_file_list = NULL;
1410          delete_file_list = g_list_append (delete_file_list, (gpointer) src_file);
1411          if (delete_src_cache)
1412             delete_file_list = g_list_append (delete_file_list, src_cache);
1413          if (delete_src_comment)
1414             delete_file_list = g_list_append (delete_file_list, src_comment);
1415          if (delete_file_list)
1416             delete_files (delete_file_list, CONFIRM_YES, window);
1417          g_list_free (delete_file_list);
1418       }
1419 
1420       break;
1421    }
1422    case FILE_LINK:
1423       g_snprintf (message, BUF_SIZE,
1424                   _("Creating Link %s ..."), src_file_internal);
1425       gtkutil_progress_window_update (progress_win, _("Creating Links"),
1426                                       message, NULL, progress);
1427       result = link_file (src_file, dest_dir, TRUE, window);
1428 
1429       if (!result)
1430          success = FALSE;
1431 
1432       /* FIXME!! */ /* link cache file */
1433       if (result && src_cache && dest_cache_dir)
1434          link_file (src_cache, dest_cache_dir, FALSE, window);
1435       if (result && src_comment && dest_comment_dir)
1436          link_file (src_comment, dest_comment_dir, FALSE, window);
1437 
1438       break;
1439 
1440    default:
1441       success = FALSE;
1442       break;
1443    }
1444 
1445    g_free (src_file_internal);
1446 
1447    /* FIXME!! */
1448    g_free (src_cache);
1449    g_free (dest_cache_dir);
1450    g_free (src_comment);
1451    g_free (dest_comment_dir);
1452 
1453    return success;
1454 }
1455 
1456 
1457 gboolean
files2dir(GList * filelist,const gchar * dir,FileOperateType action,GtkWindow * window)1458 files2dir (GList *filelist, const gchar *dir, FileOperateType action, GtkWindow *window)
1459 {
1460    GtkWidget *progress_win;
1461    GList *node;
1462    ConfirmType over_write = CONFIRM_ASK;
1463    gboolean success = TRUE, cancel = FALSE, result;
1464    gchar message[BUF_SIZE], *src_file, *dest_dir, *dir_internal;
1465    gint length, pos;
1466    gfloat progress;
1467 
1468    g_return_val_if_fail (filelist, FALSE);
1469    g_return_val_if_fail (dir, FALSE);
1470 
1471    dir_internal = charset_to_internal (dir,
1472                                        conf.charset_filename,
1473                                        conf.charset_auto_detect_fn,
1474                                        conf.charset_filename_mode);
1475 
1476    /*****************
1477     * check dest dir
1478     *****************/
1479    if (!file_exists (dir)) {
1480       g_snprintf (message, BUF_SIZE,
1481                   _("Directory doesn't exist!!: %s"),
1482                   dir_internal);
1483       gtkutil_message_dialog (_("Error!!"), message, window);
1484       goto ERROR;
1485    }
1486    if (!iswritable (dir)) {
1487       g_snprintf (message, BUF_SIZE,
1488                   _("Permission denied!!: %s"),
1489                   dir_internal);
1490       gtkutil_message_dialog (_("Error!!"), message, window);
1491       goto ERROR;
1492    }
1493 
1494    /* add "/" character */
1495    if (dir[strlen(dir) - 1] == '/')
1496       dest_dir = g_strdup (dir);
1497    else
1498       dest_dir = g_strconcat (dir, "/", NULL);
1499 
1500    /* create progress window */
1501    progress_win = gtkutil_create_progress_window ("File Operation", "...",
1502                                                   &cancel, 300, -1, window);
1503    gtk_grab_add (progress_win);
1504 
1505    /* do file operation */
1506    length = g_list_length (filelist);
1507    for (node = filelist; node; node = g_list_next (node)) {
1508       src_file = node->data;
1509 
1510       while (gtk_events_pending()) gtk_main_iteration();
1511 
1512       pos = g_list_position (filelist, node);
1513       progress = (gfloat) pos / (gfloat) length;
1514 
1515       result = do_file_operate (src_file, dest_dir, &over_write, action,
1516                                 progress_win, progress, window);
1517       if (!result)
1518          success = FALSE;
1519 
1520       /* cancel */
1521       if (cancel || (over_write == CONFIRM_CANCEL)) break;
1522 
1523       /* reset to CONFIRM_ASK mode */
1524       if (over_write != CONFIRM_YES_TO_ALL && over_write != CONFIRM_NO_TO_ALL) {
1525          over_write = CONFIRM_ASK;
1526       }
1527    }
1528 
1529    gtk_grab_remove (progress_win);
1530    gtk_widget_destroy (progress_win);
1531 
1532    g_free (dest_dir);
1533    g_free (dir_internal);
1534 
1535    return success;
1536 
1537 ERROR:
1538    g_free (dir_internal);
1539    return FALSE;
1540 }
1541 
1542 
1543 gboolean
files2dir_with_dialog(GList * filelist,gchar ** default_dir,FileOperateType action,GtkWindow * window)1544 files2dir_with_dialog (GList *filelist, gchar **default_dir, FileOperateType action,
1545                        GtkWindow *window)
1546 {
1547    gchar *dir;
1548    gboolean retval = FALSE;
1549    gchar *title, *label, *tmpstr;
1550 
1551    g_return_val_if_fail (filelist, FALSE);
1552    g_return_val_if_fail (default_dir, FALSE);
1553 
1554    if (!*default_dir)
1555       *default_dir = g_strdup (g_getenv("HOME"));
1556 
1557    switch (action) {
1558    case FILE_MOVE:
1559       title = _("Move files to...");
1560       label = _("Move files to: ");
1561       break;
1562    case FILE_COPY:
1563       title = _("Copy files to...");
1564       label = _("Copy files to: ");
1565       break;
1566    case FILE_LINK:
1567       title = _("Link files to...");
1568       label = _("Link files to: ");
1569       break;
1570    default:
1571       dir = *default_dir;
1572       goto FUNC_END;
1573       break;
1574    }
1575 
1576    tmpstr = charset_to_internal (*default_dir,
1577                                  conf.charset_filename,
1578                                  conf.charset_auto_detect_fn,
1579                                  conf.charset_filename_mode);
1580    dir = gtkutil_modal_file_dialog (title, tmpstr, MODAL_FILE_DIALOG_DIR_ONLY, window);
1581    g_free (tmpstr);
1582    tmpstr = NULL;
1583 
1584    if (dir) {
1585       if (dir[strlen(dir) - 1] != '/') {
1586          tmpstr = dir;
1587          dir = g_strconcat (dir, "/", NULL);
1588          g_free (tmpstr);
1589       }
1590 
1591       tmpstr = dir;
1592       dir = charset_internal_to_locale (dir);
1593       g_free (tmpstr);
1594 
1595       retval = files2dir (filelist, dir, action, window);
1596    }
1597 
1598 FUNC_END:
1599    if (*default_dir != dir)
1600       g_free (*default_dir);
1601    *default_dir = dir;
1602 
1603    return retval;
1604 }
1605 
1606 
1607 gboolean
delete_dir(const gchar * path,GtkWindow * window)1608 delete_dir (const gchar *path, GtkWindow *window)
1609 {
1610    gboolean exist, cancel, not_empty = FALSE;
1611    struct stat st;
1612    gchar message[BUF_SIZE], *path_internal;
1613    GList *filelist, *listnode;
1614    gint length, pos;
1615    gfloat progress;
1616    GtkWidget *progress_win;
1617    ConfirmType action;
1618 
1619    g_return_val_if_fail (path && *path, FALSE);
1620 
1621    path_internal = charset_to_internal (path,
1622                                         conf.charset_filename,
1623                                         conf.charset_auto_detect_fn,
1624                                         conf.charset_filename_mode);
1625 
1626    /* check direcotry exist or not */
1627    exist = !lstat (path, &st);
1628    if (!exist) {
1629       g_snprintf (message, BUF_SIZE,
1630                   _("Directory not exist : %s"), path_internal);
1631       gtkutil_message_dialog (_("Error!!"), message, window);
1632       goto ERROR;
1633    }
1634 
1635    /* check path is link or not */
1636    if (islink (path)) {
1637       g_snprintf (message, BUF_SIZE,
1638                   _("%s is symbolic link.\n"
1639                     "Remove link ?"), path_internal);
1640       action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"),
1641                                        message, 0, window);
1642       if (action == CONFIRM_YES) {
1643          remove (path);
1644       }
1645       goto SUCCESS;
1646    }
1647 
1648    /* confirm */
1649    g_snprintf (message, BUF_SIZE,
1650                _("Delete %s\n"
1651                  "OK?"), path_internal);
1652    action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"),
1653                                     message, 0, window);
1654    if (action != CONFIRM_YES) goto ERROR;
1655 
1656    /* remove sub directories recursively */
1657    filelist = get_dir_all (path);
1658    if (filelist) {
1659       g_snprintf (message, BUF_SIZE,
1660                   _("%s is not empty\n"
1661                     "Delete all files under %s ?"),
1662                   path_internal, path_internal);
1663       action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"),
1664                                        message, 0, window);
1665       if (action != CONFIRM_YES) goto ERROR;
1666 
1667       /* create progress bar */
1668       progress_win = gtkutil_create_progress_window ("Delete File", "Deleting Files",
1669                                                      &cancel, 300, -1, window);
1670       gtk_grab_add (progress_win);
1671 
1672       length = g_list_length (filelist);
1673       listnode = filelist;
1674 
1675       while (listnode) {
1676 
1677          /* update progress */
1678          pos = g_list_position (filelist, listnode);
1679          if ((pos % 50) == 0) {
1680             while (gtk_events_pending()) gtk_main_iteration();
1681 
1682             pos = g_list_position (filelist, listnode);
1683             progress = (gfloat) pos / (gfloat) length;
1684 
1685             {   /********** convert charset **********/
1686                gchar *tmpstr;
1687                tmpstr =  charset_to_internal (listnode->data,
1688                                               conf.charset_filename,
1689                                               conf.charset_auto_detect_fn,
1690                                               conf.charset_filename_mode);
1691                g_snprintf (message, BUF_SIZE,
1692                            _("Deleting %s ..."),
1693                            tmpstr);
1694                g_free (tmpstr);
1695             }
1696 
1697             gtkutil_progress_window_update (progress_win, NULL,
1698                                             message, NULL, progress);
1699          }
1700 
1701          /* remove a file */
1702          if (remove ((gchar *) listnode->data) < 0)
1703             not_empty = TRUE;
1704          listnode = g_list_next (listnode);
1705 
1706          /* cancel */
1707          if (cancel) break;
1708       }
1709       gtk_grab_remove (progress_win);
1710       gtk_widget_destroy (progress_win);
1711 
1712       g_list_foreach (filelist, (GFunc) g_free, NULL);
1713       g_list_free (filelist);
1714    }
1715 
1716    /* remove the directory */
1717    if (not_empty) {
1718       g_snprintf (message, BUF_SIZE,
1719                   _("Faild to remove directory :\n"
1720                     "%s is not empty."), path_internal);
1721       gtkutil_message_dialog (_("Error!!"), message, window);
1722    } else if (remove (path) < 0) {
1723       g_snprintf (message, BUF_SIZE,
1724                   _("Faild to remove directory : %s"), path_internal);
1725       gtkutil_message_dialog (_("Error!!"), message, window);
1726    }
1727 
1728 SUCCESS:
1729    g_free (path_internal);
1730    return TRUE;
1731 
1732 ERROR:
1733    g_free (path_internal);
1734    return FALSE;
1735 }
1736 
1737 
1738 gboolean
delete_files(GList * filelist,ConfirmType confirm,GtkWindow * window)1739 delete_files (GList *filelist, ConfirmType confirm, GtkWindow *window)
1740 {
1741    GtkWidget *progress_win = NULL;
1742    GList *node;
1743    gboolean cancel = FALSE, dialog = FALSE;
1744    gint pos, length;
1745    gfloat progress;
1746    gchar message[BUF_SIZE], *dirname;
1747 
1748    g_return_val_if_fail (filelist, FALSE);
1749 
1750    length = g_list_length (filelist);
1751 
1752    if (confirm == CONFIRM_ASK)
1753       dialog = TRUE;
1754 
1755    if (dialog) {
1756       g_snprintf (message, BUF_SIZE,
1757                   _("Delete these %d files.\n"
1758                     "OK?"),
1759                   length);
1760       confirm = gtkutil_confirm_dialog (_("Confirm Deleting Files"),
1761                                         message, 0, window);
1762    }
1763 
1764    if (!(confirm == CONFIRM_YES || confirm == CONFIRM_YES_TO_ALL)) {
1765       return FALSE;
1766    }
1767 
1768    if (dialog) {
1769       progress_win = gtkutil_create_progress_window (_("Delete File"),
1770                                                      _("Deleting Files"),
1771                                                      &cancel, 300, -1, window);
1772       gtk_grab_add (progress_win);
1773    }
1774 
1775    node = filelist;
1776    while (node) {
1777       gchar *filename = node->data, *filename_internal, *dirname_internal;
1778 
1779       node = g_list_next (node);
1780       if (!filename || !*filename) continue;
1781 
1782       filename_internal =  charset_to_internal (filename,
1783                                                 conf.charset_filename,
1784                                                 conf.charset_auto_detect_fn,
1785                                                 conf.charset_filename_mode);
1786 
1787       while (gtk_events_pending()) gtk_main_iteration();
1788 
1789       pos = g_list_position (filelist, node);
1790       progress = (gfloat) pos / (gfloat) length;
1791 
1792       if (dialog && progress_win) {
1793          g_snprintf (message, BUF_SIZE, _("Deleting %s ..."),
1794                      filename_internal);
1795          gtkutil_progress_window_update (progress_win, NULL,
1796                                          message, NULL, progress);
1797       }
1798 
1799       dirname = g_dirname (filename);
1800       dirname_internal =  charset_to_internal (dirname,
1801                                                conf.charset_filename,
1802                                                conf.charset_auto_detect_fn,
1803                                                conf.charset_filename_mode);
1804 
1805       if (!iswritable (dirname)) {
1806          g_snprintf (message, BUF_SIZE,
1807                      _("Permission denied : %s"), dirname_internal);
1808          gtkutil_message_dialog (_("Error!!"), message, window);
1809 
1810       } else { /* remove file!! */
1811          gboolean success;
1812          gint ret;
1813 
1814          if (isdir (filename)) {
1815             success = delete_dir (filename, window);
1816          } else {
1817             ret = remove (filename);
1818             if (ret < 0)
1819                success = FALSE;
1820             else
1821                success = TRUE;
1822          }
1823 
1824          if (!success) {
1825             g_snprintf (message, BUF_SIZE,
1826                         _("Faild to delete file :\n%s"),
1827                         filename_internal);
1828             gtkutil_message_dialog (_("Error!!"), message, window);
1829          }
1830       }
1831 
1832       g_free (dirname);
1833       g_free (dirname_internal);
1834       g_free (filename_internal);
1835       dirname = NULL;
1836       dirname_internal  = NULL;
1837       filename_internal = NULL;
1838 
1839       /* cancel */
1840       if (cancel) break;
1841    }
1842 
1843    if (dialog && progress_win) {
1844       gtk_grab_remove (progress_win);
1845       gtk_widget_destroy (progress_win);
1846    }
1847 
1848    return TRUE;
1849 }
1850 
1851 gboolean
make_dir_dialog(const gchar * parent_dir,GtkWindow * window)1852 make_dir_dialog (const gchar *parent_dir, GtkWindow *window)
1853 {
1854    gchar *dirname, *path, *parent_path, *tmpstr;
1855    gboolean success = FALSE, exist;
1856    struct stat st;
1857    gchar error_message[BUF_SIZE];
1858 
1859    g_return_val_if_fail (parent_dir && *parent_dir, FALSE);
1860 
1861    parent_path = add_slash (parent_dir);
1862 
1863    if (!iswritable (parent_path)) {
1864       g_snprintf (error_message, BUF_SIZE,
1865                   _("Permission denied : %s"), parent_path);
1866       gtkutil_message_dialog (_("Error!!"), error_message, window);
1867       goto ERROR0;
1868    }
1869 
1870    dirname = gtkutil_popup_textentry (_("Make directory"),
1871                                       _("New directory name: "),
1872                                       NULL, NULL, -1, 0, window);
1873    if (!dirname) goto ERROR0;
1874 
1875    tmpstr = charset_internal_to_locale (dirname);
1876    g_free (dirname);
1877    dirname = tmpstr;
1878    path = g_strconcat (parent_path, dirname, NULL);
1879 
1880    exist = !lstat (path, &st);
1881    if (exist) {
1882       if (isdir (path))
1883          g_snprintf (error_message, BUF_SIZE,
1884                      _("Directory exist : %s"), path);
1885       else
1886          g_snprintf (error_message, BUF_SIZE,
1887                      _("File exist : %s"), path);
1888       gtkutil_message_dialog (_("Error!!"), error_message, window);
1889       g_free (path);
1890       goto ERROR1;
1891    }
1892 
1893    success = makedir (path);
1894    if (!success) {
1895       g_snprintf (error_message, BUF_SIZE,
1896                   _("Faild to create directory : %s"), path);
1897       gtkutil_message_dialog (_("Error!!"), error_message, window);
1898    }
1899 
1900  ERROR1:
1901    g_free (path);
1902  ERROR0:
1903    g_free (parent_path);
1904 
1905    return success;
1906 }
1907 
1908 
1909 gboolean
rename_dir_dialog(const gchar * dir,GtkWindow * window)1910 rename_dir_dialog (const gchar *dir, GtkWindow *window)
1911 {
1912    gboolean exist, success = FALSE;
1913    struct stat st;
1914    gchar message[BUF_SIZE];
1915    gchar *path, *parent_dir, *dirname, *src_path, *src_file_internal;
1916    gchar *dest_path, *tmpstr;
1917 
1918    g_return_val_if_fail (dir && *dir, FALSE);
1919 
1920    path = add_slash (dir);
1921 
1922    /* check direcotry */
1923    exist = !lstat (path, &st);
1924    if (!exist) {
1925       g_snprintf (message, BUF_SIZE,
1926                   _("Directory not exist :%s"), path);
1927       gtkutil_message_dialog (_("Error!!"), message, window);
1928       goto ERROR0;
1929    }
1930 
1931    src_path = remove_slash (path);
1932    parent_dir = g_dirname (src_path);
1933 
1934    /* popup rename directory dialog */
1935    src_file_internal = charset_locale_to_internal (g_basename (src_path));
1936    dirname = gtkutil_popup_textentry (_("Rename directory"),
1937                                       _("New directory name: "),
1938                                       src_file_internal,
1939                                       NULL, -1, 0, window);
1940    g_free (src_file_internal);
1941    if (!dirname) goto ERROR1;
1942 
1943    tmpstr = charset_internal_to_locale (dirname);
1944    g_free (dirname);
1945    dirname = tmpstr;
1946 
1947    dest_path = g_strconcat (parent_dir, "/", dirname, NULL);
1948 
1949    if (rename (src_path, dest_path) < 0) {
1950       g_snprintf (message, BUF_SIZE,
1951                   _("Faild to rename directory : %s"), src_path);
1952       gtkutil_message_dialog (_("Error!!"), message, window);
1953    } else {
1954       success = TRUE;
1955    }
1956 
1957    g_free (dirname);
1958    g_free (dest_path);
1959  ERROR1:
1960    g_free (src_path);
1961    g_free (parent_dir);
1962  ERROR0:
1963    g_free (path);
1964 
1965    return success;
1966 }
1967