1 /*
2  * file.c	Functions to handle file selector.
3  *
4  *	This file is part of the minicom communications package,
5  *	Copyright 1991-1995 Miquel van Smoorenburg.
6  *
7  *	This file created from code mostly cadged from "dial.c"
8  *	by Miquel van Smoorenburg.  Written by James S. Seymour.
9  *	Copyright (c) 1998 by James S. Seymour (jseymour@jimsun.LinxNet.com)
10  *      Some mods for i18n
11  *      Copyright (c) 1998 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
12  *
13  *	This program is free software; you can redistribute it and/or
14  *	modify it under the terms of the GNU General Public License
15  *	as published by the Free Software Foundation; either version
16  *	2 of the License, or (at your option) any later version.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with this program; if not, write to the Free Software Foundation, Inc.,
20  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <limits.h>
28 
29 #include "port.h"
30 #include "minicom.h"
31 #include "intl.h"
32 #include "getsdir.h"
33 
34 #ifdef HAVE_UNISTD_H
35 #  include <unistd.h>
36 #endif
37 
38 #define FILE_MWTR 1	/* main window top row */
39 #define SUBM_OKAY 5	/* last entry in sub-menu */
40 
41 static int nrents = 1;
42 
43 static void file_tell(const char *s);
44 static void dhili(int k);
45 static void prdir(WIN *dirw, int top, int cur, GETSDIR_ENTRY *dirdat, int longest);
46 static void prone(WIN *dirw, GETSDIR_ENTRY *dirdat, int longest, int inverse);
47 static void *set_work_dir(void *existing, size_t min_len);
48 static int  new_filedir(GETSDIR_ENTRY *dirdat, int flushit);
49 static void goto_filedir(char *new_dir, int absolut);
50 static int  tag_untag(char *pat, int tag);
51 static char *concat_list(GETSDIR_ENTRY *d);
52 
53 static WIN *dsub;
54 static const char *const what[] =
55   {
56     /* TRANSLATORS: Translation of each of these menu items should not be
57      * longer than 7 characters. The upper-case letter is a shortcut,
58      * so keep them unique and ASCII; 'h', 'j', 'k', 'l' are reserved */
59     N_("[Goto]"), N_("[Prev]"), N_("[Show]"), N_("[Tag]"), N_("[Untag]"),
60     N_("[Okay]")
61   };
62 #define WHAT_NR_OPTIONS (sizeof (what) / sizeof (*what))
63 #define WHAT_WIDTH 8 /* Width of one entry */
64 /* Number of bytes for <= 7 characters */
65 static int what_lens[WHAT_NR_OPTIONS];
66 /* Number of ' ' padding entries at left and right, left is >= 1 */
67 static int what_padding[WHAT_NR_OPTIONS][2];
68 static int dprev;
69 
70 /* Little menu. */
71 static const char *d_yesno[] = { N_("   Yes  "), N_("   No   "), NULL };
72 
73 
74 /*
75  * Tell a little message
76  */
file_tell(const char * s)77 static void file_tell(const char *s)
78 {
79   WIN *w;
80 
81   w = mc_tell("%s", s);
82   sleep(1);
83   mc_wclose(w, 1);
84 }
85 
86 /* Draw an entry in the horizontal menu */
horiz_draw(size_t k,char start_attr,char end_attr)87 static void horiz_draw(size_t k, char start_attr, char end_attr)
88 {
89   static const char spaces[] = "        ";
90 
91   mc_wprintf(dsub, "%.*s", what_padding[k][0], spaces);
92   mc_wsetattr(dsub, start_attr);
93   mc_wprintf(dsub, "%.*s", what_lens[k], _(what[k]));
94   mc_wsetattr(dsub, end_attr);
95   mc_wprintf(dsub, "%.*s", what_padding[k][1], spaces);
96 }
97 
98 /*
99  * Highlight a choice in the horizontal menu.
100  */
dhili(int k)101 static void dhili(int k)
102 {
103   int initial_y = (76 - (WHAT_NR_OPTIONS * WHAT_WIDTH >= 76
104 	           ? 74 : WHAT_NR_OPTIONS * WHAT_WIDTH)) / 2;
105 
106   if (k == dprev)
107     return;
108 
109   if (dprev >= 0) {
110     mc_wlocate(dsub, initial_y + WHAT_WIDTH * dprev, 0);
111     if (!useattr)
112       mc_wputs(dsub, " ");
113     else
114       horiz_draw(dprev, stdattr, stdattr);
115   }
116   dprev = k;
117 
118   mc_wlocate(dsub, initial_y + WHAT_WIDTH * k, 0);
119   if (!useattr)
120     mc_wputs(dsub, ">");
121   else
122     horiz_draw(k, XA_REVERSE | stdattr, stdattr);
123 }
124 
getno(int no,GETSDIR_ENTRY * d)125 static inline GETSDIR_ENTRY *getno(int no, GETSDIR_ENTRY *d)
126 {
127   if (no >= nrents)
128     return NULL;
129   return d + no;
130 }
131 
132 /*
133  * Print the directory. Only draw from "cur" to bottom.
134  */
prdir(WIN * dirw,int top,int cur,GETSDIR_ENTRY * dirdat,int longest)135 static void prdir(WIN *dirw, int top, int cur,
136                   GETSDIR_ENTRY *dirdat, int longest)
137 {
138   int f, start;
139   char f_str[BUFSIZ];
140   char t_str[BUFSIZ];
141 
142   start = cur - top;
143   dirflush = 0;
144   sprintf(f_str, " %%-%ds", longest + 2);
145   mc_wlocate(dirw, 0, start + FILE_MWTR);
146   for (f = start; f < dirw->ys - (1 + FILE_MWTR); f++) {
147     GETSDIR_ENTRY *d;
148     if (!(d = getno(f + top, dirdat)))
149       break;
150     if (d->cflags & FL_TAG)
151       mc_wsetattr(dirw, XA_REVERSE | stdattr);
152     if (S_ISDIR(d->mode)) {
153       snprintf(t_str, sizeof(t_str), "[%s]", d->fname);
154       mc_wprintf(dirw, f_str, t_str);
155     } else
156       mc_wprintf(dirw, f_str, d->fname);
157     mc_wsetattr(dirw, XA_NORMAL | stdattr);
158     mc_wputc(dirw, '\n');
159   }
160   dirflush = 1;
161   mc_wflush();
162 }
163 
164 /*
165  * Print one directory entry.
166  */
prone(WIN * dirw,GETSDIR_ENTRY * dirdat,int longest,int inverse)167 static void prone(WIN *dirw, GETSDIR_ENTRY *dirdat, int longest, int inverse)
168 {
169   char f_str[BUFSIZ];
170   char t_str[BUFSIZ];
171 
172   dirflush = 0;
173   sprintf(f_str, " %%-%ds", longest + 2);
174   /*
175   if (dirdat->cflags & FL_TAG)
176     mc_wsetattr(dirw, XA_REVERSE | stdattr);
177      */
178   if (inverse)
179     mc_wsetattr(dirw, XA_REVERSE | stdattr);
180   if (S_ISDIR(dirdat->mode)) {
181     snprintf(t_str, sizeof(t_str),  "[%s]", dirdat->fname);
182     mc_wprintf(dirw, f_str, t_str);
183   } else
184     mc_wprintf(dirw, f_str, dirdat->fname);
185   mc_wsetattr(dirw, XA_NORMAL | stdattr);
186   dirflush = 1;
187   mc_wflush();
188 }
189 
190 static WIN *main_w;
191 static GETSDIR_ENTRY *global_dirdat;
192 static int cur = 0;
193 static int ocur = 0;
194 static int subm = SUBM_OKAY;
195 static int quit = 0;
196 static int top = 0;
197 static int c = 0;
198 static int pgud = 0;
199 static int first = 1;
200 static char *s;
201 static int longest;
202 static char file_title[BUFSIZ];
203 static char cwd_str[BUFSIZ];
204 static char *prev_dir = NULL;
205 static char *work_dir = NULL;
206 static char *d_work_dir = NULL;
207 static char *u_work_dir = NULL;
208 static int min_len = 1;
209 static char wc_str[128] = "";
210 static char wc_mem[128] = "";
211 static int tag_cnt = 0;
212 static int how_many = 0;
213 static int down_loading = 0;
214 static char *ret_buf = NULL;
215 
216 
217 /* Init up/down work directories to make sure we start from
218  * the configuration defaults on the next up/download. jl 6/2000
219  */
init_dir(char dir)220 void init_dir(char dir)
221 {
222   char *p = NULL;
223 
224   switch (dir) {
225   case 'u':
226     p = u_work_dir;
227     u_work_dir = NULL;
228     break;
229   case 'd':
230     p = d_work_dir;
231     d_work_dir = NULL;
232     break;
233   }
234   free((void *) p);
235   return;
236 }
237 
set_work_dir(void * existing,size_t min_len)238 static void *set_work_dir(void *existing, size_t min_len)
239 {
240   void *vp = realloc(existing, min_len);
241 
242   if (down_loading)
243     d_work_dir = vp;
244   else
245     u_work_dir = vp;
246 
247   return vp;
248 }
249 
250 
251 /*
252  * Initialize new file directory.
253  *
254  * Sets the current working directory.  Non-0 return = no change.
255  */
new_filedir(GETSDIR_ENTRY * dirdat,int flushit)256 static int new_filedir(GETSDIR_ENTRY *dirdat, int flushit)
257 {
258   static size_t dp_len = 0;
259   static char cwd_str_fmt[BUFSIZ] = "";
260   size_t new_dp_len, fmt_len;
261   char disp_dir[80];
262   int initial_y = (76 - (WHAT_NR_OPTIONS * WHAT_WIDTH >= 76
263                    ? 74 : WHAT_NR_OPTIONS * WHAT_WIDTH)) / 2;
264   size_t i;
265   char * new_prev_dir;
266 
267   cur      =  0;
268   ocur     =  0;
269   subm     =  SUBM_OKAY;
270   quit     =  0;
271   top      =  0;
272   c        =  0;
273   pgud     =  0;
274   first    =  1;
275   min_len  =  1;
276   dprev    = -1;
277   tag_cnt  =  0;
278 
279   /*
280    * get last directory
281    */
282   work_dir = down_loading ? d_work_dir : u_work_dir;
283 
284   /*
285    * init working directory to default?
286    */
287   if (work_dir == NULL) {
288     char *s = down_loading? P_DOWNDIR : P_UPDIR;
289     min_len = 1;
290 
291     if (*s != '/')
292       min_len += strlen(homedir) + 1;
293     min_len += strlen(s);
294     if (min_len < BUFSIZ)
295       min_len = BUFSIZ;
296 
297     work_dir = set_work_dir(NULL, min_len);
298 
299     if (*s == '/')
300       strncpy(work_dir, s, min_len);
301     else
302       snprintf(work_dir, min_len, "%s/%s", homedir, s);
303   }
304   /* lop-off trailing "/" for consistency */
305   if (strlen(work_dir) > 1 && work_dir[strlen(work_dir) - 1] == '/')
306     work_dir[strlen(work_dir) - 1] = (char)0;
307 
308   /* get the current working directory, which will become the prev_dir, on success */
309   new_prev_dir = getcwd(NULL, BUFSIZ);
310   if (!new_prev_dir)
311     return -1;
312 
313   if (!access(work_dir, R_OK | X_OK) && !chdir(work_dir)) {
314     /* was able to change to new working directory */
315     free(prev_dir);
316     prev_dir = new_prev_dir;
317   }
318   else {
319     /* Could not change to the new working directory */
320     mc_wbell();
321     werror(
322         _("Could not change to directory %s (%s)"),
323         work_dir,
324         strerror(errno));
325 
326     /* restore the previous working directory */
327     free(work_dir);
328     work_dir = set_work_dir(new_prev_dir, strlen(new_prev_dir));
329   }
330 
331   /* All right, draw the file directory! */
332 
333   if (flushit) {
334     dirflush = 0;
335     mc_winclr(main_w);
336     mc_wredraw(main_w, 1);
337   }
338 
339   mc_wcursor(main_w, CNORMAL);
340 
341   {
342     char *s;
343 
344     if (down_loading) {
345       if (how_many < 0)
346         s = _("Select one or more files for download");
347       else if (how_many)
348 	s = _("Select a file for download");
349       else
350 	s = _("Select a directory for download");
351     } else {
352       if (how_many < 0)
353         s = _("Select one or more files for upload");
354       else if (how_many)
355 	s = _("Select a file for upload");
356       else
357 	s = _("Select a directory for upload");
358     }
359     snprintf(file_title, sizeof(file_title), "%s", s);
360   }
361 
362   mc_wtitle(main_w, TMID, file_title);
363   if ((new_dp_len = strlen(work_dir)) > dp_len) {
364     dp_len = new_dp_len;
365     snprintf(cwd_str_fmt, sizeof(cwd_str_fmt),
366              _("Directory: %%-%ds"), (int)dp_len);
367   }
368   new_dp_len = mbslen (work_dir);
369   if (new_dp_len + (fmt_len = mbslen(cwd_str_fmt)) > 75) {
370     size_t i;
371     char *tmp_dir = work_dir;
372 
373     /* We want the last 73 characters */
374     for (i = 0; 73 + i < new_dp_len + fmt_len; i++) {
375       wchar_t wc;
376 
377       tmp_dir += one_mbtowc(&wc, work_dir, MB_LEN_MAX);
378     }
379     snprintf(disp_dir, sizeof(disp_dir), "...%s", tmp_dir);
380     snprintf(cwd_str, sizeof(cwd_str), cwd_str_fmt, disp_dir);
381   } else
382     snprintf(cwd_str, sizeof(cwd_str), cwd_str_fmt, work_dir);
383 
384   mc_wlocate(main_w, 0, 0);
385   mc_wputs(main_w, cwd_str);
386 
387   for (i = 0; i < WHAT_NR_OPTIONS; i++) {
388     const char *str, *c;
389     size_t j;
390 
391     str = _(what[i]);
392     c = str;
393     for (j = 0; j < WHAT_WIDTH - 1 && *c != 0; j++) {
394       wchar_t wc;
395       c += one_mbtowc (&wc, c, MB_LEN_MAX);
396     }
397     what_lens[i] = c - str;
398     j = WHAT_WIDTH - j; /* Characters left for padding */
399     what_padding[i][1] = j / 2; /* Rounding down */
400     what_padding[i][0] = j - what_padding[i][1]; /* >= 1 */
401   }
402   mc_wlocate(dsub, initial_y, 0);
403   for (i = 0; i < WHAT_NR_OPTIONS; i++)
404     horiz_draw(i, mc_wgetattr(dsub), mc_wgetattr(dsub));
405 
406   mc_wsetregion(main_w, 1, main_w->ys - FILE_MWTR);
407   main_w->doscroll = 0;
408 
409   /* old dir to discard? */
410   free(dirdat);
411   dirdat = NULL;
412 
413   /* get sorted directory */
414   if ((nrents = getsdir(".", wc_str,
415                         GETSDIR_PARNT|GETSDIR_NSORT|GETSDIR_DIRSF,
416                         0, &dirdat, &longest)) < 0) {
417     /* we really want to announce the error here!!! */
418     mc_wclose(main_w, 1);
419     mc_wclose(dsub, 1);
420     free(dirdat);
421     dirdat = NULL;
422     return -1;
423   }
424 
425   global_dirdat = dirdat; // Hmm...
426 
427   prdir(main_w, top, top, dirdat, longest);
428   mc_wlocate(main_w, initial_y, main_w->ys - FILE_MWTR);
429   mc_wputs(main_w, _("( Escape to exit, Space to tag )"));
430   dhili(subm);
431   /* this really needs to go in dhili !!!*/
432   mc_wlocate(main_w, 0, cur + FILE_MWTR - top);
433   if (flushit) {
434     dirflush = 1;
435     mc_wredraw(dsub, 1);
436   }
437 
438   return 0;
439 }
440 
441 
442 /*
443  * Goto a new directory
444  */
goto_filedir(char * new_dir,int absolut)445 static void goto_filedir(char *new_dir, int absolut)
446 {
447   if (strcmp(new_dir, "..") == 0) {
448     if (strcmp(work_dir, "/")) {
449       char *sp = strrchr(work_dir, '/');
450       *sp = (char)0;
451       if (strlen(work_dir) == 0)
452         strcpy(work_dir, "/");
453     } else {
454       file_tell(_("Can't back up!"));
455       return;
456     }
457   } else if (!absolut) {
458     int new_len = strlen(work_dir) + 1;	/* + '/' */
459     if ((new_len += strlen(new_dir) + 1) > min_len) {
460       min_len = new_len;
461       work_dir = set_work_dir(work_dir, min_len);
462     }
463     if (strcmp(work_dir, "/") != 0)
464       strcat(work_dir, "/");
465     strcat(work_dir, new_dir);
466   } else {
467     int new_len = 1;
468     if (*new_dir != '/')
469       new_len += strlen(homedir) + 1;
470     new_len += strlen(new_dir);
471     if (min_len < new_len)
472       min_len = new_len;
473 
474     work_dir = set_work_dir(work_dir, min_len);
475 
476     if (*new_dir == '/')
477       strncpy(work_dir, new_dir, min_len);
478     else
479       snprintf(work_dir, min_len, "%s/%s", homedir, new_dir);
480   }
481   new_filedir(global_dirdat, 1);
482 }
483 
484 
485 /*
486  * Initialize the file directory.
487  */
init_filedir(void)488 static int init_filedir(void)
489 {
490   int x1, x2;
491   int retstat = -1;
492 
493   dirflush = 0;
494   x1 = (COLS / 2) - 37;
495   x2 = (COLS / 2) + 37;
496   dsub = mc_wopen(x1 - 1, LINES - 3, x2 + 1, LINES - 3, BNONE,
497                stdattr, mfcolor, mbcolor, 0, 0, 1);
498   main_w = mc_wopen(x1, 2, x2, LINES - 6, BSINGLE, stdattr, mfcolor,
499                  mbcolor, 0, 0, 1);
500 
501   if (ret_buf != NULL ||
502       (retstat = ((ret_buf = (char *)malloc(BUFSIZ)) == NULL)? -1 : 0) == 0) {
503     retstat = new_filedir(NULL, 0);
504     dirflush = 1;
505     mc_wredraw(dsub, 1);
506   }
507   return retstat;
508 }
509 
510 
tag_untag(char * pat,int tag)511 static int tag_untag(char *pat, int tag)
512 {
513   GETSDIR_ENTRY *d = global_dirdat;
514   int indxr, cntr;
515 
516   if (nrents < 1)
517     return 0;
518 
519   for (indxr = nrents, cntr = 0; indxr; --indxr, ++d)
520     if (S_ISREG(d->mode) && wildmat(d->fname, pat)) {
521       if (tag) {
522         d->cflags |= FL_TAG;
523         ++cntr;
524       } else if (d->cflags & FL_TAG) {
525         d->cflags &= ~FL_TAG;
526         ++cntr;
527       }
528     }
529 
530   return cntr;
531 }
532 
533 
534 /*
535  * concatenate tagged files into a buffer
536  */
concat_list(GETSDIR_ENTRY * dirdat)537 static char *concat_list(GETSDIR_ENTRY *dirdat)
538 {
539   GETSDIR_ENTRY *d;
540   int indxr, len;
541   int i;
542   char *j;
543 
544   d = dirdat;
545   for (indxr = nrents, len = 0; indxr; --indxr, ++d)
546     if (d->cflags & FL_TAG)
547       len += strlen(d->fname) + 1;
548 
549   if (len) {
550     if (len > BUFSIZ) {
551       if ((ret_buf = (char *)realloc(ret_buf, len)) == NULL) {
552         file_tell(_("Too many files tagged - buffer would overflow"));
553         return NULL;
554       }
555     }
556 
557     *ret_buf = (char)0;
558     d = dirdat;
559     for (indxr = nrents; indxr; --indxr, ++d)
560       if (d->cflags & FL_TAG) {
561         /* this could be *much* more efficient */
562         for (i = strlen(ret_buf), j = d->fname; *j; j++) {
563           if (*j == ' ') {
564             if ((ret_buf = (char*)realloc(ret_buf, ++len)) == NULL) {
565               file_tell(_("Too many files tagged - buffer would overflow"));
566               return(NULL);
567             }
568             ret_buf[i++] = '\\';
569           }
570           ret_buf[i++] = *j;
571         }
572         ret_buf[i++] = ' ';
573         ret_buf[i]   = '\0';
574       }
575 
576     ret_buf[strlen(ret_buf) - 1] = (char)0;
577     return ret_buf;
578   }
579 
580   return NULL;
581 }
582 
583 
584 /*
585  * Draw the file directory.
586  *
587  *      howmany - How many files can be selected
588  *		      0 = none (for directory selection only, as in "rz")
589  *		      1 = one  (for single-file up-/down-loads, as in "rx")
590  *		     -1 = any number (for multiple files, as in "sz")
591  *
592  *    downloading - Is this for download selection?
593  *		      0 = no
594  *		      1 = yes - when single file selected, see if it exists
595  */
filedir(int howmany,int downloading)596 char * filedir(int howmany, int downloading)
597 {
598   time_t click_time = (time_t) 0;
599   size_t i;
600 
601   how_many = howmany;
602   down_loading = downloading;
603   init_filedir();
604 
605 again:
606   mc_wlocate(main_w, 0, cur + FILE_MWTR - top);
607   if (first) {
608     mc_wredraw(main_w, 1);
609     first = 0;
610   }
611   while (!quit) {
612     GETSDIR_ENTRY *d = getno(cur, global_dirdat);
613     /*
614        if(S_ISDIR(d->mode))
615        prone(main_w, d, longest, 0);
616        */
617     switch (c = wxgetch()) {
618       case K_UP:
619       case 'k':
620         /*
621          if(S_ISDIR(d->mode))
622          prone(main_w, d, longest, 1);
623          */
624         cur -= cur > 0;
625         break;
626       case K_DN:
627       case 'j':
628         /*
629          if(S_ISDIR(d->mode))
630          prone(main_w, d, longest, 1);
631          */
632         cur += cur < nrents - 1;
633         break;
634       case K_LT:
635       case 'h':
636         subm--;
637         if (subm < 0)
638           subm = SUBM_OKAY;
639         break;
640       case K_RT:
641       case 'l':
642         subm = (subm + 1) % 6;
643         break;
644       case K_PGUP:
645       case '\002': /* Control-B */
646         pgud = 1;
647         quit = 1;
648         break;
649       case K_PGDN:
650       case '\006': /* Control-F */
651         pgud = 2;
652         quit = 1;
653         break;
654       case ' ':    /* Tag if not directory */
655         if (S_ISDIR(d->mode)) {
656           time_t this_time = time((time_t *)NULL);
657           if (this_time - click_time < 2) {
658             GETSDIR_ENTRY *d2 = getno(cur, global_dirdat);
659             goto_filedir(d2->fname, 0);
660             click_time = (time_t)0;
661           } else
662             click_time = this_time;
663         }
664         else {
665           if (how_many) {
666             if ((d->cflags ^= FL_TAG) & FL_TAG) {
667               if (tag_cnt && how_many == 1) {
668                 d->cflags &= ~FL_TAG;
669                 file_tell(_("Can select only one!"));
670                 break;
671               }
672               ++tag_cnt;
673             } else
674               --tag_cnt;
675             mc_wlocate(main_w, 0, cur + FILE_MWTR - top);
676             prone(main_w, d, longest, d->cflags & FL_TAG);
677             mc_wputc(main_w, '\n');
678             cur += cur < nrents - 1;
679           }
680         }
681         break;
682 
683       case '\033':
684       case '\r':
685       case '\n':
686         quit = 1;
687         break;
688 
689       default:
690 	for (i = 0; i < WHAT_NR_OPTIONS; i++) {
691 	  if (strchr (_(what[i]), toupper (c)) != NULL) {
692 	    subm = i;
693 	    c = '\n';
694 	    quit = 1;
695 	    break;
696 	  }
697 	 }
698 
699         break;
700     }
701 
702     if (c != ' ')
703       click_time = (time_t)0;
704 
705     if (cur < top) {
706       top--;
707       prdir(main_w, top, top, global_dirdat, longest);
708     }
709     if (cur - top > main_w->ys - (2 + FILE_MWTR)) {
710       top++;
711       prdir(main_w, top, top, global_dirdat, longest);
712     }
713     /*
714      if(cur != ocur)
715      mc_wlocate(main_w, 0, cur + FILE_MWTR - top);
716      */
717 
718     ocur = cur;
719     dhili(subm);
720     /* this really needs to go in dhili !!!*/
721     mc_wlocate(main_w, 0, cur + FILE_MWTR - top);
722   }
723 
724   quit = 0;
725   /* ESC means quit */
726   if (c == '\033') {
727     mc_wclose(main_w, 1);
728     mc_wclose(dsub, 1);
729     free(global_dirdat);
730     global_dirdat = NULL;
731     return NULL;
732   }
733   /* Page up or down ? */
734   if (pgud == 1) { /* Page up */
735     ocur = top;
736     top -= main_w->ys - (1 + FILE_MWTR);
737     if (top < 0)
738       top = 0;
739     cur = top;
740     pgud = 0;
741     if (ocur != top)
742       prdir(main_w, top, cur, global_dirdat, longest);
743     ocur = cur;
744     goto again;
745   }
746   if (pgud == 2) { /* Page down */
747     ocur = top;
748     if (top < nrents - main_w->ys + (1 + FILE_MWTR)) {
749       top += main_w->ys - (1 + FILE_MWTR);
750       if (top > nrents - main_w->ys + (1 + FILE_MWTR)) {
751         top = nrents - main_w->ys + (1 + FILE_MWTR);
752       }
753       cur = top;
754     } else
755       cur = nrents - 1;
756     pgud = 0;
757     if (ocur != top)
758       prdir(main_w, top, cur, global_dirdat, longest);
759     ocur = cur;
760     goto again;
761   }
762 
763   if (c =='\r' || c == '\n') {
764     switch(subm) {
765       case 0:
766         /* Goto directory */
767         {
768           char buf[128];
769           char *s;
770           strncpy(buf, down_loading? P_DOWNDIR : P_UPDIR, sizeof(buf) -1);
771           s = input(_("Goto directory:"), buf);
772           /* if(s == NULL || *s == (char) 0) */
773           if (s == NULL)
774             break;
775           goto_filedir(buf, 1);
776         }
777         break;
778       case 1:
779         /* Previous directory */
780         goto_filedir(prev_dir, 1);
781         break;
782       case 2:
783         /* File (wildcard) spec */
784         {
785           char *s = input(_("Filename pattern:"), wc_mem);
786           if (s == NULL || *s == (char) 0)
787             break;
788           strcpy(wc_str, wc_mem);
789           new_filedir(global_dirdat, 1);
790           wc_str[0] = (char)0;
791         }
792         break;
793       case 3:
794         /* Tag */
795         if (how_many == 1)
796           file_tell(_("Can select only one!"));
797         else if (how_many == -1) {
798           char tag_buf[128];
799           char *s;
800           strncpy(tag_buf, wc_mem, 128);
801 
802           s = input(_("Tag pattern:"), tag_buf);
803           if (s != NULL && *s != (char)0) {
804             int newly_tagged;
805             if ((newly_tagged = tag_untag(tag_buf, 1)) == 0) {
806               file_tell(_("No file(s) tagged"));
807               goto tag_end;
808             }
809             tag_cnt += newly_tagged;
810             prdir(main_w, top, top, global_dirdat, longest);
811           }
812         }
813 tag_end:
814         break;
815       case 4:
816         /* Untag */
817         {
818           char tag_buf[128];
819           char *s;
820           int untagged;
821           strncpy(tag_buf, wc_mem, 128);
822 
823           s = input(_("Untag pattern:"), tag_buf);
824           if (s == NULL || *s == (char)0)
825             goto untag_end;
826           if ((untagged = tag_untag(tag_buf, 0)) == 0) {
827             file_tell(_("No file(s) untagged"));
828             goto untag_end;
829           }
830           tag_cnt -= untagged;
831           prdir(main_w, top, top, global_dirdat, longest);
832         }
833 untag_end:
834         break;
835       case 5:
836         {
837           /* Done */
838           char *ret_ptr = NULL;	/* failsafe: assume failure */
839 
840           if (how_many != 0 && !tag_cnt) {
841 
842             while (1) {
843               s = input(_("No file selected - enter filename:"),
844                         ret_buf);
845               if (s != NULL && *s != (char) 0) {
846                 int f_exist = access(ret_buf, F_OK);
847                 if (down_loading) {
848                   if (f_exist != -1) {
849                     /* ask 'em if they're *sure* */
850                     char buf[BUFSIZ];
851 
852                     snprintf(buf, sizeof(buf),
853                              _("File: \"%s\" exists! Overwrite?"), ret_buf);
854                     if (ask(buf, d_yesno) == 0) {
855                       ret_ptr = ret_buf;
856                       break;
857                     }
858                   } else {
859                     ret_ptr = ret_buf;
860                     break;
861                   }
862                 } else {
863                   if (f_exist == -1)
864                     file_tell(_("no such file!"));
865                   else {
866                     ret_ptr = ret_buf;
867                     break;
868                   }
869                 }
870               } else {
871                 /* maybe want to ask: "abort?", here */
872                 goto again;
873               }
874             }
875           }
876           else {
877             /* put 'em in a buffer for return */
878             if (how_many == 0) {
879               /* current working directory */
880               ret_ptr = work_dir;
881             } else {
882               ret_ptr = concat_list(global_dirdat);
883             }
884           }
885 
886           mc_wclose(main_w, 1);
887           mc_wclose(dsub, 1);
888           free(global_dirdat);
889 	  global_dirdat = NULL;
890           return ret_ptr;
891         }
892         break;
893       default:
894         /* should "beep", I guess (? shouldn't get here) */
895         file_tell("BEEP!");
896         break;
897     } /* switch */
898   }
899 
900   goto again;
901 }
902