3 * ========================================================================
4 * Copyright 2006-2008 University of Washington
5 * Copyright 2013-2022 Eduardo Chappa
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * ========================================================================
15 * Program: Routines to support file browser in pico and Pine composer
20 * Misc. thoughts (mss, 5 Apr 92)
22 * This is supposed to be just a general purpose browser, equally
23 * callable from either pico or the pine composer. Someday, it could
24 * even be used to "wrap" the unix file business for really novice
25 * users. The stubs are here for renaming, copying, creating directories,
26 * deleting, undeleting (thought is delete just moves files to
27 * ~/.pico.deleted directory or something and undelete offers the
28 * files in there for undeletion: kind of like the mac trashcan).
32 * Since the full path name is always maintained and referencing ".."
33 * stats the path stripped of its trailing name, the unpleasantness of
34 * symbolic links is hidden.
36 * Fleshed out the file managements stuff (mss, 24 June 92)
41 #include "../c-client/mail.h"
42 #include "../c-client/rfc822.h"
43 #include "../pith/osdep/collate.h"
44 #include "../pith/charconv/filesys.h"
45 #include "../pith/conf.h"
49 #if defined(bsd) || defined(lnx)
57 * directory cell structure
60 char *fname
; /* file name */
61 unsigned mode
; /* file's mode */
62 char size
[16]; /* file's size in s */
69 * master browser structure
71 static struct bmaster
{
72 struct fcell
*head
; /* first cell in list */
73 struct fcell
*bottom
; /* last cell in list */
74 struct fcell
*top
; /* cell in top left */
75 struct fcell
*current
; /* currently selected */
76 int longest
; /* longest file name (in screen width) */
77 int fpl
; /* file names per line */
78 int cpf
; /* chars / file / line */
79 int menu
; /* current menu to display */
81 char dname
[NLINE
]; /* this dir's name (UTF-8) */
82 char *names
; /* malloc'd name array (UTF-8) */
84 } *gmp
; /* global master ptr */
88 * title for exported browser display
90 static char *browser_title
= NULL
;
93 struct bmaster
*getfcells(char *, int);
94 void PaintCell(int, int, int, struct fcell
*, int);
95 void PaintBrowser(struct bmaster
*, int, int *, int *);
96 struct bmaster
*RepaintBrowser(struct bmaster
*, int);
97 void BrowserKeys(void);
98 void layoutcells(struct bmaster
*);
99 void percdircells(struct bmaster
*);
100 int PlaceCell(struct bmaster
*, struct fcell
*, int *, int *);
101 void zotfcells(struct fcell
*);
102 void zotmaster(struct bmaster
**);
103 struct fcell
*FindCell(struct bmaster
*, char *, int);
104 int sisin(char *, char *);
105 void p_chdir(struct bmaster
*);
106 void BrowserAnchor(char *);
107 void ClearBrowserScreen(void);
108 void BrowserRunChild(char *, char *);
109 int fcell_is_selected(struct fcell
*, struct bmaster
*);
110 void add_cell_to_lmlist(struct fcell
*, struct bmaster
*);
111 void del_cell_from_lmlist(struct fcell
*, struct bmaster
*);
114 #define HELP_MENU {"?", N_("Get Help"), KS_SCREENHELP}
115 #define OTHER_MENU {"O", N_("OTHER CMDS"), KS_NONE}
116 static KEYMENU menu_browse
[] = {
117 HELP_MENU
, {NULL
, NULL
, KS_NONE
},
118 {NULL
, NULL
, KS_NONE
}, {"-", N_("Prev Pg"), KS_PREVPAGE
},
119 {"D", N_("Delete"), KS_NONE
}, {"C",N_("Copy"), KS_NONE
},
120 OTHER_MENU
, {NULL
, NULL
, KS_NONE
},
121 {"W", N_("Where is"), KS_NONE
}, {"Spc", N_("Next Pg"), KS_NEXTPAGE
},
122 {"R", N_("Rename"), KS_NONE
}, {NULL
, NULL
, KS_NONE
}
124 static KEYMENU menu_other
[] = {
125 HELP_MENU
, {NULL
, NULL
, KS_NONE
},
126 {NULL
, NULL
, KS_NONE
}, {NULL
, NULL
, KS_NONE
},
127 {NULL
, NULL
, KS_NONE
}, {"1", N_("One Col"), KS_NONE
},
128 OTHER_MENU
, {NULL
, NULL
, KS_NONE
},
129 {NULL
, NULL
, KS_NONE
}, {NULL
, NULL
, KS_NONE
},
130 {NULL
, NULL
, KS_NONE
}, {".", N_("Dot files"), KS_NONE
}
139 #define DIRWORD "dir"
140 #define PARENTDIR "parent"
141 #define SELECTWORD "SELECT"
145 * Default pager used by the stand-alone file browser.
147 #define BROWSER_PAGER ((gmode & MDFKEY) ? "alpine -k -F" : "alpine -F")
151 * function key mappings for callable browser
153 static UCS bfmappings
[2][12][2] = { { { F1
, '?'}, /* stand alone */
154 { F2
, NODATA
}, /* browser function */
155 { F3
, 'q'}, /* key mappings... */
165 { { F1
, '?'}, /* callable browser */
166 { F2
, NODATA
}, /* function key */
167 { F3
, 'e'}, /* mappings... */
180 * Browser help for pico (pine composer help handed to us by pine)
182 static char *BrowseHelpText
[] = {
183 /* TRANSLATORS: The next several lines go together. The ~ characters
184 should be left in front of the characters they cause to be bold. */
185 N_("Help for Browse Command"),
187 N_(" Pico's file browser is used to select a file from the"),
188 N_(" file system for inclusion in the edited text."),
190 N_("~ Both directories and files are displayed. Press ~S"),
191 N_("~ or ~R~e~t~u~r~n to select a file or directory. When a file"),
192 N_(" is selected during the \"Read File\" command, it is"),
193 N_(" inserted into edited text. Answering \"yes\" to the"),
194 N_(" verification question after a directory is selected causes"),
195 N_(" the contents of that directory to be displayed for selection."),
197 N_(" The file named \"..\" is special, and means the \"parent\""),
198 N_(" of the directory being displayed. Select this directory"),
199 N_(" to move upward in the directory tree."),
201 N_("End of Browser Help."),
207 * Help for standalone browser (pilot)
209 static char *sa_BrowseHelpText
[] = {
210 /* TRANSLATORS: Some more help text */
211 N_("Help for Pilot (PIne's Looker-upper Of Things"),
213 N_(" Pilot is a simple, display-oriented file system browser based on the"),
214 N_("~ Alpine message system composer. As with Alpine, commands are displayed at"),
215 N_("~ the bottom of the screen, and context-sensitive help is provided."),
217 N_("~ Pilot displays the current working directory at the top of the screen."),
218 N_("~ The directory's contents are displayed in columns of file name, file"),
219 N_("~ size pairs. Names that are directories are indicated by the name"),
220 N_("~ ~(~d~i~r~) in place of the file size. The parent of the current working"),
221 N_("~ directory is indicated by the file name ~.~. and size of ~(~p~a~r~e~n~t~ ~d~i~r~)."),
222 N_("~ File names that are symbolic links to other files are displayed with a"),
223 N_("~ file size of ~-~-."),
225 N_(" The following function keys are available in Pilot:"),
227 N_("~ ~? Display this help text."),
228 N_("~ ~Q Quit Pilot."),
230 N_("~ ~V View the currently selected file or open the selected directory."),
231 N_("~ Note: Pilot invokes ~a~l~p~i~n~e ~-~F, or the program defined by the ~P~A~G~E~R"),
232 N_("~ environment variable, to view the file."),
233 N_("~ ~L Launch an external application program."),
235 N_("~ ~W Search for a file by name."),
236 N_("~ ~- Scroll up one page."),
237 N_("~ ~S~p~a~c~e Scroll down one page."),
238 N_("~ ~N,~^~F Move forward (right) one column."),
239 N_("~ ~P,~^~B Move back (left) one column."),
240 N_("~ ~^~N Move down one row."),
241 N_("~ ~^~P Move up one row."),
242 N_("~ ~. Switch show dot files."),
243 N_("~ ~1 Switch single column display."),
245 N_("~ ~D Delete the selected file."),
246 N_("~ ~R Rename the selected file or directory."),
247 N_("~ ~C Copy the selected file."),
248 N_("~ ~E Edit the selected file."),
249 N_("~ Note: Pilot invokes ~p~i~c~o, or the program defined by the ~E~D~I~T~O~R"),
250 N_("~ environment variable, to edit the file."),
252 N_("End of Pilot Help."),
259 * pico_file_browse - Exported version of FileBrowse below.
262 pico_file_browse(PICO
*pdata
, char *dir
, size_t dirlen
, char *fn
, size_t fnlen
,
263 char *sz
, size_t szlen
, int flags
)
269 gmode
= pdata
->pine_flags
| MDEXTFB
;
272 /* only init screen bufs for display and winch handler */
277 term
.t_mrow
= Pmaster
->menu_rows
;
278 if(Pmaster
->oper_dir
)
279 strncpy(opertree
, Pmaster
->oper_dir
, NLINE
);
282 fixpath(opertree
, sizeof(opertree
));
285 /* install any necessary winch signal handler */
288 snprintf(title_buf
, sizeof(title_buf
), "%s FILE", pdata
->pine_anchor
);
289 set_browser_title(title_buf
);
290 rv
= FileBrowse(dir
, dirlen
, fn
, fnlen
, sz
, szlen
, flags
, NULL
);
291 set_browser_title(NULL
);
292 vttidy(); /* clean up tty handling */
293 zotdisplay(); /* and display structures */
294 Pmaster
= NULL
; /* and global config structure */
301 * FileBrowse - display contents of given directory dir
304 * dir points to initial dir to browse.
305 * dirlen- buffer size of dir
306 * fn initial file name.
307 * fnlen- buffer size of fn
310 * dir points to currently selected directory (without
311 * trailing file system delimiter)
312 * fn points to currently selected file
313 * sz points to size of file if ptr passed was non-NULL
316 * Special dispensation for FB_LMODE. If the caller sets
317 * FB_LMODEPOS, and the caller passes a non-null lmreturn,
318 * then the return values will be in lmreturn instead of
319 * in dir and fn. The caller is responsible for freeing
320 * the contents of lmreturn.
322 * 1 if a file's been selected
323 * 0 if no files selected
324 * -1 if there were problems
327 FileBrowse(char *dir
, size_t dirlen
, char *fn
, size_t fnlen
,
328 char *sz
, size_t szlen
, int fb_flags
, LMLIST
**lmreturn
)
332 int row
, col
, crow
, ccol
;
335 char *p
, *envp
, child
[2*NLINE
+2], tmp
[2*NLINE
+1];
345 if((gmode
&MDTREE
) && !in_oper_tree(dir
)){
347 emlwwrite(_("Can't read outside of %s in restricted mode"), &eml
);
353 /* fix up function key mapping table */
354 /* fix up key menu labels */
357 /* build contents of cell structures */
358 if((gmp
= getfcells(dir
, fb_flags
)) == NULL
)
363 if((tp
= FindCell(gmp
, fn
, 0)) != NULL
){
365 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
370 PaintBrowser(gmp
, 0, &crow
, &ccol
);
372 while(1){ /* the big loop */
373 if(!(gmode
&MDSHOCUR
)){
374 crow
= term
.t_nrow
-term
.t_mrow
;
378 if(!(gmode
&MDSHOCUR
))
379 movecursor(crow
, ccol
);
380 else if(gmp
->flags
& FB_LMODEPOS
){
381 if(gmp
->flags
& FB_LMODE
&& gmp
->current
->mode
!= FIODIR
)
382 movecursor(crow
, ccol
+1);
384 movecursor(crow
, ccol
+4);
387 movecursor(crow
, ccol
);
392 /* cause bottom three lines to repaint */
393 PaintBrowser(gmp
, 0, &crow
, &ccol
);
396 if(km_popped
){ /* temporarily change to cause menu to paint */
398 movecursor(term
.t_nrow
-2, 0); /* clear status line */
407 mouse_in_content(KEY_MOUSE
, -1, -1, 0, 0);
408 register_mfunc(mouse_in_content
,2,0,term
.t_nrow
-(term
.t_mrow
+1),
413 clear_mfunc(mouse_in_content
);
417 if(Pmaster
->newmail
&& (c
== NODATA
|| time_to_check())){
418 if((*Pmaster
->newmail
)(c
== NODATA
? 0 : 2, 1) >= 0){
421 if(km_popped
){ /* restore display */
423 PaintBrowser(gmp
, 0, &crow
, &ccol
);
428 rv
= (*Pmaster
->showmsg
)(c
);
431 if(rv
) /* Did showmsg corrupt the display? */
432 PaintBrowser(gmp
, 0, &crow
, &ccol
); /* Yes, repaint */
438 if(gmp
->flags
& FB_LMODEPOS
){
439 if(gmp
->flags
& FB_LMODE
&& gmp
->current
->mode
!= FIODIR
)
440 movecursor(crow
, ccol
+1);
442 movecursor(crow
, ccol
+4);
445 movecursor(crow
, ccol
);
449 if(get_input_timeout() && (c
== NODATA
|| time_to_check()))
451 emlwrite(_("You may possibly have new mail."), NULL
);
462 /* clear bottom three lines */
463 movecursor(term
.t_nrow
-2, 0);
465 movecursor(term
.t_nrow
-1, 0);
467 movecursor(term
.t_nrow
, 0);
472 if(c
== NODATA
) /* GetKey timed out */
475 (*Pmaster
->keybinput
)();
478 if(mpresf
){ /* blast old messages */
479 if(mpresf
++ > MESSDELAY
){ /* every few keystrokes */
484 /* process commands */
485 switch(new_c
= normalize_cmd(c
,bfmappings
[(gmode
&MDBRONLY
)?0:1],2)){
487 case KEY_RIGHT
: /* move right */
489 case (CTRL
|'F'): /* forward */
492 if(gmp
->current
->next
== NULL
){
497 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
498 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
499 gmp
->current
= gmp
->current
->next
;
500 if(PlaceCell(gmp
, gmp
->current
, &row
, &col
)){
501 PaintBrowser(gmp
, 1, &crow
, &ccol
);
504 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
510 case KEY_LEFT
: /* move left */
511 case (CTRL
|'B'): /* back */
514 if(gmp
->current
->prev
== NULL
){
519 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
520 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
521 gmp
->current
= gmp
->current
->prev
;
522 if(PlaceCell(gmp
, gmp
->current
, &row
, &col
)){
523 PaintBrowser(gmp
, 1, &crow
, &ccol
);
526 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
532 case (CTRL
|'A'): /* beginning of line */
540 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
541 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
543 if(PlaceCell(gmp
, tp
, &row
, &col
)){
544 PaintBrowser(gmp
, 1, &crow
, &ccol
);
547 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
553 case (CTRL
|'E'): /* end of line */
556 while(i
+gmp
->cpf
<= gmp
->cpf
* gmp
->fpl
){
562 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
563 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
565 if(PlaceCell(gmp
, tp
, &row
, &col
)){
566 PaintBrowser(gmp
, 1, &crow
, &ccol
);
569 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
575 case (CTRL
|'V'): /* page forward */
580 i
= term
.t_nrow
- term
.t_mrow
- 2;
582 while(i
-- && tp
->next
!= NULL
){
584 while(++j
<= gmp
->fpl
&& tp
->next
!= NULL
)
591 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
592 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
594 if(PlaceCell(gmp
, tp
, &row
, &col
)){
595 PaintBrowser(gmp
, 1, &crow
, &ccol
);
598 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
605 case (CTRL
|'Y'): /* page backward */
609 i
= term
.t_nrow
- term
.t_mrow
- 4;
610 while(i
-- && tp
!= NULL
){
612 while(j
-- && tp
!= NULL
)
616 if(tp
|| (gmp
->current
!= gmp
->top
)){ /* clear old hilite */
617 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
618 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
621 if(tp
) /* new page ! */
623 else if(gmp
->current
!= gmp
->top
) /* goto top of page */
624 gmp
->current
= gmp
->top
;
625 else /* do nothing */
628 if(PlaceCell(gmp
, gmp
->current
, &row
, &col
)){
629 PaintBrowser(gmp
, 1, &crow
, &ccol
);
632 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
640 case (CTRL
|'N'): /* next */
644 if(tp
->next
== NULL
){
651 if(i
!= -1) /* can't go down */
654 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
655 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
657 if(PlaceCell(gmp
, tp
, &row
, &col
)){
658 PaintBrowser(gmp
, 1, &crow
, &ccol
);
661 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
668 case (CTRL
|'P'): /* previous */
677 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
678 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
680 if(PlaceCell(gmp
, tp
, &row
, &col
)){
681 PaintBrowser(gmp
, 1, &crow
, &ccol
);
684 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
692 mouse_get_last (NULL
, &mousep
);
693 if (mousep
.doubleclick
) {
697 row
= mousep
.row
-= 2; /* Adjust for header*/
699 i
= row
* gmp
->fpl
+ (col
/ gmp
->cpf
); /* Count from top */
700 tp
= gmp
->top
; /* start at top. */
701 for (; i
> 0 && tp
!= NULL
; --i
) /* Count cells. */
703 if (tp
!= NULL
) { /* Valid cell? */
704 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
705 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
707 if(PlaceCell(gmp
, tp
, &row
, &col
)){
708 PaintBrowser(gmp
, 1, &crow
, &ccol
);
711 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
720 case 'e': /* exit or edit */
722 if(gmode
&MDBRONLY
){ /* run "pico" */
724 snprintf(child
, sizeof(child
), "%.*s%c%.*s", NLINE
, gmp
->dname
, C_FILESEP
,
725 NLINE
, gmp
->current
->fname
);
726 /* make sure selected isn't a directory or executable */
727 if(!LikelyASCII(child
)){
728 emlwrite(_("Can't edit non-text file. Try Launch."), NULL
);
732 if((envp
= (char *) getenv("EDITOR")) != NULL
){
733 t
= fs_get(strlen(envp
) + strlen(child
) + 3 + 1);
734 sprintf(t
, "%s \'%s\'", envp
, child
);
737 t
= fs_get(strlen(child
) + 16 + 1);
738 sprintf(t
, "pico%s%s%s \'%s\'",
739 (gmode
& MDFKEY
) ? " -f" : "",
740 (gmode
& MDSHOCUR
) ? " -g" : "",
741 (gmode
& MDMOUSE
) ? " -m" : "",
745 BrowserRunChild(t
, gmp
->dname
); /* spawn pico */
746 PaintBrowser(gmp
, 0, &crow
, &ccol
); /* redraw browser */
747 if(t
) fs_give((void **) &t
);
756 case 'q': /* user exits wrong */
766 case 'x': /* toggle selection */
768 if(!(gmp
->flags
& FB_LMODE
)){
769 if(gmp
->flags
& FB_LMODEPOS
)
770 emlwwrite(_("Type L command to use ListMode"), NULL
);
777 if(gmp
->current
->mode
== FIODIR
){
778 emlwwrite(_("Can't Set directories"), NULL
);
782 if(fcell_is_selected(gmp
->current
, gmp
))
783 del_cell_from_lmlist(gmp
->current
, gmp
);
785 add_cell_to_lmlist(gmp
->current
, gmp
);
787 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
788 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
791 case 'l': /* run Command */
792 case 'L': /* or ListMode */
793 if(gmp
->flags
& FB_LMODEPOS
){
794 if(gmp
->flags
& FB_LMODE
){
796 * Unless we make it so you can get out of ListMode
797 * once you're in ListMode, this must be an error.
799 emlwwrite(_("Already in ListMode"), NULL
);
803 gmp
->flags
|= FB_LMODE
;
804 PaintBrowser(gmp
, 0, &crow
, &ccol
);
810 if(!(gmode
&MDBRONLY
)){
815 /* add subcommands to invoke pico and insert selected filename */
816 /* perhaps: add subcmd to scroll command history */
820 snprintf(child
, sizeof(child
), "%.*s%c%.*s", NLINE
, gmp
->dname
, C_FILESEP
,
821 NLINE
, gmp
->current
->fname
);
823 static EXTRAKEYS opts
[] = {
824 {"^X", N_("Add Name"), CTRL
|'X', KS_NONE
},
825 {NULL
, NULL
, 0, KS_NONE
},
826 {NULL
, NULL
, 0, KS_NONE
},
827 {NULL
, NULL
, 0, KS_NONE
},
828 {NULL
, NULL
, 0, KS_NONE
},
829 {NULL
, NULL
, 0, KS_NONE
},
830 {NULL
, NULL
, 0, KS_NONE
},
831 {NULL
, NULL
, 0, KS_NONE
},
832 {NULL
, NULL
, 0, KS_NONE
},
833 {NULL
, NULL
, 0, KS_NONE
}
836 status
= mlreply_utf8(_("Command to execute: "),
837 tmp
, NLINE
, QNORML
, opts
);
840 emlwwrite(_("No help yet!"), NULL
);
841 /* remove break and sleep after help text is installed */
845 strncat(tmp
, child
, sizeof(tmp
)-strlen(tmp
)-1);
846 tmp
[sizeof(tmp
)-1] = '\0';
849 PaintBrowser(gmp
, 0, &crow
, &ccol
);
852 emlwrite(_("Command cancelled"), NULL
);
860 emlwrite(_("No command specified"), NULL
);
864 BrowserRunChild(tmp
, gmp
->dname
);
865 PaintBrowser(gmp
, 0, &crow
, &ccol
);
875 case 'd': /* delete */
877 if(gmp
->current
->mode
== FIODIR
){
878 /* BUG: if dir is empty it should be deleted */
879 emlwwrite(_("Can't delete a directory"), NULL
);
883 if(gmode
&MDSCUR
){ /* not allowed! */
884 emlwrite(_("Delete not allowed in restricted mode"),NULL
);
888 snprintf(child
, sizeof(child
), "%s%c%s", gmp
->dname
, C_FILESEP
,
889 gmp
->current
->fname
);
892 while(i
++ < 2){ /* verify twice!! */
894 if(fexist(child
, "w", (off_t
*)NULL
) != FIOSUC
){
895 strncpy(tmp
, _("File is write protected! OVERRIDE"), sizeof(tmp
));
896 tmp
[sizeof(tmp
)-1] = '\0';
899 /* TRANSLATORS: This is a question, Delete file <filename> */
900 snprintf(tmp
, sizeof(tmp
), _("Delete file \"%.*s\""), NLINE
- 20, child
);
903 strncpy(tmp
, _("File CANNOT be UNdeleted! Really delete"), sizeof(tmp
));
904 tmp
[sizeof(tmp
)-1] = '\0';
907 if((status
= mlyesno_utf8(tmp
, FALSE
)) != TRUE
){
908 emlwrite((status
== ABORT
)
909 ? _("Delete Cancelled")
910 : _("File Not Deleted"),
917 if(our_unlink(child
) < 0){
918 eml
.s
= errstr(errno
);
919 emlwrite(_("Delete Failed: %s"), &eml
);
921 else{ /* fix up pointers and redraw */
924 gmp
->current
= tp
->next
;
925 if((tp
->next
->prev
= tp
->prev
) != NULL
)
926 tp
->prev
->next
= tp
->next
;
929 gmp
->current
= tp
->prev
;
930 if((tp
->prev
->next
= tp
->next
) != NULL
)
931 tp
->next
->prev
= tp
->prev
;
935 gmp
->head
= tp
->next
;
937 if(tp
== gmp
->bottom
)
938 gmp
->bottom
= tp
->prev
;
941 tp
->next
= tp
->prev
= NULL
;
942 if(tp
!= gmp
->current
)
945 if((tp
= FindCell(gmp
, gmp
->current
->fname
, 0)) != NULL
){
947 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
950 PaintBrowser(gmp
, 1, &crow
, &ccol
);
958 case '?': /* HELP! */
960 if(term
.t_mrow
== 0){
968 VARS_TO_SAVE
*saved_state
;
970 saved_state
= save_pico_state();
971 (*Pmaster
->helper
)(Pmaster
->browse_help
,
972 _("Help for Browsing"), 1);
974 restore_pico_state(saved_state
);
975 free_pico_state(saved_state
);
978 else if(gmode
&MDBRONLY
)
979 pico_help(sa_BrowseHelpText
, _("Browser Help"), 1);
981 pico_help(BrowseHelpText
, _("Help for Browsing"), 1);
982 /* fall thru to repaint everything */
985 PaintBrowser(gmp
, 0, &crow
, &ccol
);
988 case 'g': /* jump to a directory */
999 /* TRANSLATORS: A prompt asking for a directory to
1001 status
= mlreply_utf8(_("Directory to go to: "), child
, NLINE
, QNORML
,
1006 emlwwrite(_("No help yet!"), NULL
);
1007 /* remove break and sleep after help text is installed */
1011 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1014 emlwrite(_("Goto cancelled"), NULL
);
1022 strncpy(child
, gethomedir(NULL
), sizeof(child
));
1023 child
[sizeof(child
)-1] = '\0';
1026 if(!compresspath(gmp
->dname
, child
, sizeof(child
))){
1028 emlwrite(_("Invalid Directory: %s"), &eml
);
1032 if((gmode
&MDSCUR
) && homeless(child
)){
1033 emlwrite(_("Restricted mode browsing limited to home directory"),NULL
);
1037 if((gmode
&MDTREE
) && !in_oper_tree(child
)){
1039 emlwwrite(_("Can't go outside of %s in restricted mode"),
1044 if(isdir(child
, (long *) NULL
, NULL
)){
1045 if((mp
= getfcells(child
, fb_flags
)) == NULL
){
1046 /* getfcells should explain what happened */
1053 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1057 emlwwrite(_("Not a directory: \"%s\""), &eml
);
1068 case '.': /* display dot files */
1070 gmp
= RepaintBrowser(gmp
, fb_flags
);
1073 case '1': /* One column mode */
1075 gmp
= RepaintBrowser(gmp
, fb_flags
);
1078 case 'o': /* Other menu */
1092 if(gmode
&MDSCUR
){ /* not allowed! */
1093 emlwrite(_("Add not allowed in restricted mode"),NULL
);
1100 /* pass in default filename */
1102 strncpy(child
, fn
, sizeof(child
) - 1);
1103 child
[sizeof(child
) - 1] = '\0';
1110 memset((void *) &opts
, 0, 10*sizeof(EXTRAKEYS
));
1111 opts
[0].name
= "^X";
1112 opts
[0].label
= add_file
? N_("Add Dir") : N_("Add File");
1113 opts
[0].key
= (CTRL
|'X');
1115 switch(status
=mlreply_utf8(add_file
? _("Name of file to add: ") : _("Name of directory to add: "), child
, NLINE
,
1118 emlwwrite(_("No help yet!"), NULL
);
1119 /* remove break and sleep after help text is installed */
1123 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1126 if(add_file
> 0) add_file
= 0; else add_file
= 1;
1129 emlwrite(add_file
> 0 ? _("Add File Cancelled") : _("Add Directory Cancelled"), NULL
);
1134 * Support default filename. A return of 'FALSE' means
1135 * 'No change in filename' which is fine if we have
1136 * provided a default.
1137 * John Berthels <john.berthels@nexor.co.uk>
1143 if(child
[0] == '\0'){
1144 emlwrite(add_file
> 0 ? _("No file named. Add Cancelled.") : _("No directory named. Add Cancelled"), NULL
);
1148 if(!compresspath(gmp
->dname
, child
, sizeof(child
))){
1149 emlwrite(_("Too many ..'s in name"), NULL
);
1153 if((gmode
&MDTREE
) && !in_oper_tree(child
)){
1155 emlwwrite(_("Restricted mode allows Add in %s only"),
1160 if((status
= fexist(child
, "w", (off_t
*)NULL
)) == FIOSUC
){
1161 snprintf(tmp
, sizeof(tmp
), _("%s \"%.*s\" already exists!"),
1162 add_file
> 0 ? "File" : "Directory", NLINE
- 20, child
);
1163 emlwrite(tmp
, NULL
);
1166 else if(status
!= FIOFNF
){
1167 fioperr(status
, child
);
1172 if(our_mkdir(child
, (0700)) < 0){
1174 emlwrite(_("Error adding Directory \"%s\""), &eml
);
1176 else /* success! Directory added! */
1179 else if(ffwopen(child
, FALSE
) != FIOSUC
){
1180 /* ffwopen should've complained */
1183 else{ /* highlight new file */
1186 emlwrite(_("Added File \"%s\""), &eml
);
1191 if((p
= strrchr(child
, C_FILESEP
)) == NULL
){
1192 emlwrite(_("Problems refiguring browser"), NULL
);
1198 strncpy(tmp
, child
, sizeof(tmp
));
1199 tmp
[sizeof(tmp
)-1] = '\0';
1201 while((child
[j
++] = *++p
) != '\0')
1205 strncpy(tmp
, S_FILESEP
, sizeof(tmp
));
1206 tmp
[sizeof(tmp
)-1] = '\0';
1210 * new file in same dir? if so, refigure files
1213 if(!strcmp(tmp
, gmp
->dname
)){
1214 if((mp
= getfcells(gmp
->dname
, fb_flags
)) == NULL
)
1215 /* getfcells should explain what happened */
1220 if((tp
= FindCell(gmp
, child
, 0)) != NULL
){
1222 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1225 PaintBrowser(gmp
, 1, &crow
, &ccol
);
1237 case 'c': /* copy */
1239 if(gmp
->current
->mode
== FIODIR
){
1240 emlwwrite(_("Can't copy a directory"), NULL
);
1244 if(gmode
&MDSCUR
){ /* not allowed! */
1245 emlwrite(_("Copy not allowed in restricted mode"),NULL
);
1254 switch(status
=mlreply_utf8(_("Name of new copy: "), child
, NLINE
,
1257 emlwwrite(_("No help yet!"), NULL
);
1258 /* remove break and sleep after help text is installed */
1262 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1265 emlwrite(_("Make Copy Cancelled"), NULL
);
1275 if(child
[0] == '\0'){
1276 emlwrite(_("No destination, file not copied"), NULL
);
1280 if(!strcmp(gmp
->current
->fname
, child
)){
1281 emlwwrite(_("Can't copy file on to itself!"), NULL
);
1285 if(!compresspath(gmp
->dname
, child
, sizeof(child
))){
1286 emlwrite(_("Too many ..'s in name"), NULL
);
1290 if((gmode
&MDTREE
) && !in_oper_tree(child
)){
1292 emlwwrite(_("Restricted mode allows Copy in %s only"),
1297 if((status
= fexist(child
, "w", (off_t
*)NULL
)) == FIOSUC
){
1298 /* TRANSLATORS: A question: File <filename> exists! Replace? */
1299 snprintf(tmp
, sizeof(tmp
), _("File \"%.*s\" exists! OVERWRITE"),
1301 if((status
= mlyesno_utf8(tmp
, 0)) != TRUE
){
1302 emlwrite((status
== ABORT
)
1303 ? _("Make copy cancelled")
1304 : _("File Not Renamed"),
1309 else if(status
!= FIOFNF
){
1310 fioperr(status
, child
);
1314 snprintf(tmp
, sizeof(tmp
), "%.*s%c%.*s", NLINE
, gmp
->dname
, C_FILESEP
,
1315 NLINE
, gmp
->current
->fname
);
1317 if(copy(tmp
, child
) < 0){
1318 /* copy() will report any error messages */
1321 else{ /* highlight new file */
1323 emlwrite(_("File copied to %s"), &eml
);
1325 if((p
= strrchr(child
, C_FILESEP
)) == NULL
){
1326 emlwrite(_("Problems refiguring browser"), NULL
);
1331 strncpy(tmp
, (p
== child
) ? S_FILESEP
: child
, sizeof(tmp
));
1332 tmp
[sizeof(tmp
)-1] = '\0';
1335 * new file in same dir? if so, refigure files
1338 if(!strcmp(tmp
, gmp
->dname
)){
1339 strncpy(child
, gmp
->current
->fname
, sizeof(child
));
1340 child
[sizeof(child
)-1] = '\0';
1341 if((mp
= getfcells(gmp
->dname
, fb_flags
)) == NULL
)
1342 /* getfcells should explain what happened */
1347 if((tp
= FindCell(gmp
, child
, 0)) != NULL
){
1349 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1352 PaintBrowser(gmp
, 1, &crow
, &ccol
);
1363 case 'r': /* rename */
1367 if(!strcmp(gmp
->current
->fname
, "..")){
1368 emlwwrite(_("Can't rename \"..\""), NULL
);
1372 if(gmode
&MDSCUR
){ /* not allowed! */
1373 emlwrite(_("Rename not allowed in restricted mode"),NULL
);
1377 strncpy(child
, gmp
->current
->fname
, sizeof(child
));
1378 child
[sizeof(child
)-1] = '\0';
1382 switch(status
=mlreply_utf8(_("Rename file to: "), child
, NLINE
, QFFILE
,
1385 emlwwrite(_("No help yet!"), NULL
);
1386 /* remove break and sleep after help text is installed */
1390 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1393 emlwrite(_("Rename cancelled"), NULL
);
1400 if(child
[0] == '\0' || status
== FALSE
){
1405 if(!compresspath(gmp
->dname
, child
, sizeof(child
))){
1406 emlwrite(_("Too many ..'s in name"), NULL
);
1410 if((gmode
&MDTREE
) && !in_oper_tree(child
)){
1412 emlwwrite(_("Restricted mode allows Rename in %s only"),
1417 status
= fexist(child
, "w", (off_t
*)NULL
);
1418 if(status
== FIOSUC
|| status
== FIOFNF
){
1419 if(status
== FIOSUC
){
1420 snprintf(tmp
, sizeof(tmp
), _("File \"%.*s\" exists! OVERWRITE"),
1423 if((status
= mlyesno_utf8(tmp
, FALSE
)) != TRUE
){
1424 emlwrite((status
== ABORT
)
1425 ? _("Rename cancelled")
1432 snprintf(tmp
, sizeof(tmp
), "%.*s%c%.*s", NLINE
, gmp
->dname
, C_FILESEP
,
1433 NLINE
, gmp
->current
->fname
);
1435 if(our_rename(tmp
, child
) < 0){
1436 eml
.s
= errstr(errno
);
1437 emlwrite(_("Rename Failed: %s"), &eml
);
1440 if((p
= strrchr(child
, C_FILESEP
)) == NULL
){
1441 emlwrite(_("Problems refiguring browser"), NULL
);
1446 strncpy(tmp
, (p
== child
) ? S_FILESEP
: child
, sizeof(tmp
));
1447 tmp
[sizeof(tmp
)-1] = '\0';
1449 if((mp
= getfcells(tmp
, fb_flags
)) == NULL
)
1450 /* getfcells should explain what happened */
1456 if((tp
= FindCell(gmp
, ++p
, 0)) != NULL
){
1458 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1461 PaintBrowser(gmp
, 1, &crow
, &ccol
);
1466 fioperr(status
, child
);
1476 case 'v': /* stand-alone */
1477 case 'V': /* browser "view" */
1478 case 's': /* user "select" */
1483 if(((new_c
== 'S' || new_c
== 's') && (gmode
&MDBRONLY
))
1484 || ((new_c
== 'V' || new_c
== 'v') && !(gmode
&MDBRONLY
)))
1487 if(gmp
->current
->mode
== FIODIR
){
1489 strncpy(tmp
, gmp
->dname
, sizeof(tmp
));
1490 tmp
[sizeof(tmp
)-1] = '\0';
1491 p
= gmp
->current
->fname
;
1492 if(p
[0] == '.' && p
[1] == '.' && p
[2] == '\0'){
1493 if((p
=strrchr(tmp
, C_FILESEP
)) != NULL
){
1496 if((gmode
&MDTREE
) && !in_oper_tree(tmp
)){
1499 _("Can't visit %s in restricted mode"),
1504 strncpy(child
, &p
[1], sizeof(child
));
1505 child
[sizeof(child
)-1] = '\0';
1508 #if defined(DOS) || defined(OS2)
1509 (p
== tmp
|| (tmp
[1] == ':' && tmp
[2] == '\0'))
1514 #if defined(DOS) || defined(OS2)
1516 strncat(tmp
, S_FILESEP
, sizeof(tmp
)-strlen(tmp
)-1);
1517 tmp
[sizeof(tmp
)-1] = '\0';
1521 strncpy(tmp
, S_FILESEP
, sizeof(tmp
));
1522 tmp
[sizeof(tmp
)-1] = '\0';
1526 emlwwrite(_("Can't move up a directory"),
1533 else if((fb_flags
&FB_SAVE
) && p
[0] == '.' && p
[1] == '\0'){
1534 if ((strlen(gmp
->dname
) < dirlen
) &&
1535 (strlen(gmp
->current
->fname
) < fnlen
)){
1536 strncpy(dir
, gmp
->dname
, dirlen
);
1537 dir
[dirlen
-1] = '\0';
1541 return(0); /* just change the directory, still return no selection */
1544 if(tmp
[1] != '\0'){ /* were in root? */
1545 strncat(tmp
, S_FILESEP
, sizeof(tmp
)-strlen(tmp
)-1);
1546 tmp
[sizeof(tmp
)-1] = '\0';
1549 strncat(tmp
, gmp
->current
->fname
, sizeof(tmp
)-strlen(tmp
)-1);
1550 tmp
[sizeof(tmp
)-1] = '\0';
1553 if((mp
= getfcells(tmp
, fb_flags
)) == NULL
)
1554 /* getfcells should explain what happened */
1557 if(gmp
->flags
& FB_LMODE
){
1558 mp
->flags
|= FB_LMODE
;
1568 if((tp
= FindCell(gmp
, child
, 0)) != NULL
){
1570 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1574 emlwwrite(_("Problem finding dir \"%s\""), &eml
);
1578 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1582 snprintf(b
, sizeof(b
), "Select/View \" .. %s %s\" to return to previous directory.", PARENTDIR
, DIRWORD
);
1588 else if(gmode
&MDBRONLY
){
1589 snprintf(child
, sizeof(child
), "%.*s%c%.*s", NLINE
, gmp
->dname
, C_FILESEP
,
1590 NLINE
, gmp
->current
->fname
);
1592 if(LikelyASCII(child
)){
1594 envp
= (char *) getenv("PAGER");
1595 t
= fs_get((envp
? strlen(envp
) : strlen(BROWSER_PAGER
))
1596 + strlen(child
) + 3 + 1);
1597 sprintf(t
, "%s \'%s\'", envp
? envp
: BROWSER_PAGER
, child
);
1598 BrowserRunChild(t
, gmp
->dname
);
1599 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1600 if(t
) fs_give((void **) &t
);
1605 else{ /* just return */
1606 if(gmp
->flags
& FB_LMODEPOS
){
1609 emlwrite("Programming error, called FileBrowse with LMODEPOS but no lmreturn", NULL
);
1614 /* user actually used ListMode, the list is finished */
1615 if(gmp
->flags
& FB_LMODE
){
1618 emlwrite(_("No files are selected, use \"X\" to mark files for selection"), NULL
);
1622 *lmreturn
= gmp
->lm
;
1625 else{ /* construct an lmreturn for user */
1629 if((new=(LMLIST
*)malloc(sizeof(*new))) == NULL
1630 || (new->fname
=malloc(gmp
->current
->fname
? (flen
=strlen(gmp
->current
->fname
))+1 : 1)) == NULL
1631 || (new->dir
=malloc((dlen
=strlen(gmp
->dname
))+1)) == NULL
){
1632 emlwwrite(_("Can't malloc space for filename"), NULL
);
1637 gmp
->current
->fname
? gmp
->current
->fname
: "", flen
);
1638 new->fname
[flen
] = '\0';
1639 strncpy(new->dir
, gmp
->dname
, dlen
);
1640 new->dir
[dlen
] = '\0';
1641 strncpy(new->size
, gmp
->current
->size
, sizeof(new->size
));
1642 new->size
[sizeof(new->size
)-1] = '\0';
1651 if ((strlen(gmp
->dname
) < dirlen
) &&
1652 (strlen(gmp
->current
->fname
) < fnlen
)){
1653 strncpy(dir
, gmp
->dname
, dirlen
);
1654 dir
[dirlen
-1] = '\0';
1655 strncpy(fn
, gmp
->current
->fname
, fnlen
);
1662 if(sz
!= NULL
){ /* size uninteresting */
1663 strncpy(sz
, gmp
->current
->size
, szlen
);
1672 case 'w': /* Where is */
1676 flags
= SR_ORIGMEN
| SR_FORWARD
| SR_NOEXACT
;
1679 switch(readpattern(_("File name to find"), FALSE
, flags
)){
1681 emlwwrite(_("No help yet!"), NULL
);
1682 /* remove break and sleep after help text is installed */
1686 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1689 if(flags
& SR_FORWARD
){
1690 flags
&= ~SR_FORWARD
;
1691 flags
|= SR_BACKWRD
;
1693 flags
&= ~SR_BACKWRD
;
1694 flags
|= SR_FORWARD
;
1697 case (CTRL
|'Y'): /* first first cell */
1698 for(tp
= gmp
->top
; tp
->prev
; tp
= tp
->prev
)
1702 /* fall thru to repaint */
1707 if((i
= term
.t_nrow
- term
.t_mrow
- 2) <= 0)
1710 while(i
-- && tp
->next
){
1712 while(++j
<= gmp
->fpl
&& tp
->next
)
1721 emlwrite(_("Searched to end of directory"), NULL
);
1724 emlwrite(_("Searched to start of directory"), NULL
);
1727 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1728 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
1730 if(PlaceCell(gmp
, gmp
->current
, &row
, &col
)){
1731 PaintBrowser(gmp
, 1, &crow
, &ccol
);
1734 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
1740 i
++; /* make sure we jump out */
1743 emlwrite(_("Whereis cancelled"), NULL
);
1755 utf8
= ucs4_to_utf8_cpystr(pat
);
1757 if(utf8
&& (tp
= FindCell(gmp
, utf8
, flags
& SR_BACKWRD
)) != NULL
){
1758 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
1759 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 0);
1762 if(PlaceCell(gmp
, tp
, &row
, &col
)){ /* top changed */
1763 PaintBrowser(gmp
, 1, &crow
, &ccol
);
1766 PaintCell(row
, col
, gmp
->cpf
, gmp
->current
, 1);
1774 emlwrite(_("\"%s\" not found"), &eml
);
1778 fs_give((void **) &utf8
);
1792 #if defined MOUSE && !defined(_WINDOWS)
1793 toggle_xterm_mouse(0,1);
1802 PaintBrowser(gmp
, 0, &crow
, &ccol
);
1804 } /* fall thru with error! */
1806 default: /* what? */
1810 case NODATA
: /* no op */
1818 * getfcells - make a master browser struct and fill it in
1819 * return NULL if there's a problem.
1822 getfcells(char *dname
, int fb_flags
)
1824 int i
, /* various return codes */
1826 nentries
= 0; /* number of dir ents */
1828 char *np
, /* names of files in dir */
1829 *dcp
, /* to add file to path */
1831 **filtnames
, /* array filtered names */
1833 struct fcell
*ncp
, /* new cell pointer */
1834 *tcp
= NULL
; /* trailing cell ptr */
1839 if((mp
=(struct bmaster
*)malloc(sizeof(struct bmaster
))) == NULL
){
1840 emlwwrite(_("Can't malloc space for master filename cell"), NULL
);
1844 memset(mp
, 0, sizeof(*mp
));
1846 if(dname
[0] == '.' && dname
[1] == '\0'){ /* remember this dir */
1847 if(!getcwd(mp
->dname
, 256))
1848 mp
->dname
[0] = '\0';
1850 else if(dname
[0] == '.' && dname
[1] == '.' && dname
[2] == '\0'){
1851 if(!getcwd(mp
->dname
, 256))
1852 mp
->dname
[0] = '\0';
1854 if((np
= (char *)strrchr(mp
->dname
, C_FILESEP
)) != NULL
)
1860 strncpy(mp
->dname
, dname
, sizeof(mp
->dname
));
1861 mp
->dname
[sizeof(mp
->dname
)-1] = '\0';
1864 mp
->bottom
= mp
->head
= mp
->top
= NULL
;
1865 mp
->menu
= mp
->cpf
= mp
->fpl
= 0;
1866 mp
->longest
= 5; /* .. must be labeled! */
1867 mp
->flags
= fb_flags
;
1870 emlwrite("Building file list of %s...", &eml
);
1872 if((mp
->names
= getfnames(mp
->dname
, NULL
, &nentries
, errbuf
, sizeof(errbuf
))) == NULL
){
1875 emlwwrite(errbuf
, NULL
);
1881 * this is the fun part. build an array of pointers to the fnames we're
1882 * interested in (i.e., do any filtering), then pass that off to be
1883 * sorted before building list of cells...
1885 * right now default filtering on ".*" except "..", but this could
1886 * easily be made a user option later on...
1888 if((filtnames
=(char **)malloc((nentries
+1) * sizeof(char *))) == NULL
){
1889 emlwwrite(_("Can't malloc space for name array"), NULL
);
1894 i
= 0; /* index of filt'd array */
1901 * Filter dot files? Always filter ".", never filter "..",
1902 * and sometimes filter ".*"...
1904 if(*np
== '.' && (!(*(np
+1) == '.' && *(np
+2) == '\0')
1905 && !(*(np
+1) == '\0' && (fb_flags
&FB_SAVE
)))
1906 && (*(np
+1) == '\0' || !(gmode
& MDDOTSOK
))){
1907 np
+= strlen(np
) + 1;
1911 filtnames
[i
++] = np
;
1913 ii
= (int) strlen(np
);
1914 if((width
= (int) utf8_width(np
)) > mp
->longest
)
1915 mp
->longest
= width
; /* remember longest */
1917 np
+= ii
+ 1; /* advance name pointer */
1920 nentries
= i
; /* new # of entries */
1923 * sort files case independently
1925 qsort((qsort_t
*)filtnames
, (size_t)nentries
, sizeof(char *), sstrcasecmp
);
1928 * this is so we use absolute path names for stats.
1929 * remember: be careful using dname as directory name, and fix mp->dname
1932 dcp
= (char *) strchr(mp
->dname
, '\0');
1933 if(dcp
== mp
->dname
|| dcp
[-1] != C_FILESEP
){
1941 while(nentries
--){ /* stat filtered files */
1942 /* get a new cell */
1943 if((ncp
=(struct fcell
*)malloc(sizeof(struct fcell
))) == NULL
){
1944 emlwwrite(_("Can't malloc cells for browser!"), NULL
);
1945 zotfcells(mp
->head
); /* clean up cells */
1946 free((char *) filtnames
);
1948 return(NULL
); /* bummer. */
1951 ncp
->next
= ncp
->prev
= NULL
;
1953 if(mp
->head
== NULL
){ /* tie it onto the list */
1954 mp
->head
= mp
->top
= mp
->current
= ncp
;
1964 /* fill in the new cell */
1965 ncp
->fname
= filtnames
[i
++];
1967 /* fill in file's mode */
1968 if ((flength
= strlen(ncp
->fname
) + 1 + strlen(dname
)) < sizeof(mp
->dname
)){
1969 strncpy(&dcp
[1], ncp
->fname
, sizeof(mp
->dname
)-(dcp
+1-mp
->dname
)); /* use absolute path! */
1970 mp
->dname
[sizeof(mp
->dname
)-1] = '\0';
1974 if((tmpstr
= (char *)malloc((flength
+1)*sizeof(char))) == NULL
){
1975 emlwwrite(_("Can't malloc cells for temp buffer!"), NULL
);
1976 zotfcells(mp
->head
); /* clean up cells */
1977 free((char *) filtnames
);
1979 return(NULL
); /* bummer. */
1982 strncpy(tmpstr
, dname
, flength
);
1983 tmpstr
[flength
] = '\0';
1984 tmpstr
= strncat(tmpstr
, S_FILESEP
, flength
+1-1-strlen(tmpstr
));
1985 tmpstr
[flength
] = '\0';
1986 tmpstr
= strncat(tmpstr
, ncp
->fname
, flength
+1-1-strlen(tmpstr
));
1987 tmpstr
[flength
] = '\0';
1990 switch(fexist(tmpstr
, "t", &attsz
)){
1993 snprintf(ncp
->size
, sizeof(ncp
->size
), "(%s%s%s)",
1994 (ncp
->fname
[0] == '.' && ncp
->fname
[1] == '.'
1995 && ncp
->fname
[2] == '\0') ? PARENTDIR
:
1996 ((fb_flags
&FB_SAVE
) && ncp
->fname
[0] == '.' && ncp
->fname
[1] == '\0'
1998 (ncp
->fname
[0] == '.' && ncp
->fname
[1] == '.'
1999 && ncp
->fname
[2] == '\0') ? " " :
2000 ((fb_flags
&FB_SAVE
) && ncp
->fname
[0] == '.' && ncp
->fname
[1] == '\0'
2007 strncpy(ncp
->size
, "--", sizeof(ncp
->size
));
2008 ncp
->size
[sizeof(ncp
->size
)-1] = '\0';
2012 ncp
->mode
= FIOSUC
; /* regular file */
2013 strncpy(ncp
->size
, prettysz(attsz
), sizeof(ncp
->size
));
2014 ncp
->size
[sizeof(ncp
->size
)-1] = '\0';
2018 if (flength
>= NLINE
)
2019 free((char *) tmpstr
);
2022 dcp
[(dcp
== mp
->dname
) ? 1 : 0] = '\0'; /* remember to cap dname */
2023 free((char *) filtnames
); /* 'n blast filt'd array*/
2027 if(strlen(mp
->dname
) < sizeof(browse_dir
)){
2028 strncpy(browse_dir
, mp
->dname
, sizeof(browse_dir
));
2029 browse_dir
[sizeof(browse_dir
)-1] = '\0';
2032 browse_dir
[0] = '\0';
2039 fcell_is_selected(struct fcell
*cell
, struct bmaster
*mp
)
2043 if(cell
&& cell
->fname
){
2044 for(lm
= mp
? mp
->lm
: NULL
; lm
; lm
= lm
->next
){
2045 /* directory has to match */
2046 if(!((mp
->dname
[0] == '\0' && (!lm
->dir
|| lm
->dir
[0] =='\0'))
2047 || (mp
->dname
[0] != '\0' && lm
->dir
&& lm
->dir
[0] !='\0'
2048 && !strcmp(mp
->dname
, lm
->dir
))))
2051 if(lm
->fname
&& !strcmp(cell
->fname
, lm
->fname
))
2061 * Adds a new name to the head of the lmlist
2064 add_cell_to_lmlist(struct fcell
*cell
, struct bmaster
*mp
)
2069 if(mp
&& cell
&& cell
->fname
&& cell
->fname
[0]){
2070 if((new=(LMLIST
*)malloc(sizeof(*new))) == NULL
||
2071 (new->fname
=malloc(sizeof(char)*((flen
=strlen(cell
->fname
))+1))) == NULL
||
2072 (new->dir
=malloc(sizeof(char)*((dlen
=strlen(mp
->dname
))+1))) == NULL
){
2073 emlwwrite(_("Can't malloc space for filename"), NULL
);
2077 strncpy(new->fname
, cell
->fname
, flen
);
2078 new->fname
[flen
] = '\0';
2079 strncpy(new->dir
, mp
->dname
, dlen
);
2080 new->dir
[dlen
] = '\0';
2081 new->size
[0] = '\0';
2083 strncpy(new->size
, cell
->size
, sizeof(new->size
));
2084 new->size
[sizeof(new->size
)-1] = '\0';
2094 * Deletes a name from the lmlist
2097 del_cell_from_lmlist(struct fcell
*cell
, struct bmaster
*mp
)
2099 LMLIST
*lm
, *lmprev
= NULL
;
2101 if(mp
&& cell
&& cell
->fname
&& cell
->fname
[0])
2102 for(lm
= mp
? mp
->lm
: NULL
; lm
; lm
= lm
->next
){
2103 if(lm
->fname
&& strcmp(cell
->fname
, lm
->fname
) == 0){
2104 free((char *) lm
->fname
);
2106 free((char *) lm
->dir
);
2109 lmprev
->next
= lm
->next
;
2124 * PaintCell - print the given cell at the given location on the display
2125 * the format of a printed cell is:
2130 PaintCell(int row
, int col
,
2131 int sc
, /* screen columns available for this cell */
2132 struct fcell
*cell
, int inverted
)
2134 char buf1
[NLINE
], buf2
[NLINE
];
2136 int need
, l_wid
, f_wid
, f_to_s_wid
, s_wid
;
2142 l_wid
= (gmp
&& ((gmp
->flags
& FB_LMODEPOS
) > 4)) ? 4 : 0;
2143 f_wid
= utf8_width(cell
->fname
? cell
->fname
: "");
2145 s_wid
= utf8_width(cell
->size
? cell
->size
: "");
2147 /* the two is the space between cell columns */
2148 sc
= MIN(sc
-2, term
.t_ncol
-col
);
2151 if(gmp
&& gmp
->flags
& FB_LMODE
&& cell
->mode
!= FIODIR
){
2153 * We have to figure out here if it is selected or not
2154 * and use that to write the X or space.
2157 if(fcell_is_selected(cell
, gmp
))
2166 lbuf
[0] = lbuf
[1] = lbuf
[2] = lbuf
[3] = ' ';
2174 need
= f_wid
+f_to_s_wid
+s_wid
;
2176 /* space between name and size */
2178 f_to_s_wid
+= (sc
-need
);
2181 * If the width isn't enough to handle everything we're just putting a single
2182 * space between fname and size and truncating on the right. That means that
2183 * the sizes in the right hand column won't line up correctly when there is
2184 * a lack of space. Instead, we opt for displaying as much info as possible
2185 * in a slightly discordant way.
2188 movecursor(row
, col
);
2190 ucs
= utf8_to_ucs4_cpystr(lbuf
);
2193 fs_give((void **) &ucs
);
2197 utf8_snprintf(buf1
, sizeof(buf1
), "%*.*w%*.*w%*.*w",
2198 f_wid
, f_wid
, cell
->fname
? cell
->fname
: "",
2199 f_to_s_wid
, f_to_s_wid
, "",
2200 s_wid
, s_wid
, cell
->size
? cell
->size
: "");
2202 utf8_snprintf(buf2
, sizeof(buf2
), "%*.*w", sc
, sc
, buf1
);
2206 else if (*term
.t_eri
)
2209 ucs
= utf8_to_ucs4_cpystr(buf2
);
2212 fs_give((void **) &ucs
);
2221 * PaintBrowse - with the current data, display the browser. if level == 0
2222 * paint the whole thing, if level == 1 just paint the cells
2226 PaintBrowser(struct bmaster
*mp
, int level
, int *row
, int *col
)
2232 ClearBrowserScreen();
2233 BrowserAnchor(mp
->dname
);
2238 cl
= COMPOSER_TOP_LINE
; /* current display line */
2241 PaintCell(cl
, mp
->cpf
* i
, mp
->cpf
, tp
, tp
== mp
->current
);
2243 if(tp
== mp
->current
){
2253 if(++cl
> term
.t_nrow
-(term
.t_mrow
+1))
2261 while(cl
<= term
.t_nrow
- (term
.t_mrow
+1)){
2265 movecursor(++cl
, 0);
2274 * RepaintBrowser - factorized method to just repaint everything
2277 RepaintBrowser(struct bmaster
*gmp
, int fb_flags
)
2283 fn
= gmp
->current
->fname
;
2285 if((mp
= getfcells(gmp
->dname
, fb_flags
)) == NULL
){
2286 /* getfcells should explain what happened */
2294 if((tp
= FindCell(gmp
, fn
, 0)) != NULL
){
2296 PlaceCell(gmp
, gmp
->current
, &row
, &col
);
2300 PaintBrowser(gmp
, 0, NULL
, NULL
);
2306 * BrowserKeys - just paints the keyhelp at the bottom of the display
2311 if (gmp
&& gmp
->menu
== 1){
2312 menu_other
[GOTO_KEY
].name
= (gmode
&MDGOTO
) ? "G" : NULL
;
2313 menu_other
[GOTO_KEY
].label
= (gmode
&MDGOTO
) ? N_("Goto") : NULL
;
2314 wkeyhelp(menu_other
);
2317 menu_browse
[QUIT_KEY
].name
= (gmode
&MDBRONLY
) ? "Q" : "E";
2318 /* TRANSLATORS: Brwsr is an abbreviation for Browser, which is
2319 a command used to look through something */
2320 menu_browse
[QUIT_KEY
].label
= (gmode
&MDBRONLY
) ? N_("Quit") : N_("Exit Brwsr");
2321 if(gmode
& MDBRONLY
){
2322 menu_browse
[EXEC_KEY
].name
= "L";
2323 menu_browse
[EXEC_KEY
].label
= N_("Launch");
2324 menu_browse
[SELECT_KEY
].name
= "V";
2325 menu_browse
[SELECT_KEY
].label
= "[" N_("View") "]";
2326 menu_browse
[PICO_KEY
].name
= "E";
2327 menu_browse
[PICO_KEY
].label
= N_("Edit");
2330 menu_browse
[SELECT_KEY
].name
= "S";
2331 menu_browse
[SELECT_KEY
].label
= "[" N_("Select") "]";
2332 menu_browse
[PICO_KEY
].name
= "A";
2333 menu_browse
[PICO_KEY
].label
= N_("Add");
2335 if(gmp
&& gmp
->flags
& FB_LMODEPOS
){
2336 if(gmp
&& gmp
->flags
& FB_LMODE
){ /* ListMode is already on */
2337 menu_browse
[EXEC_KEY
].name
= "X";
2338 menu_browse
[EXEC_KEY
].label
= N_("Set/Unset");
2340 else{ /* ListMode is possible */
2341 menu_browse
[EXEC_KEY
].name
= "L";
2342 menu_browse
[EXEC_KEY
].label
= N_("ListMode");
2345 else{ /* No ListMode possible */
2346 menu_browse
[EXEC_KEY
].name
= NULL
;
2347 menu_browse
[EXEC_KEY
].label
= NULL
;
2351 wkeyhelp(menu_browse
);
2356 * layoutcells - figure out max length of cell and how many cells can
2357 * go on a line of the display
2360 layoutcells(struct bmaster
*mp
)
2362 static int wid
= -1;
2364 * Max chars/file. Actually this is max screen cells/file
2365 * Longest name + "(parent dir)"
2368 wid
= MAX(utf8_width(PARENTDIR
),utf8_width(SELECTWORD
)) + utf8_width(DIRWORD
);
2370 mp
->cpf
= mp
->longest
+ wid
+ 3;
2372 if(mp
->flags
& FB_LMODEPOS
) /* "[X] " */
2375 if(gmode
& MDONECOL
){
2381 while(i
*mp
->cpf
- 2 <= term
.t_ncol
) /* no force... */
2382 i
++; /* like brute force! */
2384 mp
->fpl
= i
- 1; /* files per line */
2393 * percdircells - bubble all the directory cells to the top of the
2397 percdircells(struct bmaster
*mp
)
2399 struct fcell
*dirlp
, /* dir cell list pointer */
2400 *lp
, *nlp
; /* cell list ptr and next */
2403 for(lp
= mp
->head
; lp
; lp
= nlp
){
2405 if(lp
->mode
== FIODIR
){
2406 if(lp
->prev
) /* clip from list */
2407 lp
->prev
->next
= lp
->next
;
2410 lp
->next
->prev
= lp
->prev
;
2412 if((lp
->prev
= dirlp
) != NULL
){ /* tie it into dir portion */
2413 if((lp
->next
= dirlp
->next
) != NULL
)
2414 lp
->next
->prev
= lp
;
2420 if((dirlp
= lp
) != mp
->head
)
2421 dirlp
->next
= mp
->head
;
2424 dirlp
->next
->prev
= dirlp
;
2426 mp
->head
= mp
->top
= mp
->current
= dirlp
;
2434 * PlaceCell - given a browser master and a cell, return row and col of the display that
2437 * return 1 if mp->top has changed, x,y relative to new page
2438 * return 0 if otherwise (same page)
2439 * return -1 on error
2442 PlaceCell(struct bmaster
*mp
, struct fcell
*cp
, int *x
, int *y
)
2444 int cl
= COMPOSER_TOP_LINE
; /* current line */
2445 int ci
= 0; /* current index on line */
2450 /* will cp fit on screen? */
2453 if(tp
== cp
){ /* bingo! */
2459 if((tp
= tp
->next
) == NULL
){ /* above top? */
2461 emlwwrite(_("Internal error: can't find fname cell"), NULL
);
2465 tp
= mp
->top
= mp
->head
; /* try from the top! */
2466 cl
= COMPOSER_TOP_LINE
;
2469 continue; /* start over! */
2473 if(++ci
>= mp
->fpl
){ /* next line? */
2475 if(++cl
> term
.t_nrow
-(term
.t_mrow
+1)){ /* next page? */
2476 ci
= mp
->fpl
; /* tp is at bottom right */
2477 while(ci
--) /* find new top */
2481 cl
= COMPOSER_TOP_LINE
; /* keep checking */
2488 /* not on display! */
2494 * zotfcells - clean up malloc'd cells of file names
2497 zotfcells(struct fcell
*hp
)
2511 * zotmaster - blast the browser master struct
2514 zotmaster(struct bmaster
**mp
)
2517 zotfcells((*mp
)->head
); /* free cells */
2518 zotlmlist((*mp
)->lm
); /* free lmlist */
2520 free((char *)(*mp
)->names
); /* free file names */
2522 free((char *)*mp
); /* free master */
2523 *mp
= NULL
; /* make double sure */
2529 * FindCell - starting from the current cell find the first occurance of
2530 * the given string wrapping around if necessary
2533 FindCell(struct bmaster
*mp
, char *utf8string
, int bsearch
)
2535 struct fcell
*tp
, *fp
;
2537 if(*utf8string
== '\0')
2541 tp
= bsearch
? mp
->current
->prev
: mp
->current
->next
;
2544 if(sisin(tp
->fname
, utf8string
))
2547 tp
= bsearch
? tp
->prev
: tp
->next
;
2550 tp
= bsearch
? mp
->bottom
: mp
->head
;
2551 while(tp
!= mp
->current
&& !fp
){
2552 if(sisin(tp
->fname
, utf8string
))
2555 tp
= bsearch
? tp
->prev
: tp
->next
;
2563 * sisin - case insensitive substring matching function
2565 * We can't really do case-insensitive for non-ascii, so restrict
2566 * that to ascii characters. The strings will be utf8.
2569 sisin(char *bigstr
, char *utf8substr
)
2575 while(bigstr
[j
] == utf8substr
[j
]
2576 || ((unsigned char)bigstr
[j
] < 0x80 && (unsigned char)utf8substr
[j
] < 0x80
2577 && toupper((unsigned char)bigstr
[j
]) == toupper((unsigned char)utf8substr
[j
])))
2578 if(utf8substr
[++j
] == '\0') /* bingo! */
2589 * set_browser_title -
2592 set_browser_title(char *s
)
2599 * BrowserAnchor - draw the browser's anchor line.
2602 BrowserAnchor(char *utf8dir
)
2605 char titlebuf
[NLINE
];
2609 char *br
= "BROWSER";
2610 char *dir
= "Dir: ";
2612 int need
, extra
, avail
;
2613 int title_wid
, b_wid
, t_to_b_wid
, b_to_d_wid
, d_wid
, dot_wid
, dir_wid
, after_dir_wid
;
2614 COLOR_PAIR
*lastc
= NULL
;
2622 snprintf(titlebuf
, sizeof(buf
), " %s", browser_title
);
2624 snprintf(titlebuf
, sizeof(buf
), " ALPINE %s", Pmaster
->pine_version
);
2626 snprintf(titlebuf
, sizeof(buf
), " UW PICO %s", (gmode
&MDBRONLY
) ? "BROWSER" : version
);
2628 title_wid
= utf8_width(titlebuf
);
2630 b_wid
= utf8_width(br
);
2632 d_wid
= utf8_width(dir
);
2634 dir_wid
= utf8_width(pdir
);
2636 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2638 if(need
> term
.t_ncol
){
2639 extra
= need
- term
.t_ncol
;
2640 t_to_b_wid
-= MIN(extra
, 10);
2641 need
-= MIN(extra
, 10);
2643 if(need
> term
.t_ncol
){
2644 extra
= need
- term
.t_ncol
;
2645 b_to_d_wid
-= MIN(extra
, 2);
2646 need
-= MIN(extra
, 2);
2649 if(need
> term
.t_ncol
){
2650 titlebuf
[0] = titlebuf
[1] = ' ';
2652 title_wid
= utf8_width(titlebuf
);
2655 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2656 if(need
> term
.t_ncol
){
2657 extra
= need
- term
.t_ncol
;
2658 b_to_d_wid
-= MIN(extra
, 2);
2659 need
-= MIN(extra
, 2);
2662 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2663 if(need
> term
.t_ncol
){
2669 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2670 if(need
> term
.t_ncol
)
2673 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2675 if(need
> term
.t_ncol
&& dir_wid
> 0){
2676 dot_wid
= utf8_width(dots
);
2677 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2678 while(need
> term
.t_ncol
&& (pdir
= strchr(pdir
+1, C_FILESEP
))){
2679 dir_wid
= utf8_width(pdir
);
2680 need
= title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
;
2683 if(!pdir
){ /* adjust other widths to fill up space */
2684 avail
= term
.t_ncol
- (title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
);
2686 utf8_to_width_rhs(dirbuf
, utf8dir
, sizeof(dirbuf
), avail
);
2693 dir_wid
= utf8_width(pdir
);
2698 extra
= term
.t_ncol
- (title_wid
+t_to_b_wid
+b_wid
+b_to_d_wid
+d_wid
+dot_wid
+dir_wid
);
2701 after_dir_wid
= extra
;
2705 utf8_snprintf(buf
, sizeof(buf
), "%*.*w%*.*w%*.*w%*.*w%*.*w%*.*w%*.*w%*.*w",
2706 title_wid
, title_wid
, titlebuf
,
2707 t_to_b_wid
, t_to_b_wid
, "",
2709 b_to_d_wid
, b_to_d_wid
, "",
2711 dot_wid
, dot_wid
, dots
,
2712 dir_wid
, dir_wid
, pdir
,
2713 after_dir_wid
, after_dir_wid
, "");
2715 /* just making sure */
2716 utf8_snprintf(titlebuf
, sizeof(titlebuf
), "%-*.*w", term
.t_ncol
, term
.t_ncol
, buf
);
2719 if(Pmaster
&& Pmaster
->colors
&& Pmaster
->colors
->tbcp
2720 && pico_is_good_colorpair(Pmaster
->colors
->tbcp
)){
2721 lastc
= pico_get_cur_color();
2722 (void) pico_set_colorp(Pmaster
->colors
->tbcp
, PSC_NONE
);
2727 ucs
= utf8_to_ucs4_cpystr(titlebuf
);
2730 fs_give((void **) &ucs
);
2734 (void) pico_set_colorp(lastc
, PSC_NONE
);
2735 free_color_pair(&lastc
);
2743 * ResizeBrowser - handle a resize event
2750 PaintBrowser(gmp
, 0, NULL
, NULL
);
2759 ClearBrowserScreen(void)
2763 for(i
= 0; i
<= term
.t_nrow
; i
++){ /* clear screen */
2771 BrowserRunChild(char *child
, char *dir
)
2777 ClearBrowserScreen();
2780 if(!isdir(dir
, NULL
, &t_in
))
2784 status
= system(child
);
2786 if(t_in
&& isdir(dir
, NULL
, &t_out
) && t_in
< t_out
){
2789 if((mp
= getfcells(dir
, 0)) != NULL
){
2793 /* else getfcells should explain what happened */
2796 /* complain about non-zero exit status */
2797 if((status
>> 8) & 0xff){
2799 movecursor(term
.t_nrow
- 1, 0);
2800 snprintf(tmp
, sizeof(tmp
), "[ \"%.30s\" exit with error value: %d ]",
2801 child
, (status
>> 8) & 0xff);
2803 movecursor(term
.t_nrow
, 0);
2804 pputs_utf8("[ Hit RETURN to continue ]", 1);
2807 while(GetKey() != (CTRL
|'M')){
2816 * imitate pc-pine memory for where we last called the file browser.
2819 p_chdir(struct bmaster
*mp
)
2824 #else /* _WINDOWS */
2828 * pico_file_browse - Exported version of FileBrowse below.
2831 pico_file_browse(PICO
*pdata
, char *dir
, size_t dirlen
, char *fn
, size_t fnlen
,
2832 char *sz
, size_t szlen
, int flags
)
2834 return(FileBrowse(dir
, dirlen
, fn
, fnlen
, sz
, szlen
, flags
, NULL
));
2838 ResizeBrowser (void)
2844 * FileBrowse - Windows version of above function
2847 FileBrowse(char *dir
, size_t dirlen
, char *fn
, size_t fnlen
,
2848 char *sz
, size_t szlen
, int fb_flags
, LMLIST
**lmreturn
)
2854 if (fb_flags
& FB_SAVE
){
2855 rc
= mswin_savefile(dir
, dirlen
, fn
, MIN(dirlen
,fnlen
));
2858 *fn
= '\0'; /* No initial file names for
2860 if(fb_flags
& FB_LMODEPOS
){
2862 * We're going to allow multiple filenames to be returned so
2863 * we don't want to use the passed in fn for that. Instead, make
2864 * a bigger space and use that.
2869 memset(f
, 0, sizeof(f
));
2871 rc
= mswin_multopenfile(dir
, dirlen
, f
, sizeof(f
),
2872 (fb_flags
& FB_ATTACH
) ? NULL
: "Text Files (*.txt)#*.txt");
2875 LMLIST
*lmhead
= NULL
, *new;
2879 * Build an LMLIST to return to the caller.
2881 for(p
= f
; *p
; p
+= strlen(p
)+1){
2883 dlen
= strlen(dir
? dir
: "");
2884 new = (LMLIST
*) fs_get(sizeof(*new));
2885 new->fname
= (char *) fs_get((flen
+1) * sizeof(char));
2886 new->dir
= (char *) fs_get((dlen
+1) * sizeof(char));
2888 strncpy(new->fname
, p
, flen
);
2889 new->fname
[flen
] = '\0';
2890 strncpy(new->dir
, dir
? dir
: "", dlen
);
2891 new->dir
[dlen
] = '\0';
2893 /* build full path to stat file. */
2894 if((strlen(new->dir
) + strlen(S_FILESEP
) +
2895 strlen(new->fname
) + 1) < sizeof(lfn
)){
2896 strncpy(lfn
, new->dir
, sizeof(lfn
));
2897 lfn
[sizeof(lfn
)-1] = '\0';
2898 strncat(lfn
, S_FILESEP
, sizeof(lfn
)-strlen(lfn
)-1);
2899 strncat(lfn
, new->fname
, sizeof(lfn
)-strlen(lfn
)-1);
2900 lfn
[sizeof(lfn
)-1] = '\0';
2901 if(our_stat(lfn
, &sbuf
) < 0)
2902 strncpy(new->size
, "0", 32);
2904 strncpy(new->size
, prettysz((off_t
)sbuf
.st_size
), 32);
2906 new->size
[32-1] = '\0';
2918 rc
= mswin_openfile (dir
, dirlen
, fn
, fnlen
,
2919 (fb_flags
& FB_ATTACH
) ? NULL
: "Text Files (*.txt)#*.txt");
2924 /* build full path to stat file. */
2925 if((strlen(dir
) + strlen(S_FILESEP
) + strlen(fn
) + 1) > NLINE
)
2928 strncpy(lfn
, dir
, sizeof(lfn
));
2929 lfn
[sizeof(lfn
)-1] = '\0';
2930 strncat(lfn
, S_FILESEP
, sizeof(lfn
)-strlen(lfn
)-1);
2931 lfn
[sizeof(lfn
)-1] = '\0';
2932 strncat(lfn
, fn
, sizeof(lfn
)-strlen(lfn
)-1);
2933 lfn
[sizeof(lfn
)-1] = '\0';
2934 if(our_stat(lfn
, &sbuf
) < 0){
2935 strncpy(sz
, "0", szlen
);
2939 strncpy(sz
, prettysz ((off_t
)sbuf
.st_size
), szlen
);
2947 return(rc
? -1 : 0);
2950 #endif /* _WINDOWS */
2954 * LikelyASCII - make a rough guess as to the displayability of the
2958 LikelyASCII(char *file
)
2960 #define LA_TEST_BUF 1024
2961 #define LA_LINE_LIMIT 300
2962 int n
, i
, line
, rv
= FALSE
;
2963 unsigned char buf
[LA_TEST_BUF
];
2967 if((fp
= our_fopen(file
, "rb")) != NULL
){
2969 if((n
= fread(buf
, sizeof(char), LA_TEST_BUF
* sizeof(char), fp
)) > 0
2972 * If we don't hit any newlines in a reasonable number,
2973 * LA_LINE_LIMIT, of characters or the file contains NULLs,
2977 for(i
= line
= 0; i
< n
; i
++)
2978 if((line
= (buf
[i
] == '\n') ? 0 : line
+ 1) >= LA_LINE_LIMIT
2981 emlwrite(_("Can't display non-text file. Try \"Launch\"."),
2988 emlwrite(_("Can't read file: %s"), &eml
);
2995 emlwrite(_("Can't open file: %s"), &eml
);
3003 zotlmlist(LMLIST
*lm
)
3023 * time_to_check - checks the current time against the last time called
3024 * and returns true if the elapsed time is > below.
3025 * Newmail won't necessarily check, but we want to give it
3026 * a chance to check or do a keepalive.
3031 static time_t lasttime
= 0L;
3033 if(!get_input_timeout())
3036 if(time((time_t *) 0) - lasttime
> (Pmaster
? (time_t)(FUDGE
-10) : get_input_timeout())){
3037 lasttime
= time((time_t *) 0);