2 * ========================================================================
3 * Copyright 2013-2021 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*======================================================================
18 Screen to display and manage all the users folders
20 This puts up a list of all the folders in the users mail directory on
21 the screen spacing it nicely. The arrow keys move from one to another
22 and the user can delete the folder or select it to change to or copy a
23 message to. The display lets the user scroll up or down a screen full,
24 or search for a folder name.
29 #include "../c-client/utf8aux.h"
45 #include "../pith/state.h"
46 #include "../pith/conf.h"
47 #include "../pith/folder.h"
48 #include "../pith/flag.h"
49 #include "../pith/filter.h"
50 #include "../pith/msgno.h"
51 #include "../pith/thread.h"
52 #include "../pith/util.h"
53 #include "../pith/stream.h"
54 #include "../pith/save.h"
55 #include "../pith/busy.h"
56 #include "../pith/list.h"
59 #define SUBSCRIBE_PMT \
60 _("Enter newsgroup name (or partial name to get a list): ")
61 #define LISTMODE_GRIPE _("Use \"X\" to mark selections in list mode")
62 #define SEL_ALTER_PMT _("ALTER folder selection : ")
63 #define SEL_TEXT_PMT _("Select by folder Name or Contents ? ")
64 #define SEL_PROP_PMT _("Select by which folder property ? ")
65 #define DIR_FOLD_PMT \
66 _("Folder and directory of the same name will be deleted. Continue")
73 #define FLW_LUNK 0x01 /* Using handles */
74 #define FLW_SLCT 0x02 /* Some folder is selected, may need X to show it */
75 #define FLW_LIST 0x04 /* Allow for ListMode for subscribing */
76 #define FLW_UNSEEN 0x08 /* Add (unseen) */
79 #define CLR_UNSEEN 0x01 /* color folder with unseen/new messages */
80 #define CLR_FOLDER 0x02 /* color a name of folder or directory */
81 #define CLR_DIRECT 0x04 /* color a separator of a directory */
82 #define CLR_FLDRLT 0x08 /* color of explanatory text in list scrn*/
83 #define CLR_NORMAL 0x10 /* use normal color */
85 /*----------------------------------------------------------------------
86 The data needed to redraw the folders screen, including the case where the
87 screen changes size in which case it may recalculate the folder_display.
92 * Struct managing folder_lister arguments and holding state
93 * for various internal methods
95 typedef struct _folder_screen
{
96 CONTEXT_S
*context
; /* current collection */
97 CONTEXT_S
*list_cntxt
; /* list mode collection */
98 MAILSTREAM
**cache_streamp
; /* cached mailstream */
99 char first_folder
[MAXFOLDER
];
100 unsigned first_dir
:1; /* first_folder is a dir */
101 unsigned combined_view
:1; /* display flat folder list */
102 unsigned no_dirs
:1; /* no dirs in this screen */
103 unsigned no_empty_dirs
:1; /* no empty dirs on this screen */
104 unsigned relative_path
:1; /* return fully-qual'd specs */
106 unsigned force_intro
:1;
108 unsigned include_unseen_cnt
:1;
109 struct key_menu
*km
; /* key label/command bindings */
110 struct _func_dispatch
{
111 int (*valid
)(FOLDER_S
*, struct _folder_screen
*);
125 * Struct managing folder_lister metadata as it gets passed
126 * in and back up thru scrolltool
128 typedef struct _folder_proc
{
131 unsigned done
:1; /* done listing folders?... */
132 unsigned all_done
:1; /* ...and will list no more forever */
135 #define FPROC(X) ((FPROC_S *)(X)->proc.data.p)
138 typedef struct _scanarg
{
147 typedef struct _statarg
{
158 * Internal prototypes
160 STRLIST_S
*folders_for_subscribe(struct pine
*, CONTEXT_S
*, char *);
161 int folders_for_post(struct pine
*, CONTEXT_S
**, char *);
162 int folder_selector(struct pine
*, FSTATE_S
*, char *, CONTEXT_S
**);
163 void folder_sublist_context(char *, CONTEXT_S
*, CONTEXT_S
*, FDIR_S
**, int);
164 CONTEXT_S
*context_screen(CONTEXT_S
*, struct key_menu
*, int);
165 int exit_collection_add(struct headerentry
*, void (*)(void), int, char **);
166 char *cancel_collection_add(void (*)(void));
167 char *cancel_collection_edit(void (*)(void));
168 char *cancel_collection_editing(char *, void (*)(void));
169 int build_namespace(char *, char **, char **, BUILDER_ARG
*, int *);
170 int fl_val_gen(FOLDER_S
*, FSTATE_S
*);
171 int fl_val_writable(FOLDER_S
*, FSTATE_S
*);
172 int fl_val_subscribe(FOLDER_S
*, FSTATE_S
*);
173 STRLIST_S
*folder_lister(struct pine
*, FSTATE_S
*);
174 int folder_list_text(struct pine
*, FPROC_S
*, gf_io_t
, HANDLE_S
**, int);
175 int folder_list_write(gf_io_t
, HANDLE_S
**, CONTEXT_S
*, int, char *, int);
176 int folder_list_write_prefix(FOLDER_S
*, int, gf_io_t
);
177 int folder_list_write_middle(FOLDER_S
*fp
, CONTEXT_S
*ctxt
, gf_io_t pc
, HANDLE_S
*);
178 int folder_list_write_suffix(FOLDER_S
*, int, gf_io_t
);
179 int color_monitored(FOLDER_S
*, int, int);
180 int color_test_for_folder(char *, char *);
181 int color_write_for_folder(gf_io_t pc
, int testtype
);
182 int use_color_for_folder(FOLDER_S
*fp
);
183 int folder_list_ith(int, CONTEXT_S
*);
184 char *folder_list_center_space(char *, int);
185 HANDLE_S
*folder_list_handle(FSTATE_S
*, HANDLE_S
*);
186 int folder_processor(int, MSGNO_S
*, SCROLL_S
*);
187 int folder_lister_clickclick(SCROLL_S
*);
188 int folder_lister_choice(SCROLL_S
*);
189 int folder_lister_finish(SCROLL_S
*, CONTEXT_S
*, int);
190 int folder_lister_addmanually(SCROLL_S
*);
191 void folder_lister_km_manager(SCROLL_S
*, int);
192 void folder_lister_km_sel_manager(SCROLL_S
*, int);
193 void folder_lister_km_sub_manager(SCROLL_S
*, int);
194 int folder_select(struct pine
*, CONTEXT_S
*, int);
195 int folder_lister_select(FSTATE_S
*, CONTEXT_S
*, int, int);
196 int folder_lister_parent(FSTATE_S
*, CONTEXT_S
*, int, int);
197 char *folder_lister_fullname(FSTATE_S
*, char *);
198 void folder_export(SCROLL_S
*);
199 int folder_import(SCROLL_S
*, char *, size_t);
200 int folder_select_toggle(CONTEXT_S
*, int, int (*)(CONTEXT_S
*, int));
201 char *end_bracket_no_nest(char *);
202 int group_subscription(char *, size_t, CONTEXT_S
*);
203 int rename_folder(CONTEXT_S
*, int, char *, size_t, MAILSTREAM
*);
204 int delete_folder(CONTEXT_S
*, int, char *, size_t, MAILSTREAM
**);
205 void print_folders(FPROC_S
*);
206 int scan_get_pattern(char *, char *, int);
207 int folder_select_text(struct pine
*, CONTEXT_S
*, int);
208 int foreach_do_scan(FOLDER_S
*, void *);
209 int scan_scan_folder(MAILSTREAM
*, CONTEXT_S
*, FOLDER_S
*, char *);
210 int folder_select_props(struct pine
*, CONTEXT_S
*, int);
211 int folder_select_count(long *, int *);
212 int foreach_do_stat(FOLDER_S
*, void *);
213 int foreach_folder(CONTEXT_S
*, int, int (*)(FOLDER_S
*, void *), void *);
214 int folder_delimiter(char *);
215 int shuffle_incoming_folders(CONTEXT_S
*, int);
216 int swap_incoming_folders(int, int, FLIST
*);
217 int search_folder_list(void *, char *);
218 char *get_post_list(char **);
219 char *quote_brackets_if_needed(char *);
221 int folder_list_popup(SCROLL_S
*, int);
222 int folder_list_select_popup(SCROLL_S
*, int);
223 void folder_popup_config(FSTATE_S
*, struct key_menu
*,MPopup
*);
227 /*----------------------------------------------------------------------
228 Front end to folder lister when it's called from the main menu
230 Args: ps -- The general pine_state data structure
232 Result: runs context and folder listers
236 folder_screen(struct pine
*ps
)
239 CONTEXT_S
*cntxt
= ps
->context_current
;
242 MAILSTREAM
*cache_stream
= NULL
;
244 dprint((1, "=== folder_screen called ====\n"));
245 mailcap_free(); /* free resources we won't be using for a while */
246 ps
->next_screen
= SCREEN_FUN_NULL
;
248 /* Initialize folder state and dispatches */
249 memset(&fs
, 0, sizeof(FSTATE_S
));
251 fs
.cache_streamp
= &cache_stream
;
252 fs
.combined_view
= F_ON(F_CMBND_FOLDER_DISP
, ps_global
) != 0;
253 fs
.agg_ops
= F_ON(F_ENABLE_AGG_OPS
, ps_global
) != 0;
254 fs
.relative_path
= 1;
255 fs
.include_unseen_cnt
= 1;
256 fs
.f
.valid
= fl_val_gen
;
257 /* TRANSLATORS: The all upper case things are screen titles */
258 fs
.f
.title
.bar
= _("FOLDER LIST");
259 fs
.f
.title
.style
= FolderName
;
260 fs
.f
.help
.text
= h_folder_maint
;
261 fs
.f
.help
.title
= _("HELP FOR FOLDERS");
264 if(context_isambig(ps
->cur_folder
)
265 && (IS_REMOTE(ps
->cur_folder
) || !is_absolute_path(ps
->cur_folder
)
266 || (cntxt
&& cntxt
->context
&& cntxt
->context
[0] == '{'))){
267 if(strlen(ps_global
->cur_folder
) < MAXFOLDER
- 1){
268 strncpy(fs
.first_folder
, ps_global
->cur_folder
, MAXFOLDER
);
269 fs
.first_folder
[MAXFOLDER
-1] = '\0';
273 * If we're asked to start in the folder list of the current
274 * folder and it looks like the current folder is part of the
275 * current context, try to start in the list of folders in the
278 if(ps
->start_in_context
|| fs
.combined_view
){
279 char tmp
[MAILTMPLEN
], *p
, *q
;
282 ps
->start_in_context
= 0;
285 if(!(NEWS_TEST(cntxt
) || (cntxt
->use
& CNTXT_INCMNG
))
287 && strchr(ps
->cur_folder
, cntxt
->dir
->delim
)){
288 for(p
= strchr(q
= ps
->cur_folder
, cntxt
->dir
->delim
);
290 p
= strchr(q
= ++p
, cntxt
->dir
->delim
)){
291 strncpy(tmp
, q
, MIN(p
- q
, sizeof(tmp
)-1));
292 tmp
[MIN(p
- q
, sizeof(tmp
)-1)] = '\0';
294 fp
= next_folder_dir(cntxt
, tmp
, FALSE
, fs
.cache_streamp
);
296 fp
->desc
= folder_lister_desc(cntxt
, fp
);
298 /* Insert new directory into list */
299 fp
->delim
= cntxt
->dir
->delim
;
300 fp
->prev
= cntxt
->dir
;
301 fp
->status
|= CNTXT_SUBDIR
;
308 while(ps
->next_screen
== SCREEN_FUN_NULL
309 && ((n
++) ? (cntxt
= context_screen(cntxt
,&c_mgr_km
,1)) != NULL
:1)){
312 if(F_ON(F_ENABLE_INCOMING_CHECKING
, ps
) && ps
->VAR_INCOMING_FOLDERS
&& ps
->VAR_INCOMING_FOLDERS
[0])
313 ps
->in_folder_screen
= 1;
315 if((folders
= folder_lister(ps
, &fs
)) != NULL
){
317 ps
->in_folder_screen
= 0;
320 blank_keymenu(ps
->ttyo
->screen_rows
- 2, 0);
321 ps
->mangled_footer
= 1;
324 if(do_broach_folder((char *) folders
->name
,
325 fs
.context
, fs
.cache_streamp
326 && *fs
.cache_streamp
? fs
.cache_streamp
328 reset_context_folders(ps
->context_list
);
329 ps
->next_screen
= mail_index_screen
;
333 *fs
.cache_streamp
= NULL
;
334 free_strlist(&folders
);
337 ps
->in_folder_screen
= 0;
340 if(fs
.cache_streamp
&& *fs
.cache_streamp
)
341 pine_mail_close(*fs
.cache_streamp
);
343 ps
->prev_screen
= folder_screen
;
347 /*----------------------------------------------------------------------
348 Front end to folder lister when it's called from the main menu
350 Args: ps -- The general pine_state data structure
352 Result: runs context and folder listers
356 folder_config_screen(struct pine
*ps
, int edit_exceptions
)
359 char title
[50], htitle
[50];
361 dprint((1, "=== folder_config_screen called ====\n"));
362 mailcap_free(); /* free resources we won't be using for a while */
365 snprintf(title
, sizeof(title
), _("SETUP EXCEPTIONS COLLECTION LIST"));
366 snprintf(htitle
, sizeof(htitle
), _("HELP FOR SETUP EXCEPTIONS COLLECTIONS"));
369 snprintf(title
, sizeof(title
), _("SETUP COLLECTION LIST"));
370 snprintf(htitle
, sizeof(htitle
), _("HELP FOR SETUP COLLECTIONS"));
373 memset(&css
, 0, sizeof(CONT_SCR_S
));
375 /* TRANSLATORS: Print something1 using something2.
376 contexts is something1 */
377 css
.print_string
= _("contexts");
378 css
.contexts
= &ps_global
->context_list
;
379 css
.help
.text
= h_collection_maint
;
380 css
.help
.title
= htitle
;
381 css
.keymenu
= &c_cfg_km
;
385 * Use conf_scroll_screen to manage display/selection
388 context_config_screen(ps_global
, &css
, edit_exceptions
);
392 /*----------------------------------------------------------------------
393 Browse folders for ^T selection from the Goto Prompt
396 cntxtp -- pointer to addr of context to start in, list, and return
397 folder -- pointer to buffer inwhich to return selected folder
399 Returns: 1 if we have something valid in cntxtp and folder
400 0 if problem or user cancelled
404 folders_for_goto(struct pine
*ps
, CONTEXT_S
**cntxtp
, char *folder
, int sublist
)
407 CONTEXT_S fake_context
;
408 FDIR_S
*fake_dir
= NULL
;
411 dprint((1, "=== folders_for_goto called ====\n"));
413 /* Initialize folder state and dispatches */
414 memset(&fs
, 0, sizeof(FSTATE_S
));
415 fs
.context
= *cntxtp
;
416 fs
.combined_view
= !sublist
&& F_ON(F_CMBND_FOLDER_DISP
, ps_global
) != 0;
417 fs
.f
.valid
= fl_val_gen
;
418 fs
.f
.title
.bar
= _("GOTO: SELECT FOLDER");
419 fs
.f
.title
.style
= FolderName
;
420 fs
.f
.help
.text
= h_folder_open
;
421 fs
.f
.help
.title
= _("HELP FOR OPENING FOLDERS");
422 fs
.km
= &folder_sel_km
;
424 /* If we were provided a string,
425 * dummy up a context for a substring match
427 if(sublist
&& *folder
&& context_isambig(folder
)){
428 if((*cntxtp
)->use
& CNTXT_INCMNG
){
429 q_status_message(SM_ORDER
, 0, 3,
430 _("All folders displayed for Incoming Collection"));
433 folder_sublist_context(folder
, *cntxtp
, &fake_context
,
435 fs
.context
= &fake_context
;
436 fs
.relative_path
= 1;
438 cntxtp
= &fs
.context
;
442 rv
= folder_selector(ps
, &fs
, folder
, cntxtp
);
445 free_fdir(&fake_dir
, TRUE
);
451 /*----------------------------------------------------------------------
452 Browse folders for ^T selection from the Save Prompt
455 cntxtp -- pointer to addr of context to start in, list, and return
456 folder -- pointer to buffer inwhich to return selected folder
458 Returns: 1 if we have something valid in cntxtp and folder
459 0 if problem or user cancelled
463 folders_for_save(struct pine
*ps
, CONTEXT_S
**cntxtp
, char *folder
, int sublist
)
466 CONTEXT_S fake_context
;
467 FDIR_S
*fake_dir
= NULL
;
470 dprint((1, "=== folders_for_save called ====\n"));
472 /* Initialize folder state and dispatches */
473 memset(&fs
, 0, sizeof(FSTATE_S
));
474 fs
.context
= *cntxtp
;
475 fs
.combined_view
= F_ON(F_CMBND_FOLDER_DISP
, ps_global
) != 0;
476 fs
.f
.valid
= fl_val_gen
;
477 fs
.f
.title
.bar
= _("SAVE: SELECT FOLDER");
478 fs
.f
.title
.style
= MessageNumber
;
479 fs
.f
.help
.text
= h_folder_save
;
480 fs
.f
.help
.title
= _("HELP FOR SAVING MESSAGES TO FOLDERS");
481 fs
.km
= &folder_sela_km
;
483 /* If we were provided a string,
484 * dummy up a context for a substring match
486 if(sublist
&& *folder
&& context_isambig(folder
)){
487 if((*cntxtp
)->use
& CNTXT_INCMNG
){
488 q_status_message(SM_ORDER
, 0, 3,
489 _("All folders displayed for Incoming Collection"));
492 folder_sublist_context(folder
, *cntxtp
, &fake_context
,
494 fs
.context
= &fake_context
;
495 fs
.relative_path
= 1;
497 cntxtp
= &fs
.context
;
501 rv
= folder_selector(ps
, &fs
, folder
, cntxtp
);
504 free_fdir(&fake_dir
, TRUE
);
510 /*----------------------------------------------------------------------
511 Browse folders for ^T selection from the Subscribe Prompt
514 cntxtp -- pointer to addr of context to start in, list, and return
515 folder -- pointer to buffer inwhich to return selected folder
517 Returns: 1 if we have something valid in cntxtp and folder
518 0 if problem or user cancelled
522 folders_for_subscribe(struct pine
*ps
, CONTEXT_S
*cntxt
, char *folder
)
524 STRLIST_S
*folders
= NULL
;
526 void (*redraw
)(void);
528 dprint((1, "=== folders_for_sub called ====\n"));
530 /* Initialize folder state and dispatches */
531 memset(&fs
, 0, sizeof(FSTATE_S
));
533 fs
.f
.valid
= fl_val_subscribe
;
534 fs
.f
.title
.bar
= _("SUBSCRIBE: SELECT FOLDER");
535 fs
.f
.title
.style
= FolderName
;
536 fs
.f
.help
.text
= h_folder_subscribe
;
537 fs
.f
.help
.title
= _("HELP SELECTING NEWSGROUP TO SUBSCRIBE TO");
538 fs
.km
= &folder_sub_km
;
542 redraw
= ps_global
->redrawer
;
543 folders
= folder_lister(ps
, &fs
);
544 ps_global
->redrawer
= redraw
;
545 if(ps_global
->redrawer
)
546 (*ps_global
->redrawer
)();
552 /*----------------------------------------------------------------------
553 Browse folders for ^T selection for posting
556 cntxtp -- pointer to addr of context to start in, list, and return
557 folder -- pointer to buffer inwhich to return selected folder
559 Returns: 1 if we have something valid in cntxtp and folder
560 0 if problem or user cancelled
564 folders_for_post(struct pine
*ps
, CONTEXT_S
**cntxtp
, char *folder
)
568 dprint((1, "=== folders_for_post called ====\n"));
570 /* Initialize folder state and dispatches */
571 memset(&fs
, 0, sizeof(FSTATE_S
));
572 fs
.context
= *cntxtp
;
573 fs
.f
.valid
= fl_val_subscribe
;
574 fs
.f
.title
.bar
= _("NEWS: SELECT GROUP");
575 fs
.f
.title
.style
= FolderName
;
576 fs
.f
.help
.text
= h_folder_postnews
;
577 fs
.f
.help
.title
= _("HELP FOR SELECTING NEWSGROUP TO POST TO");
578 fs
.km
= &folder_post_km
;
580 return(folder_selector(ps
, &fs
, folder
, cntxtp
));
585 folder_selector(struct pine
*ps
, FSTATE_S
*fs
, char *folder
, CONTEXT_S
**cntxtp
)
591 fs
->context
= *cntxtp
;
592 if((folders
= folder_lister(ps
, fs
)) != NULL
){
593 strncpy(folder
, (char *) folders
->name
, MAILTMPLEN
-1);
594 folder
[MAILTMPLEN
-1] = '\0';
595 free_strlist(&folders
);
596 *cntxtp
= fs
->context
;
600 else if(!(fs
->context
601 && (fs
->context
->next
|| fs
->context
->prev
))
602 || fs
->combined_view
)
605 while((*cntxtp
= context_screen(*cntxtp
, &c_sel_km
, 0)) != NULL
);
612 folder_sublist_context(char *folder
, CONTEXT_S
*cntxt
, CONTEXT_S
*new_cntxt
, FDIR_S
**new_dir
, int lev
)
614 char *p
, *q
, *ref
, *wildcard
;
617 new_cntxt
->next
= new_cntxt
->prev
= NULL
;
618 new_cntxt
->dir
= *new_dir
= (FDIR_S
*) fs_get(sizeof(FDIR_S
));
619 memset(*new_dir
, 0, sizeof(FDIR_S
));
620 (*new_dir
)->status
|= CNTXT_NOFIND
;
621 (*new_dir
)->folders
= init_folder_entries();
622 if(!((*new_dir
)->delim
= cntxt
->dir
->delim
)){
623 /* simple LIST to acquire delimiter, doh */
624 build_folder_list(NULL
, new_cntxt
, "", NULL
,
625 NEWS_TEST(new_cntxt
) ? BFL_LSUB
: BFL_NONE
);
626 new_cntxt
->dir
->status
= CNTXT_NOFIND
;
629 wildcard
= NEWS_TEST(new_cntxt
) ? "*" : "%";
631 if((p
= strrindex(folder
, (*new_dir
)->delim
)) != NULL
){
632 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s", p
+ 1, wildcard
);
633 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
634 (*new_dir
)->view
.internal
= cpystr(tmp_20k_buf
);
635 for(ref
= tmp_20k_buf
, q
= new_cntxt
->context
;
636 (*ref
= *q
) != '\0' && !(*q
== '%' && *(q
+1) == 's');
640 for(q
= folder
; q
<= p
; q
++, ref
++)
644 (*new_dir
)->ref
= cpystr(tmp_20k_buf
);
646 (*new_dir
)->status
|= CNTXT_SUBDIR
;
649 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s%s%s",
650 (lev
> 1) ? wildcard
: "", folder
, wildcard
);
651 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
652 (*new_dir
)->view
.internal
= cpystr(tmp_20k_buf
);
653 /* leave (*new_dir)->ref == NULL */
656 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("List of folders matching \"%s*\""), folder
);
657 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
658 (*new_dir
)->desc
= cpystr(tmp_20k_buf
);
662 /*----------------------------------------------------------------------
663 Browse folders for ^T selection from the composer
665 Args: error_mess -- pointer to place to return an error message
667 Returns: result if folder selected, NULL if not
668 Composer expects the result to be alloc'd here
672 folders_for_fcc(char **errmsg
)
678 dprint((1, "=== folders_for_fcc called ====\n"));
680 /* Coming back from composer */
681 fix_windsize(ps_global
);
684 /* Initialize folder state and dispatches */
685 memset(&fs
, 0, sizeof(FSTATE_S
));
686 fs
.combined_view
= F_ON(F_CMBND_FOLDER_DISP
, ps_global
) != 0;
687 fs
.f
.valid
= fl_val_gen
;
688 fs
.f
.title
.bar
= _("FCC: SELECT FOLDER");
689 fs
.f
.title
.style
= FolderName
;
690 fs
.f
.help
.text
= h_folder_fcc
;
691 fs
.f
.help
.title
= _("HELP FOR SELECTING THE FCC");
692 fs
.km
= &folder_sela_km
;
694 /* start in the default save context */
695 fs
.context
= default_save_context(ps_global
->context_list
);
698 if((folders
= folder_lister(ps_global
, &fs
)) != NULL
){
701 /* replace nickname with full name */
702 if(!(name
= folder_is_nick((char *) folders
->name
,
703 FOLDERS(fs
.context
), 0)))
704 name
= (char *) folders
->name
;
706 if(context_isambig(name
) && !((fs
.context
->use
) & CNTXT_SAVEDFLT
)){
707 char path_in_context
[MAILTMPLEN
];
709 context_apply(path_in_context
, fs
.context
, name
,
710 sizeof(path_in_context
));
711 if(!(IS_REMOTE(path_in_context
)
712 || is_absolute_path(path_in_context
))){
714 * Name is relative to the home directory,
715 * so have to add that. Otherwise, the sender will
716 * assume it is in the primary collection since it
717 * will still be ambiguous.
719 build_path(tmp_20k_buf
, ps_global
->ui
.homedir
,
720 path_in_context
, SIZEOF_20KBUF
);
721 rs
= cpystr(tmp_20k_buf
);
724 rs
= cpystr(path_in_context
);
729 free_strlist(&folders
);
732 else if(!(fs
.context
&& (fs
.context
->next
|| fs
.context
->prev
))
736 while((fs
.context
= context_screen(fs
.context
, &c_fcc_km
, 0)) != NULL
);
742 /*----------------------------------------------------------------------
743 Browse folders for ^T selection from the role editor
745 Returns: result if folder selected, NULL if not
746 Tesult is alloc'd here
750 folder_for_config(int flags
)
756 dprint((1, "=== folder_for_config called ====\n"));
758 /* Initialize folder state and dispatches */
759 memset(&fs
, 0, sizeof(FSTATE_S
));
760 fs
.combined_view
= F_ON(F_CMBND_FOLDER_DISP
, ps_global
) != 0;
761 fs
.f
.valid
= fl_val_gen
;
762 fs
.f
.title
.bar
= _("SELECT FOLDER");
763 fs
.f
.title
.style
= FolderName
;
764 fs
.km
= &folder_sela_km
;
765 if(flags
& FOR_PATTERN
){
766 fs
.f
.help
.text
= h_folder_pattern_roles
;
767 fs
.f
.help
.title
= _("HELP FOR SELECTING CURRENT FOLDER");
769 else if(flags
& FOR_OPTIONSCREEN
){
770 fs
.f
.help
.text
= h_folder_stayopen_folders
;
771 fs
.f
.help
.title
= _("HELP FOR SELECTING FOLDER");
774 fs
.f
.help
.text
= h_folder_action_roles
;
775 fs
.f
.help
.title
= _("HELP FOR SELECTING FOLDER");
778 /* start in the current context */
779 fs
.context
= ps_global
->context_current
;
782 if((folders
= folder_lister(ps_global
, &fs
)) != NULL
){
785 /* replace nickname with full name */
786 if(!(flags
& (FOR_PATTERN
| FOR_OPTIONSCREEN
)))
787 name
= folder_is_nick((char *) folders
->name
,
788 FOLDERS(fs
.context
), 0);
791 name
= (char *) folders
->name
;
793 if(context_isambig(name
) &&
794 !(flags
& (FOR_PATTERN
| FOR_OPTIONSCREEN
) &&
795 folder_is_nick(name
, FOLDERS(fs
.context
), 0))){
796 char path_in_context
[MAILTMPLEN
];
798 context_apply(path_in_context
, fs
.context
, name
,
799 sizeof(path_in_context
));
802 * We may still have a non-fully-qualified name. In the
803 * action case, that will be interpreted in the primary
804 * collection instead of as a local name.
805 * Qualify that name the same way we
806 * qualify it in match_pattern_folder_specific.
808 if(!(IS_REMOTE(path_in_context
) ||
809 path_in_context
[0] == '#')){
810 if(strlen(path_in_context
) < (MAILTMPLEN
/2)){
811 char tmp
[MAX(MAILTMPLEN
,NETMAXMBX
)];
814 t
= mailboxfile(tmp
, path_in_context
);
817 else{ /* the else part should never happen */
818 build_path(tmp_20k_buf
, ps_global
->ui
.homedir
,
819 path_in_context
, SIZEOF_20KBUF
);
820 rs
= cpystr(tmp_20k_buf
);
824 rs
= cpystr(path_in_context
);
829 free_strlist(&folders
);
832 else if(!(fs
.context
&& (fs
.context
->next
|| fs
.context
->prev
))
836 while((fs
.context
= context_screen(fs
.context
, &c_fcc_km
, 0)) != NULL
);
843 * offer screen with list of contexts to select and some sort
847 context_screen(CONTEXT_S
*start
, struct key_menu
*km
, int edit_config
)
849 /* If a list, let the user tell us what to do */
850 if(F_OFF(F_CMBND_FOLDER_DISP
, ps_global
)
851 && ps_global
->context_list
852 && ps_global
->context_list
->next
){
855 memset(&css
, 0, sizeof(CONT_SCR_S
));
856 css
.title
= _("COLLECTION LIST");
857 css
.print_string
= _("contexts");
859 css
.contexts
= &ps_global
->context_list
;
860 css
.help
.text
= h_collection_screen
;
861 css
.help
.title
= _("HELP FOR COLLECTION LIST");
863 css
.edit
= edit_config
;
866 * Use conf_scroll_screen to manage display/selection
869 return(context_select_screen(ps_global
, &css
, 0));
872 return(ps_global
->context_list
);
876 static struct headerentry headents_templ
[]={
877 /* TRANSLATORS: these are the headings for setting up a collection of
878 folders, PATH is a filesystem path, VIEW is sort of a technical
879 term that can be used to restrict the View to fewer folders */
880 {"Nickname : ", N_("Nickname"), h_composer_cntxt_nick
, 12, 0, NULL
,
881 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
882 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
883 {"Server : ", N_("Server"), h_composer_cntxt_server
, 12, 0, NULL
,
884 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
885 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
886 {"Path : ", N_("Path"), h_composer_cntxt_path
, 12, 0, NULL
,
887 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
888 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
889 {"View : ", N_("View"), h_composer_cntxt_view
, 12, 0, NULL
,
890 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
891 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
},
892 {NULL
, NULL
, NO_HELP
, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
893 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KS_NONE
}
902 context_edit_screen(struct pine
*ps
, char *func
, char *def_nick
,
903 char *def_serv
, char *def_path
, char *def_view
)
905 int editor_result
, i
, j
;
906 char servpart
[MAILTMPLEN
], new_cntxt
[MAILTMPLEN
];
907 char pathpart
[MAILTMPLEN
], allbutnick
[MAILTMPLEN
];
908 char tmp
[MAILTMPLEN
], *nick
, *serv
, *path
, *view
,
909 *return_cntxt
= NULL
, *val
, *p
;
910 char nickpmt
[100], servpmt
[100], pathpmt
[100], viewpmt
[100];
916 standard_picobuf_setup(&pbf
);
917 pbf
.pine_flags
|= P_NOBODY
;
918 pbf
.exittest
= exit_collection_add
;
919 pbf
.canceltest
= (func
&& !strucmp(func
, "EDIT")) ? cancel_collection_edit
920 : cancel_collection_add
;
921 snprintf(tmp
, sizeof(tmp
), _("FOLDER COLLECTION %s"), func
);
922 tmp
[sizeof(tmp
)-1] = '\0';
923 pbf
.pine_anchor
= set_titlebar(tmp
, ps_global
->mail_stream
,
924 ps_global
->context_current
,
925 ps_global
->cur_folder
,ps_global
->msgmap
,
926 0, FolderName
, 0, 0, NULL
);
928 /* An informational message */
929 if((msgso
= so_get(PicoText
, NULL
, EDIT_ACCESS
)) != NULL
){
930 pbf
.msgtext
= (void *) so_text(msgso
);
932 _("\n Fill in the fields above to add a Folder Collection to your"));
934 _("\n COLLECTION LIST screen."));
936 _("\n Use the \"^G\" command to get help specific to each item, and"));
938 _("\n use \"^X\" when finished."));
942 pbf
.headents
= (struct headerentry
*)fs_get((sizeof(headents_templ
)
943 /sizeof(struct headerentry
))
944 * sizeof(struct headerentry
));
945 memset((void *) pbf
.headents
, 0,
946 (sizeof(headents_templ
)/sizeof(struct headerentry
))
947 * sizeof(struct headerentry
));
949 for(i
= 0; headents_templ
[i
].prompt
; i
++)
950 pbf
.headents
[i
] = headents_templ
[i
];
952 indent
= utf8_width(_("Nickname")) + 2;
954 nick
= cpystr(def_nick
? def_nick
: "");
955 pbf
.headents
[AC_NICK
].realaddr
= &nick
;
956 pbf
.headents
[AC_NICK
].maxlen
= strlen(nick
);
957 utf8_snprintf(nickpmt
, sizeof(nickpmt
), "%-*.*w: ", indent
, indent
, _("Nickname"));
958 pbf
.headents
[AC_NICK
].prompt
= nickpmt
;
959 pbf
.headents
[AC_NICK
].prwid
= indent
+2;
961 serv
= cpystr(def_serv
? def_serv
: "");
962 pbf
.headents
[AC_SERV
].realaddr
= &serv
;
963 pbf
.headents
[AC_SERV
].maxlen
= strlen(serv
);
964 utf8_snprintf(servpmt
, sizeof(servpmt
), "%-*.*w: ", indent
, indent
, _("Server"));
965 pbf
.headents
[AC_SERV
].prompt
= servpmt
;
966 pbf
.headents
[AC_SERV
].prwid
= indent
+2;
968 path
= cpystr(def_path
? def_path
: "");
969 pbf
.headents
[AC_PATH
].realaddr
= &path
;
970 pbf
.headents
[AC_PATH
].maxlen
= strlen(path
);
971 pbf
.headents
[AC_PATH
].bldr_private
= (void *) 0;
972 utf8_snprintf(pathpmt
, sizeof(pathpmt
), "%-*.*w: ", indent
, indent
, _("Path"));
973 pbf
.headents
[AC_PATH
].prompt
= pathpmt
;
974 pbf
.headents
[AC_PATH
].prwid
= indent
+2;
976 view
= cpystr(def_view
? def_view
: "");
977 pbf
.headents
[AC_VIEW
].realaddr
= &view
;
978 pbf
.headents
[AC_VIEW
].maxlen
= strlen(view
);
979 utf8_snprintf(viewpmt
, sizeof(viewpmt
), "%-*.*w: ", indent
, indent
, _("View"));
980 pbf
.headents
[AC_VIEW
].prompt
= viewpmt
;
981 pbf
.headents
[AC_VIEW
].prwid
= indent
+2;
984 * If this is new context, setup to query IMAP server
985 * for location of personal namespace.
987 if(!(def_nick
|| def_serv
|| def_path
|| def_view
)){
988 pbf
.headents
[AC_SERV
].builder
= build_namespace
;
989 pbf
.headents
[AC_SERV
].affected_entry
= &pbf
.headents
[AC_PATH
];
990 pbf
.headents
[AC_SERV
].bldr_private
= (void *) 0;
993 /* pass to pico and let user change them */
994 editor_result
= pico(&pbf
);
996 if(editor_result
& COMP_GOTHUP
){
1000 fix_windsize(ps_global
);
1004 if(editor_result
& COMP_CANCEL
){
1005 cmd_cancelled(func
);
1007 else if(editor_result
& COMP_EXIT
){
1008 servpart
[0] = pathpart
[0] = new_cntxt
[0] = allbutnick
[0] = '\0';
1010 if(serv
[0] == '{' && serv
[strlen(serv
)-1] == '}'){
1011 strncpy(servpart
, serv
, sizeof(servpart
)-1);
1012 servpart
[sizeof(servpart
)-1] = '\0';
1015 snprintf(servpart
, sizeof(servpart
), "{%s}", serv
);
1017 if(mail_valid_net_parse(servpart
, &mb
)){
1018 if(!struncmp(mb
.service
, "nntp", 4)
1019 && (!path
|| strncmp(path
, "#news.", 6)))
1020 strncat(servpart
, "#news.", sizeof(servpart
)-1-strlen(servpart
));
1023 alpine_panic("Unexpected invalid server");
1028 servpart
[sizeof(servpart
)-1] = '\0';
1030 new_cntxt
[0] = '\0';
1032 val
= quote_if_needed(nick
);
1034 strncpy(new_cntxt
, val
, sizeof(new_cntxt
)-2);
1035 new_cntxt
[sizeof(new_cntxt
)-2] = '\0';
1037 fs_give((void **)&val
);
1039 strncat(new_cntxt
, " ", sizeof(new_cntxt
)-strlen(new_cntxt
)-1);
1040 new_cntxt
[sizeof(new_cntxt
)-1] = '\0';
1045 sstrncpy(&p
, servpart
, sizeof(allbutnick
)-1-(p
-allbutnick
));
1046 allbutnick
[sizeof(allbutnick
)-1] = '\0';
1049 val
= quote_brackets_if_needed(path
);
1051 strncpy(pathpart
, val
, sizeof(pathpart
)-1);
1052 pathpart
[sizeof(pathpart
)-1] = '\0';
1054 fs_give((void **)&val
);
1057 if(pbf
.headents
[AC_PATH
].bldr_private
!= (void *) 0){
1058 strncat(pathpart
, (char *) pbf
.headents
[AC_PATH
].bldr_private
,
1059 sizeof(pathpart
)-strlen(pathpart
)-1);
1060 pathpart
[sizeof(pathpart
)-1] = '\0';
1064 sstrncpy(&p
, pathpart
, sizeof(allbutnick
)-1-(p
-allbutnick
));
1065 allbutnick
[sizeof(allbutnick
)-1] = '\0';
1067 if(view
[0] != '[' && sizeof(allbutnick
)-1-(p
-allbutnick
) > 0){
1072 sstrncpy(&p
, view
, sizeof(allbutnick
)-1-(p
-allbutnick
));
1073 allbutnick
[sizeof(allbutnick
)-1] = '\0';
1074 if((j
=strlen(view
)) < 2 || (view
[j
-1] != ']' &&
1075 sizeof(allbutnick
)-1-(p
-allbutnick
) > 0)){
1080 val
= quote_if_needed(allbutnick
);
1082 strncat(new_cntxt
, val
, sizeof(new_cntxt
)-1-strlen(new_cntxt
));
1083 new_cntxt
[sizeof(new_cntxt
)-1] = '\0';
1085 if(val
!= allbutnick
)
1086 fs_give((void **)&val
);
1089 return_cntxt
= cpystr(new_cntxt
);
1092 for(i
= 0; headents_templ
[i
].prompt
; i
++)
1093 fs_give((void **) pbf
.headents
[i
].realaddr
);
1095 if(pbf
.headents
[AC_PATH
].bldr_private
!= (void *) 0)
1096 fs_give(&pbf
.headents
[AC_PATH
].bldr_private
);
1098 fs_give((void **) &pbf
.headents
);
1100 standard_picobuf_teardown(&pbf
);
1105 return(return_cntxt
);
1110 * Doubles up '[' and ']' characters and returns either
1111 * an allocated string or a pointer to the source string
1112 * if no quoting is needed.
1115 quote_brackets_if_needed(char *src
)
1117 char *step1
= NULL
, *step2
= NULL
, *ret
;
1121 if((strpbrk(src
, "[]") != NULL
)
1122 && ((step1
= add_escapes(src
, "[", '[', "", "")) != NULL
)
1123 && ((step2
= add_escapes(step1
, "]", ']', "", ""))))
1127 fs_give((void **) &step1
);
1134 * Call back for pico to prompt the user for exit confirmation
1136 * Returns: either NULL if the user accepts exit, or string containing
1137 * reason why the user declined.
1140 exit_collection_add(struct headerentry
*he
, void (*redraw_pico
)(void), int allow_flowed
,
1143 char prompt
[256], tmp
[MAILTMPLEN
], tmpnodel
[MAILTMPLEN
], *server
, *path
,
1144 delim
= '\0', *rstr
= NULL
, *p
;
1146 void (*redraw
)(void) = ps_global
->redrawer
;
1149 ps_global
->redrawer
= redraw_pico
;
1150 fix_windsize(ps_global
);
1152 server
= *he
[AC_SERV
].realaddr
;
1153 removing_trailing_white_space(server
);
1154 removing_leading_white_space(server
);
1156 path
= *he
[AC_PATH
].realaddr
;
1160 if(server
[0] == '{' && server
[strlen(server
)-1] == '}'){
1161 strncpy(tmp
, server
, sizeof(tmp
)-1);
1162 tmp
[sizeof(tmp
)-1] = '\0';
1164 else /* add them */ /* sizeof(tmp) == MAILTMPLEN */
1165 snprintf(tmp
, sizeof(tmp
), "{%.*s}", MAILTMPLEN
-3, server
);
1167 if(mail_valid_net_parse(tmp
, &mb
)){ /* news? verify namespace */
1168 if(!struncmp(mb
.service
, "nntp", 4) && strncmp(path
, "#news.", 6))
1169 strncat(tmp
, "#news.", sizeof(tmp
)-1-strlen(tmp
));
1172 rstr
= "Invalid Server entry";
1177 tmp
[sizeof(tmp
)-1] = '\0';
1181 * Delimiter acquisition below serves dual purposes. One's to
1182 * get the delimiter so we can make sure it's hanging off the end
1183 * of the path so we can test for the directory existence. The
1184 * second's to make sure the server (and any requested service)
1185 * name we were given exists. It should be handled by the folder
1186 * existence test further below, but it doesn't work with news...
1188 * Update. Now we are stripping the delimiter in the tmpnodel version
1189 * so that we can pass that to folder_exists. Cyrus does not answer
1190 * that the folder exists if we leave the trailing delimiter.
1193 strncat(tmp
, path
, sizeof(tmp
)-1-strlen(tmp
));
1194 tmp
[sizeof(tmp
)-1] = '\0';
1195 strncpy(tmpnodel
, tmp
, sizeof(tmpnodel
)-1);
1196 tmpnodel
[sizeof(tmpnodel
)-1] = '\0';
1198 if(he
[AC_PATH
].bldr_private
!= (void *) 0)
1199 fs_give(&he
[AC_PATH
].bldr_private
);
1201 ps_global
->mm_log_error
= 0;
1202 if((delim
= folder_delimiter(tmp
)) != '\0'){
1204 if(tmp
[(i
= strlen(tmp
)) - 1] == delim
)
1205 tmpnodel
[i
-1] = '\0';
1209 he
[AC_PATH
].bldr_private
= (void *) cpystr(&tmp
[i
]);
1213 else if(ps_global
->mm_log_error
&& ps_global
->last_error
)
1214 /* We used to bail, but this was changed with 4.10
1215 * as some users wanted to add clctn before the server
1216 * was actually around and built.
1218 flush_status_messages(0); /* mail_create gripes */
1220 dprint((1, "exit_col_test: No Server Hierarchy!\n"));
1226 || ((*(p
= tmp
) == '#'
1227 || (*tmp
== '{' && (p
= strchr(tmp
, '}')) && *++p
))
1228 && !struncmp(p
, "#news.", 6))
1229 || (*tmp
== '{' && (p
= strchr(tmp
, '}')) && !*++p
)){
1232 else if((i
= folder_exists(NULL
, tmpnodel
)) & FEX_ERROR
){
1233 if(!(rstr
= ps_global
->last_error
))
1234 rstr
= _("Problem testing for directory existence");
1237 exists
= (i
& FEX_ISDIR
);
1240 snprintf(prompt
, sizeof(prompt
), _("Exit and save changes"));
1242 snprintf(prompt
, sizeof(prompt
), _("Exit, saving changes and creating Path"));
1244 if(want_to(prompt
, 'y', 0, NO_HELP
, WT_NORM
) == 'y'){
1245 if(!exists
&& !pine_mail_create(NULL
, tmp
)){
1246 flush_status_messages(1); /* mail_create gripes */
1247 if(!(rstr
= ps_global
->last_error
))
1252 rstr
= _("Use ^C to abandon changes you've made");
1258 ps_global
->redrawer
= redraw
;
1259 return((rstr
== NULL
) ? 0 : 1);
1264 cancel_collection_add(void (*redraw_pico
)(void))
1266 return(cancel_collection_editing(_("Add"), redraw_pico
));
1271 cancel_collection_edit(void (*redraw_pico
)(void))
1273 return(cancel_collection_editing(_("Edit"), redraw_pico
));
1278 cancel_collection_editing(char *func
, void (*redraw_pico
)(void))
1281 void (*redraw
)(void) = ps_global
->redrawer
;
1282 static char rbuf
[20];
1284 #define CCA_PROMPT \
1285 _("Cancel Add (answering \"Yes\" will abandon any changes made) ")
1287 snprintf(prompt
, sizeof(prompt
), _("Cancel %s (answering \"Yes\" will abandon any changes made) "), func
? func
: "Add");
1288 snprintf(rbuf
, sizeof(rbuf
), _("%s Cancelled) "), func
? func
: "Add");
1290 ps_global
->redrawer
= redraw_pico
;
1291 fix_windsize(ps_global
);
1293 switch(want_to(prompt
, 'y', 'x', NO_HELP
, WT_NORM
)){
1303 ps_global
->redrawer
= redraw
;
1309 build_namespace(char *server
, char **server_too
, char **error
, BUILDER_ARG
*barg
, int *mangled
)
1314 NAMESPACE
***namespace;
1317 dprint((5, "- build_namespace - (%s)\n",
1318 server
? server
: "nul"));
1320 if(*barg
->me
){ /* only call this once! */
1322 *server_too
= cpystr(server
? server
: "");
1327 *barg
->me
= (void *) 1;
1329 if((p
= server
) != NULL
) /* empty string? */
1330 while(*p
&& isspace((unsigned char) *p
))
1335 *server_too
= cpystr(p
);
1337 len
= strlen(p
) + 2;
1338 name
= (char *) fs_get((len
+ 1) * sizeof(char));
1339 snprintf(name
, len
+1, "{%s}", p
);
1343 *server_too
= cpystr("");
1348 *mangled
|= BUILDER_SCREEN_MANGLED
;
1349 fix_windsize(ps_global
);
1353 we_cancel
= busy_cue(_("Fetching default directory"), NULL
, 1);
1355 if((stream
= pine_mail_open(NULL
, name
,
1356 OP_HALFOPEN
| OP_SILENT
| SP_USEPOOL
| SP_TEMPUSE
,
1358 if((namespace = mail_parameters(stream
, GET_NAMESPACE
, NULL
))
1359 && *namespace && (*namespace)[0]
1360 && (*namespace)[0]->name
&& (*namespace)[0]->name
[0]){
1362 fs_give((void **)&barg
->tptr
);
1364 barg
->tptr
= cpystr((*namespace)[0]->name
);
1367 pine_mail_close(stream
);
1371 cancel_busy_cue(-1);
1373 fs_give((void **) &name
);
1380 fl_val_gen (FOLDER_S
*f
, FSTATE_S
*fs
)
1382 return(f
&& FLDR_NAME(f
));
1387 fl_val_writable (FOLDER_S
*f
, FSTATE_S
*fs
)
1394 fl_val_subscribe (FOLDER_S
*f
, FSTATE_S
*fs
)
1397 q_status_message1(SM_ORDER
, 0, 4, _("Already subscribed to \"%s\""),
1406 /*----------------------------------------------------------------------
1407 Business end of displaying and operating on a collection of folders
1409 Args: ps -- The pine_state data structure
1410 fs -- Folder screen state structure
1412 Result: A string list containing folders selected,
1413 NULL on Cancel, Error or other problem
1417 folder_lister(struct pine
*ps
, FSTATE_S
*fs
)
1419 int fltrv
, we_cancel
= 0;
1420 int first_time_through
= 1;
1421 HANDLE_S
*handles
= NULL
;
1422 STORE_S
*screen_text
= NULL
;
1423 FPROC_S folder_proc_data
;
1426 dprint((1, "\n\n ---- FOLDER LISTER ----\n"));
1428 memset(&folder_proc_data
, 0, sizeof(FPROC_S
));
1429 folder_proc_data
.fs
= fs
;
1431 while(!folder_proc_data
.done
){
1432 if((screen_text
= so_get(CharStar
, NULL
, EDIT_ACCESS
)) != NULL
){
1433 gf_set_so_writec(&pc
, screen_text
);
1436 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
1437 "Formatting Error: Can't create space for list");
1441 we_cancel
= busy_cue(_("Fetching folder data"), NULL
, 1);
1442 fltrv
= folder_list_text(ps
, &folder_proc_data
, pc
, &handles
,
1443 ps
->ttyo
->screen_cols
);
1445 cancel_busy_cue(-1);
1451 struct key keys
[36];
1453 memset(&sargs
, 0, sizeof(SCROLL_S
));
1454 sargs
.text
.text
= so_text(screen_text
);
1455 sargs
.text
.src
= CharStar
;
1456 sargs
.text
.desc
= "folder list";
1457 if((sargs
.text
.handles
= folder_list_handle(fs
, handles
)) != NULL
)
1458 sargs
.start
.on
= Handle
;
1460 sargs
.bar
.title
= fs
->f
.title
.bar
;
1461 sargs
.bar
.style
= fs
->f
.title
.style
;
1463 sargs
.proc
.tool
= folder_processor
;
1464 sargs
.proc
.data
.p
= (void *) &folder_proc_data
;
1466 sargs
.quell_first_view
= first_time_through
? 0 : 1;
1467 first_time_through
= 0;
1469 sargs
.resize_exit
= 1;
1470 sargs
.vert_handle
= 1;
1471 sargs
.srch_handle
= 1;
1473 sargs
.help
.text
= fs
->f
.help
.text
;
1474 sargs
.help
.title
= fs
->f
.help
.title
;
1476 sargs
.keys
.menu
= &km
;
1479 memcpy(&keys
[0], fs
->km
->keys
,
1480 (km
.how_many
* 12) * sizeof(struct key
));
1481 setbitmap(sargs
.keys
.bitmap
);
1483 if(fs
->km
== &folder_km
){
1484 sargs
.keys
.each_cmd
= folder_lister_km_manager
;
1486 sargs
.mouse
.popup
= folder_list_popup
;
1491 sargs
.mouse
.popup
= folder_list_select_popup
;
1493 if(fs
->km
== &folder_sel_km
|| fs
->km
== &folder_sela_km
)
1494 sargs
.keys
.each_cmd
= folder_lister_km_sel_manager
;
1495 else if(fs
->km
== &folder_sub_km
)
1496 sargs
.keys
.each_cmd
= folder_lister_km_sub_manager
;
1499 sargs
.mouse
.clickclick
= folder_lister_clickclick
;
1501 switch(scrolltool(&sargs
)){
1502 case MC_MAIN
: /* just leave */
1503 folder_proc_data
.done
= 1;
1506 case MC_RESIZE
: /* loop around rebuilding screen */
1507 if(sargs
.text
.handles
){
1510 fp
= folder_entry(sargs
.text
.handles
->h
.f
.index
,
1511 FOLDERS(sargs
.text
.handles
->h
.f
.context
));
1512 if(fp
&& strlen(FLDR_NAME(fp
)) < MAXFOLDER
-1){
1513 strncpy(fs
->first_folder
, FLDR_NAME(fp
), MAXFOLDER
);
1514 fs
->first_folder
[MAXFOLDER
-1] = '\0';
1517 fs
->context
= sargs
.text
.handles
->h
.f
.context
;
1522 /*--------- EXIT menu -----------*/
1525 fs
->list_cntxt
= NULL
;
1526 folder_proc_data
.done
= folder_proc_data
.all_done
= 1;
1533 ps
->noticed_change_in_unseen
= 0;
1536 if(F_ON(F_BLANK_KEYMENU
,ps
))
1537 FOOTER_ROWS(ps
) = 1;
1539 gf_clear_so_writec(screen_text
);
1540 so_give(&screen_text
);
1541 free_handles(&handles
);
1544 folder_proc_data
.done
= 1;
1547 reset_context_folders(fs
->context
);
1549 if(folder_proc_data
.all_done
)
1552 if(fs
->cache_streamp
&& *fs
->cache_streamp
){
1556 * check stream pool to see if currently cached
1559 for(i
= 0; i
< ps
->s_pool
.nstream
; i
++)
1560 if(ps
->s_pool
.streams
[i
] == *fs
->cache_streamp
)
1562 if(i
== ps
->s_pool
.nstream
)
1563 *fs
->cache_streamp
= NULL
;
1566 return(folder_proc_data
.rv
);
1571 * folder_list_text - format collection's contents for display
1574 folder_list_text(struct pine
*ps
, FPROC_S
*fp
, gf_io_t pc
, HANDLE_S
**handlesp
, int cols
)
1576 int rv
= 1, i
, j
, ftotal
, fcount
, slot_width
, slot_rows
,
1577 slot_cols
, index
, findex
, width
, shown
, selected
;
1579 char lbuf
[6*MAX_SCREEN_COLS
+1];
1581 /* disarm this trigger that gets us out of scrolltool */
1582 ps
->noticed_change_in_unseen
= 0;
1585 init_handles(handlesp
);
1587 c_list
= fp
->fs
->context
;
1588 if(fp
->fs
->combined_view
1589 && (F_ON(F_CMBND_SUBDIR_DISP
, ps_global
) || !c_list
->dir
->prev
))
1590 while(c_list
->prev
) /* rewind to start */
1591 c_list
= c_list
->prev
;
1594 ps
->user_says_cancel
= 0;
1596 /* If we're displaying folders, fetch the list */
1597 if((shown
= (c_list
== fp
->fs
->context
1598 || (c_list
->dir
->status
& CNTXT_NOFIND
) == 0
1599 || F_ON(F_EXPANDED_FOLDERS
, ps_global
))) != 0){
1601 * if select is allowed, flag context so any that are
1602 * are remembered even after the list is destroyed
1605 c_list
->use
|= CNTXT_PRESRV
;
1607 /* Make sure folder list filled in */
1608 refresh_folder_list(c_list
, fp
->fs
->no_dirs
, FALSE
, fp
->fs
->cache_streamp
);
1611 /* Insert any introductory text here */
1614 || c_list
->dir
->prev
1615 || fp
->fs
->force_intro
){
1617 /* Leading horizontal line? */
1618 if(fp
->fs
->combined_view
1619 && (F_ON(F_CMBND_SUBDIR_DISP
,ps_global
)
1620 || !c_list
->dir
->prev
)){
1622 gf_puts("\n", pc
); /* blank line */
1624 color_write_for_folder(pc
, CLR_FLDRLT
);
1625 gf_puts(repeat_char(cols
, '-'), pc
);
1627 color_write_for_folder(pc
, CLR_NORMAL
);
1630 /* nickname or description */
1631 if(F_ON(F_CMBND_FOLDER_DISP
, ps_global
)
1632 && (!c_list
->dir
->prev
1633 || F_ON(F_CMBND_SUBDIR_DISP
, ps_global
))){
1634 char buf
[6*MAX_SCREEN_COLS
+ 1];
1636 color_write_for_folder(pc
, CLR_FLDRLT
);
1638 snprintf(buf
, sizeof(buf
), "%.*s", cols
,
1639 strsquish(tmp_20k_buf
, SIZEOF_20KBUF
,
1642 : (c_list
->label
? c_list
->label
: ""),
1644 gf_puts(folder_list_center_space(buf
, cols
), pc
);
1649 snprintf(buf
, sizeof(buf
), "%s-Collection <",
1650 NEWS_TEST(c_list
) ? "News" : "Folder");
1651 wid
= utf8_width(buf
)+1;
1652 wid
= MAX(0, cols
-wid
);
1653 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
), "%.*s>", wid
,
1654 strsquish(tmp_20k_buf
, SIZEOF_20KBUF
,
1657 : (c_list
->label
? c_list
->label
: ""),
1663 color_write_for_folder(pc
, CLR_NORMAL
);
1665 else if(c_list
->label
){
1666 if(utf8_width(c_list
->label
) > ps_global
->ttyo
->screen_cols
)
1667 utf8_pad_to_width(lbuf
, c_list
->label
, sizeof(lbuf
), ps_global
->ttyo
->screen_cols
, 1);
1669 strncpy(lbuf
, c_list
->label
, sizeof(lbuf
));
1671 lbuf
[sizeof(lbuf
)-1] = '\0';
1673 color_write_for_folder(pc
, CLR_FLDRLT
);
1674 gf_puts(folder_list_center_space(lbuf
, cols
), pc
);
1677 color_write_for_folder(pc
, CLR_NORMAL
);
1680 if(c_list
->comment
){
1681 if(utf8_width(c_list
->comment
) > ps_global
->ttyo
->screen_cols
)
1682 utf8_pad_to_width(lbuf
, c_list
->comment
, sizeof(lbuf
), ps_global
->ttyo
->screen_cols
, 1);
1684 strncpy(lbuf
, c_list
->comment
, sizeof(lbuf
));
1686 lbuf
[sizeof(lbuf
)-1] = '\0';
1688 color_write_for_folder(pc
, CLR_FLDRLT
);
1689 gf_puts(folder_list_center_space(lbuf
, cols
), pc
);
1692 color_write_for_folder(pc
, CLR_NORMAL
);
1695 if(c_list
->dir
->desc
){
1696 char buf
[6*MAX_SCREEN_COLS
+ 1];
1698 strncpy(buf
, strsquish(tmp_20k_buf
,SIZEOF_20KBUF
,c_list
->dir
->desc
,cols
),
1700 buf
[sizeof(buf
)-1] = '\0';
1701 color_write_for_folder(pc
, CLR_FLDRLT
);
1702 gf_puts(folder_list_center_space(buf
, cols
), pc
);
1705 color_write_for_folder(pc
, CLR_NORMAL
);
1708 if(c_list
->use
& CNTXT_ZOOM
){
1709 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "[ ZOOMED on %d (of %d) %ss ]",
1710 selected_folders(c_list
),
1711 folder_total(FOLDERS(c_list
)),
1712 (c_list
->use
& CNTXT_NEWS
) ? "Newsgroup" : "Folder");
1713 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1715 if(utf8_width(tmp_20k_buf
) > ps_global
->ttyo
->screen_cols
)
1716 utf8_pad_to_width(lbuf
, tmp_20k_buf
, sizeof(lbuf
), ps_global
->ttyo
->screen_cols
, 1);
1718 strncpy(lbuf
, tmp_20k_buf
, sizeof(lbuf
));
1720 lbuf
[sizeof(lbuf
)-1] = '\0';
1722 color_write_for_folder(pc
, CLR_FLDRLT
);
1723 gf_puts(folder_list_center_space(lbuf
, cols
), pc
);
1726 color_write_for_folder(pc
, CLR_NORMAL
);
1729 color_write_for_folder(pc
, CLR_FLDRLT
);
1730 gf_puts(repeat_char(cols
, '-'), pc
);
1731 gf_puts("\n\n", pc
);
1732 color_write_for_folder(pc
, CLR_NORMAL
);
1735 if(shown
&& LUU_YES(c_list
->update
)){
1736 /* Run thru list formatting as necessary */
1737 if((ftotal
= folder_total(FOLDERS(c_list
))) != 0){
1739 /* If previously selected, mark members of new list */
1740 selected
= selected_folders(c_list
);
1742 /* How many screen cells per cell for each folder name? */
1744 for(fcount
= i
= 0; i
< ftotal
; i
++){
1745 FOLDER_S
*f
= folder_entry(i
, FOLDERS(c_list
));
1746 unsigned char *fname
;
1748 ps
->user_says_cancel
= 0;
1750 if((c_list
->use
& CNTXT_ZOOM
) && !f
->selected
)
1755 use_color
= use_color_for_folder(f
);
1756 fname
= folder_name_decoded((unsigned char *)FLDR_NAME(f
));
1758 width
= utf8_width(fname
? (char *)fname
: FLDR_NAME(f
));
1761 fs_give((void **)&fname
);
1764 width
+= (f
->isfolder
) ? (use_color
? 1 : 3) : (use_color
? 0 : 1);
1766 if(NEWS_TEST(c_list
) && (c_list
->use
& CNTXT_FINDALL
))
1767 /* assume listmode so we don't have to reformat */
1768 /* if listmode is actually entered */
1772 if(F_OFF(F_SELECTED_SHOWN_BOLD
, ps_global
))
1773 width
+= 4; /* " X " */
1775 else if(c_list
== fp
->fs
->list_cntxt
)
1776 width
+= 4; /* "[X] " */
1778 if(fp
->fs
->include_unseen_cnt
1779 && c_list
->use
& CNTXT_INCMNG
1780 && F_ON(F_ENABLE_INCOMING_CHECKING
, ps_global
)
1781 && ps_global
->VAR_INCOMING_FOLDERS
1782 && ps_global
->VAR_INCOMING_FOLDERS
[0]){
1784 update_folder_unseen(f
, c_list
, UFU_ANNOUNCE
, NULL
);
1785 if(F_ON(F_INCOMING_CHECKING_RECENT
, ps_global
)
1788 || F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
))){
1789 width
+= (strlen(tose(f
->new)) + 3);
1790 if(F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
))
1791 width
+= (strlen(tose(f
->total
)) + 1);
1793 else if(F_OFF(F_INCOMING_CHECKING_RECENT
, ps_global
)
1796 || F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
))){
1797 width
+= (strlen(tose(f
->unseen
)) + 3);
1798 if(F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
))
1799 width
+= (strlen(tose(f
->total
)) + 1);
1801 else if(!f
->unseen_valid
&& f
->last_unseen_update
!= LUU_NEVERCHK
)
1802 width
+= 4; /* " (?)" */
1805 if(slot_width
< width
)
1809 if(F_ON(F_SINGLE_FOLDER_LIST
, ps_global
)){
1814 /* fit as many columns as possible */
1816 while(((slot_cols
+1) * slot_width
) + slot_cols
<= cols
)
1830 * Make the slot_width as large as possible.
1831 * Slot_width is the width of the column, not counting
1832 * the space between columns.
1834 while((slot_cols
* (slot_width
+1)) + slot_cols
-1 <= cols
)
1837 slot_rows
= (fcount
/ slot_cols
)
1838 + ((fcount
% slot_cols
) ? 1 : 0);
1843 for(i
= index
= 0; i
< slot_rows
; i
++){
1847 for(j
= width
= 0; j
< slot_cols
; j
++, index
++){
1849 gf_puts(repeat_char(slot_width
+ 1 - width
, ' '), pc
);
1853 if(F_ON(F_VERTICAL_FOLDER_LIST
, ps_global
))
1854 index
= i
+ (j
* slot_rows
);
1858 if(c_list
->use
& CNTXT_ZOOM
)
1859 findex
= folder_list_ith(index
, c_list
);
1861 if(findex
< ftotal
){
1862 int flags
= (handlesp
) ? FLW_LUNK
: FLW_NONE
;
1864 if(c_list
== fp
->fs
->list_cntxt
)
1868 else if(F_ON(F_SINGLE_FOLDER_LIST
, ps_global
)
1869 || ((c_list
->use
& CNTXT_FINDALL
)
1870 && NEWS_TEST(c_list
)))
1873 if(fp
->fs
->include_unseen_cnt
1874 && c_list
->use
& CNTXT_INCMNG
1875 && F_ON(F_ENABLE_INCOMING_CHECKING
, ps_global
)
1876 && ps_global
->VAR_INCOMING_FOLDERS
1877 && ps_global
->VAR_INCOMING_FOLDERS
[0])
1878 flags
|= FLW_UNSEEN
;
1880 width
= folder_list_write(pc
, handlesp
, c_list
,
1881 findex
, NULL
, flags
);
1886 else if(fp
->fs
->combined_view
1887 && (F_ON(F_CMBND_SUBDIR_DISP
, ps_global
)
1888 || !c_list
->dir
->prev
)){
1889 char *emptiness
= N_("[No Folders in Collection]");
1891 if(utf8_width(_(emptiness
)) > ps_global
->ttyo
->screen_cols
)
1892 utf8_pad_to_width(lbuf
, _(emptiness
), sizeof(lbuf
), ps_global
->ttyo
->screen_cols
, 1);
1894 strncpy(lbuf
, _(emptiness
), sizeof(lbuf
));
1896 lbuf
[sizeof(lbuf
)-1] = '\0';
1898 color_write_for_folder(pc
, CLR_FLDRLT
);
1899 gf_puts(folder_list_center_space(lbuf
, cols
), pc
);
1900 (void) folder_list_write(pc
, handlesp
, c_list
, -1, lbuf
,
1901 (handlesp
) ? FLW_LUNK
: FLW_NONE
);
1902 color_write_for_folder(pc
, CLR_NORMAL
);
1905 else if(fp
->fs
->combined_view
1906 && (F_ON(F_CMBND_SUBDIR_DISP
, ps_global
)
1907 || !c_list
->dir
->prev
)){
1908 char *unexpanded
= N_("[Select Here to See Expanded List]");
1910 if(utf8_width(_(unexpanded
)) > ps_global
->ttyo
->screen_cols
)
1911 utf8_pad_to_width(lbuf
, _(unexpanded
), sizeof(lbuf
), ps_global
->ttyo
->screen_cols
, 1);
1913 strncpy(lbuf
, _(unexpanded
), sizeof(lbuf
));
1915 lbuf
[sizeof(lbuf
)-1] = '\0';
1917 color_write_for_folder(pc
, CLR_FLDRLT
);
1918 gf_puts(folder_list_center_space(lbuf
, cols
), pc
);
1919 (void) folder_list_write(pc
, handlesp
, c_list
, -1, lbuf
,
1920 (handlesp
) ? FLW_LUNK
: FLW_NONE
);
1921 color_write_for_folder(pc
, CLR_NORMAL
);
1924 gf_puts("\n", pc
); /* blank line */
1927 while(fp
->fs
->combined_view
1928 && (F_ON(F_CMBND_SUBDIR_DISP
, ps_global
) || !c_list
->dir
->prev
)
1929 && (c_list
= c_list
->next
));
1936 folder_list_write(gf_io_t pc
, HANDLE_S
**handlesp
, CONTEXT_S
*ctxt
, int fnum
, char *alt_name
, int flags
)
1939 int width
= 0, lprefix
= 0, lmiddle
= 0, lsuffix
= 0;
1941 HANDLE_S
*h1
= NULL
, *h2
= NULL
;
1943 if(flags
& FLW_LUNK
){
1944 h1
= new_handle(handlesp
);
1946 h1
->h
.f
.index
= fnum
;
1947 h1
->h
.f
.context
= ctxt
;
1948 h1
->force_display
= 1;
1950 snprintf(buf
, sizeof(buf
), "%d", h1
->key
);
1951 buf
[sizeof(buf
)-1] = '\0';
1954 fp
= (fnum
< 0) ? NULL
: folder_entry(fnum
, FOLDERS(ctxt
));
1956 if(flags
& FLW_LUNK
&& h1
&& fp
&& fp
->isdir
&& fp
->isfolder
){
1957 h2
= new_handle(handlesp
);
1959 h2
->h
.f
.index
= fnum
;
1960 h2
->h
.f
.context
= ctxt
;
1961 h2
->force_display
= 1;
1963 h1
->is_dual_do_open
= 1;
1968 if(color_monitored(fp
, flags
, CLR_UNSEEN
)){
1969 h1
->color_unseen
= 1;
1971 h2
->color_unseen
= 1;
1974 if(color_monitored(fp
, flags
, CLR_FOLDER
)){
1975 h1
->color_folder
= 1;
1977 h2
->color_folder
= 1;
1981 /* embed handle pointer */
1982 if(((h1
&& h1
->color_unseen
) ? color_write_for_folder(pc
, CLR_UNSEEN
)
1983 : ((h1
&& h1
->color_folder
)
1984 ? color_write_for_folder(pc
, fp
->isfolder
? CLR_FOLDER
: CLR_DIRECT
)
1986 && (h1
? ((*pc
)(TAG_EMBED
) && (*pc
)(TAG_HANDLE
)
1987 && (*pc
)(strlen(buf
)) && gf_puts(buf
, pc
)) : 1)
1988 && (fp
? ((lprefix
= folder_list_write_prefix(fp
, flags
, pc
)) >= 0
1989 && (lmiddle
= folder_list_write_middle(fp
, ctxt
, pc
, h2
)) >= 0
1990 && ((lsuffix
= folder_list_write_suffix(fp
, flags
, pc
)) >= 0))
1991 : (alt_name
? gf_puts(alt_name
, pc
) : 0))
1992 && (h1
? ((*pc
)(TAG_EMBED
) && (*pc
)(TAG_BOLDOFF
)
1993 && (*pc
)(TAG_EMBED
) && (*pc
)(TAG_INVOFF
)) : 1)
1994 && ((h1
&& (h1
->color_unseen
|| h1
->color_folder
)) ?
1995 color_write_for_folder(pc
, CLR_NORMAL
): 1)){
1997 width
= lprefix
+ lmiddle
+ lsuffix
;
1999 width
= utf8_width(alt_name
);
2007 folder_list_write_prefix(FOLDER_S
*f
, int flags
, gf_io_t pc
)
2011 if(flags
& FLW_SLCT
){
2012 if(F_OFF(F_SELECTED_SHOWN_BOLD
, ps_global
) || !(flags
& FLW_LUNK
)){
2022 rv
= ((*pc
)(TAG_EMBED
)
2023 && (*pc
)((f
->selected
) ? TAG_BOLDON
: TAG_BOLDOFF
)) ? 0 : -1;
2025 else if(flags
& FLW_LIST
){
2027 /* screen width of "SUB " is 4 */
2028 gf_puts(f
->subscribed
? "SUB " : (f
->selected
? "[X] " : "[ ] "), pc
);
2035 folder_list_write_middle(FOLDER_S
*fp
, CONTEXT_S
*ctxt
, gf_io_t pc
, HANDLE_S
*h2
)
2037 int rv
= -1, use_color
;
2039 unsigned char *fname
;
2042 snprintf(buf
, sizeof(buf
), "%d", h2
->key
);
2043 buf
[sizeof(buf
)-1] = '\0';
2049 fname
= folder_name_decoded((unsigned char *)FLDR_NAME(fp
));
2050 use_color
= use_color_for_folder(fp
);
2052 if(gf_puts(fname
? (char *)fname
: FLDR_NAME(fp
), pc
)
2053 && (h2
? ((*pc
)(TAG_EMBED
) && (*pc
)(TAG_BOLDOFF
) /* tie off handle 1 */
2054 && (*pc
)(TAG_EMBED
) && (*pc
)(TAG_INVOFF
)) : 1)
2055 && ((use_color
&& fp
->isdir
&& fp
->isfolder
)
2056 ? color_write_for_folder(pc
, CLR_DIRECT
) : 1)
2057 && (h2
? ((*pc
)(TAG_EMBED
) && (*pc
)(TAG_HANDLE
) /* start handle 2 */
2058 && (*pc
)(strlen(buf
)) && gf_puts(buf
, pc
)) : 1)
2060 ? (fp
->isdir
&& fp
->isfolder
? (*pc
)(ctxt
->dir
->delim
) : 1)
2061 : (((fp
->isdir
&& fp
->isfolder
) ? (*pc
)('[') : 1)
2062 && ((fp
->isdir
) ? (*pc
)(ctxt
->dir
->delim
) : 1)
2063 && ((fp
->isdir
&& fp
->isfolder
) ? (*pc
)(']') : 1))){
2064 rv
= utf8_width(fname
? (char *)fname
: FLDR_NAME(fp
));
2066 rv
+= (fp
->isfolder
) ? (use_color
? 1 : 3) : (use_color
? 0 : 1);
2070 fs_give((void **)&fname
);
2077 folder_list_write_suffix(FOLDER_S
*f
, int flags
, gf_io_t pc
)
2081 if(flags
& FLW_UNSEEN
){
2085 if(F_ON(F_INCOMING_CHECKING_RECENT
, ps_global
)
2088 || (F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
)
2089 && f
->total
> 0L))){
2090 snprintf(buf
, sizeof(buf
), " (%s%s%s)",
2092 F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
) ? "/" : "",
2093 F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
) ? tose(f
->total
) : "");
2095 else if(F_OFF(F_INCOMING_CHECKING_RECENT
, ps_global
)
2098 || (F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
)
2099 && f
->total
> 0L))){
2100 snprintf(buf
, sizeof(buf
), " (%s%s%s)",
2102 F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
) ? "/" : "",
2103 F_ON(F_INCOMING_CHECKING_TOTAL
, ps_global
) ? tose(f
->total
) : "");
2105 else if(!f
->unseen_valid
&& f
->last_unseen_update
!= LUU_NEVERCHK
){
2106 snprintf(buf
, sizeof(buf
), " (?)");
2118 color_write_for_folder(gf_io_t pc
, int testtype
)
2121 if(!pico_usingcolor())
2125 rv
= gf_puts(color_embed(ps_global
->VAR_INCUNSEEN_FORE_COLOR
,
2126 ps_global
->VAR_INCUNSEEN_BACK_COLOR
), pc
);
2129 rv
= gf_puts(color_embed(ps_global
->VAR_FOLDER_FORE_COLOR
,
2130 ps_global
->VAR_FOLDER_BACK_COLOR
), pc
);
2133 rv
= gf_puts(color_embed(ps_global
->VAR_FOLDER_LIST_FORE_COLOR
,
2134 ps_global
->VAR_FOLDER_LIST_BACK_COLOR
), pc
);
2137 rv
= gf_puts(color_embed(ps_global
->VAR_DIRECTORY_FORE_COLOR
,
2138 ps_global
->VAR_DIRECTORY_BACK_COLOR
), pc
);
2141 rv
= gf_puts(color_embed(ps_global
->VAR_NORM_FORE_COLOR
,
2142 ps_global
->VAR_NORM_BACK_COLOR
), pc
);
2153 color_test_for_folder(char *color_fore
, char *color_back
)
2155 return pico_usingcolor()
2156 && pico_is_good_color(color_fore
)
2157 && pico_is_good_color(color_back
)
2158 && (colorcmp(color_fore
, ps_global
->VAR_NORM_FORE_COLOR
)
2159 || colorcmp(color_back
,
2160 ps_global
->VAR_NORM_BACK_COLOR
)) ? 1 : 0;
2166 use_color_for_folder(FOLDER_S
*fp
)
2168 int test1
= 0, test2
= 0;
2170 test1
= color_test_for_folder(ps_global
->VAR_DIRECTORY_FORE_COLOR
,
2171 ps_global
->VAR_DIRECTORY_BACK_COLOR
);
2173 test2
= color_test_for_folder(ps_global
->VAR_FOLDER_FORE_COLOR
,
2174 ps_global
->VAR_FOLDER_BACK_COLOR
);
2175 return (fp
->isdir
&& fp
->isfolder
) ? test1
+ test2
2176 : (fp
->isdir
? test1
: (fp
->isfolder
? test2
: 0));
2181 color_monitored(FOLDER_S
*f
, int flags
, int testtype
)
2185 case CLR_UNSEEN
: rv
= (flags
& FLW_UNSEEN
) && f
&& f
->unseen_valid
2186 && ((F_ON(F_INCOMING_CHECKING_RECENT
, ps_global
) && f
->new > 0L)
2187 || (F_OFF(F_INCOMING_CHECKING_RECENT
, ps_global
) && f
->unseen
> 0L))
2188 && color_test_for_folder(ps_global
->VAR_INCUNSEEN_FORE_COLOR
,
2189 ps_global
->VAR_INCUNSEEN_BACK_COLOR
) ? 1 : 0;
2191 case CLR_FOLDER
: rv
= f
? use_color_for_folder(f
) : 0;
2200 folder_list_ith(int n
, CONTEXT_S
*cntxt
)
2205 for(index
= 0, ftotal
= folder_total(FOLDERS(cntxt
));
2207 && (f
= folder_entry(index
, FOLDERS(cntxt
)))
2208 && !(f
->selected
&& !n
--);
2217 folder_list_center_space(char *s
, int width
)
2221 return(((l
= utf8_width(s
)) < width
) ? repeat_char((width
- l
)/2, ' ') : "");
2226 * folder_list_handle - return pointer in handle list
2227 * corresponding to "start"
2230 folder_list_handle(FSTATE_S
*fs
, HANDLE_S
*handles
)
2232 char *p
, *name
= NULL
;
2233 HANDLE_S
*h
, *h_found
= NULL
;
2236 if(handles
&& fs
->context
){
2237 if(!(NEWS_TEST(fs
->context
) || (fs
->context
->use
& CNTXT_INCMNG
))
2238 && fs
->context
->dir
->delim
)
2239 for(p
= strchr(fs
->first_folder
, fs
->context
->dir
->delim
);
2241 p
= strchr(p
, fs
->context
->dir
->delim
))
2244 for(h
= handles
; h
; h
= h
->next
)
2245 if(h
->h
.f
.context
== fs
->context
){
2246 if(!h_found
) /* match at least given context */
2249 if(!fs
->first_folder
[0]
2250 || ((fp
= folder_entry(h
->h
.f
.index
, FOLDERS(h
->h
.f
.context
)))
2251 && ((fs
->first_dir
&& fp
->isdir
)
2252 || (!fs
->first_dir
&& fp
->isfolder
))
2253 && ((fp
->nickname
&& !strcmp(name
? name
: fs
->first_folder
, fp
->nickname
))
2254 || (fp
->name
&& !strcmp(name
? name
: fs
->first_folder
, fp
->name
))))){
2260 fs
->first_folder
[0] = '\0';
2263 return(h_found
? h_found
: handles
);
2268 folder_processor(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
2271 char tmp_output
[MAILTMPLEN
];
2275 FPROC(sparms
)->done
= rv
= 1;;
2278 /*---------- Select or enter a View ----------*/
2280 rv
= folder_lister_choice(sparms
);
2283 /*--------- Hidden "To Fldrs" command -----------*/
2285 if(sparms
->text
.handles
2286 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
))){
2287 if(!FPROC(sparms
)->fs
->list_cntxt
){
2288 FPROC(sparms
)->fs
->list_cntxt
2289 = sparms
->text
.handles
->h
.f
.context
;
2290 rv
= scroll_add_listmode(sparms
->text
.handles
->h
.f
.context
,
2291 folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
)));
2293 /* need to set the subscribe key ourselves */
2294 sparms
->keys
.menu
->keys
[SB_SUB_KEY
].name
= "S";
2295 sparms
->keys
.menu
->keys
[SB_SUB_KEY
].label
= N_("Subscribe");
2296 sparms
->keys
.menu
->keys
[SB_SUB_KEY
].bind
.cmd
= MC_CHOICE
;
2297 sparms
->keys
.menu
->keys
[SB_SUB_KEY
].bind
.ch
[0] = 's';
2298 setbitn(SB_SUB_KEY
, sparms
->keys
.bitmap
);
2299 ps_global
->mangled_screen
= 1;
2301 sparms
->keys
.menu
->keys
[SB_EXIT_KEY
].bind
.cmd
= MC_EXITQUERY
;
2303 q_status_message(SM_ORDER
, 0, 1, LISTMODE_GRIPE
);
2306 q_status_message(SM_ORDER
, 0, 4, _("Already in List Mode"));
2309 q_status_message(SM_ORDER
, 0, 4,
2310 _("No Folders! Can't enter List Mode"));
2315 /*--------- Visit parent directory -----------*/
2317 if(folder_lister_parent(FPROC(sparms
)->fs
,
2318 (sparms
->text
.handles
)
2319 ? sparms
->text
.handles
->h
.f
.context
2320 : FPROC(sparms
)->fs
->context
,
2321 (sparms
->text
.handles
)
2322 ? sparms
->text
.handles
->h
.f
.index
: -1, 0))
2323 rv
= 1; /* leave scrolltool to rebuild screen */
2328 /*--------- Open the selected folder -----------*/
2330 if(sparms
->text
.handles
2331 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
)))
2332 rv
= folder_lister_finish(sparms
, sparms
->text
.handles
->h
.f
.context
,
2333 sparms
->text
.handles
->h
.f
.index
);
2335 q_status_message(SM_ORDER
, 0, 4,
2336 _("No Folders! Nothing to View"));
2341 /*--------- Export the selected folder -----------*/
2343 folder_export(sparms
);
2347 /*--------- Import the selected folder -----------*/
2350 CONTEXT_S
*cntxt
= (sparms
->text
.handles
)
2351 ? sparms
->text
.handles
->h
.f
.context
2352 : FPROC(sparms
)->fs
->context
;
2353 char new_file
[2*MAXFOLDER
+10];
2358 r
= folder_import(sparms
, new_file
, sizeof(new_file
));
2360 if(r
&& (cntxt
->use
& CNTXT_INCMNG
|| context_isambig(new_file
))){
2361 rv
= 1; /* rebuild display! */
2362 FPROC(sparms
)->fs
->context
= cntxt
;
2363 if(strlen(new_file
) < MAXFOLDER
- 1){
2364 strncpy(FPROC(sparms
)->fs
->first_folder
, new_file
, MAXFOLDER
);
2365 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2369 ps_global
->mangled_footer
++;
2375 /*--------- Return to the Collections Screen -----------*/
2376 case MC_COLLECTIONS
:
2377 FPROC(sparms
)->done
= rv
= 1;
2381 /*--------- QUIT pine -----------*/
2383 ps_global
->next_screen
= quit_screen
;
2384 FPROC(sparms
)->done
= rv
= 1;
2388 /*--------- Compose -----------*/
2390 ps_global
->next_screen
= compose_screen
;
2391 FPROC(sparms
)->done
= rv
= 1;
2395 /*--------- Alt Compose -----------*/
2397 ps_global
->next_screen
= alt_compose_screen
;
2398 FPROC(sparms
)->done
= rv
= 1;
2402 /*--------- Message Index -----------*/
2405 && sp_viewing_a_thread(ps_global
->mail_stream
)
2406 && unview_thread(ps_global
, ps_global
->mail_stream
, ps_global
->msgmap
)){
2407 ps_global
->next_screen
= mail_index_screen
;
2408 ps_global
->view_skipped_index
= 0;
2409 ps_global
->mangled_screen
= 1;
2412 ps_global
->next_screen
= mail_index_screen
;
2413 FPROC(sparms
)->done
= rv
= 1;
2417 /*----------------- Add a new folder name -----------*/
2420 CONTEXT_S
*cntxt
= (sparms
->text
.handles
)
2421 ? sparms
->text
.handles
->h
.f
.context
2422 : FPROC(sparms
)->fs
->context
;
2423 char new_file
[2*MAXFOLDER
+10];
2426 if(NEWS_TEST(cntxt
))
2427 r
= group_subscription(new_file
, sizeof(new_file
), cntxt
);
2429 r
= add_new_folder(cntxt
, Main
, V_INCOMING_FOLDERS
, new_file
,
2431 FPROC(sparms
)->fs
->cache_streamp
2432 ? *FPROC(sparms
)->fs
->cache_streamp
: NULL
,
2434 if(ps_global
->prc
&& ps_global
->prc
->outstanding_pinerc_changes
)
2435 write_pinerc(ps_global
, Main
, WRP_NONE
);
2438 if(r
&& (cntxt
->use
& CNTXT_INCMNG
|| context_isambig(new_file
))){
2439 rv
= 1; /* rebuild display! */
2440 FPROC(sparms
)->fs
->context
= cntxt
;
2441 if(strlen(new_file
) < MAXFOLDER
- 1){
2442 strncpy(FPROC(sparms
)->fs
->first_folder
, new_file
, MAXFOLDER
);
2443 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2447 ps_global
->mangled_footer
++;
2453 /*------ Type in new folder name, e.g., for save ----*/
2455 rv
= folder_lister_addmanually(sparms
);
2459 /*--------------- Rename folder ----------------*/
2460 case MC_RENAMEFLDR
:
2461 if(sparms
->text
.handles
2462 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
))){
2463 char new_file
[MAXFOLDER
+1];
2466 r
= rename_folder(sparms
->text
.handles
->h
.f
.context
,
2467 sparms
->text
.handles
->h
.f
.index
, new_file
,
2469 FPROC(sparms
)->fs
->cache_streamp
2470 ? *FPROC(sparms
)->fs
->cache_streamp
: NULL
);
2473 /* repaint, placing cursor on new folder! */
2475 if(context_isambig(new_file
)){
2476 FPROC(sparms
)->fs
->context
2477 = sparms
->text
.handles
->h
.f
.context
;
2478 if(strlen(new_file
) < MAXFOLDER
- 1){
2479 strncpy(FPROC(sparms
)->fs
->first_folder
, new_file
, MAXFOLDER
);
2480 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2485 ps_global
->mangled_footer
++;
2488 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
2489 _("Empty folder collection. No folder to rename!"));
2494 /*-------------- Delete --------------------*/
2496 if(!(sparms
->text
.handles
2497 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
)))){
2498 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
2499 _("Empty folder collection. No folder to delete!"));
2502 char next_folder
[MAILTMPLEN
+1];
2504 next_folder
[0] = '\0';
2505 if(delete_folder(sparms
->text
.handles
->h
.f
.context
,
2506 sparms
->text
.handles
->h
.f
.index
,
2507 next_folder
, sizeof(next_folder
),
2508 FPROC(sparms
)->fs
->cache_streamp
2509 && *FPROC(sparms
)->fs
->cache_streamp
2510 ? FPROC(sparms
)->fs
->cache_streamp
: NULL
)){
2512 /* repaint, placing cursor on adjacent folder! */
2514 if(next_folder
[0] && strlen(next_folder
) < MAXFOLDER
- 1){
2515 strncpy(FPROC(sparms
)->fs
->first_folder
, next_folder
, MAXFOLDER
);
2516 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2519 sparms
->text
.handles
->h
.f
.context
->use
&= ~CNTXT_ZOOM
;
2522 ps_global
->mangled_footer
++;
2528 /*----------------- Shuffle incoming folder list -----------*/
2531 CONTEXT_S
*cntxt
= (sparms
->text
.handles
)
2532 ? sparms
->text
.handles
->h
.f
.context
: NULL
;
2534 if(!(cntxt
&& cntxt
->use
& CNTXT_INCMNG
))
2535 q_status_message(SM_ORDER
, 0, 4,
2536 _("May only shuffle Incoming-Folders."));
2537 else if(folder_total(FOLDERS(cntxt
)) == 0)
2538 q_status_message(SM_ORDER
, 0, 4,
2539 _("No folders to shuffle."));
2540 else if(folder_total(FOLDERS(cntxt
)) < 2)
2541 q_status_message(SM_ORDER
, 0, 4,
2542 _("Shuffle only makes sense with more than one folder."));
2544 if(FPROC(sparms
) && FPROC(sparms
)->fs
&&
2545 FPROC(sparms
)->fs
&& sparms
->text
.handles
&&
2546 sparms
->text
.handles
->h
.f
.index
>= 0 &&
2547 sparms
->text
.handles
->h
.f
.index
<
2548 folder_total(FOLDERS(cntxt
))){
2549 strncpy(FPROC(sparms
)->fs
->first_folder
,
2550 FLDR_NAME(folder_entry(sparms
->text
.handles
->h
.f
.index
,
2551 FOLDERS(cntxt
))), MAXFOLDER
);
2552 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2555 rv
= shuffle_incoming_folders(cntxt
,
2556 sparms
->text
.handles
->h
.f
.index
);
2563 /*-------------- Goto Folder Prompt --------------------*/
2567 CONTEXT_S
*c
= (sparms
->text
.handles
)
2568 ? sparms
->text
.handles
->h
.f
.context
2569 : FPROC(sparms
)->fs
->context
;
2570 char *new_fold
= broach_folder(-FOOTER_ROWS(ps_global
), 0, ¬realinbox
, &c
);
2572 if(ps_global
&& ps_global
->ttyo
){
2573 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
2574 ps_global
->mangled_footer
= 1;
2577 if(new_fold
&& do_broach_folder(new_fold
, c
, NULL
, notrealinbox
? 0L : DB_INBOXWOCNTXT
) > 0){
2578 ps_global
->next_screen
= mail_index_screen
;
2579 FPROC(sparms
)->done
= rv
= 1;
2582 ps_global
->mangled_footer
= 1;
2584 if((c
= ((sparms
->text
.handles
)
2585 ? sparms
->text
.handles
->h
.f
.context
2586 : FPROC(sparms
)->fs
->context
))->dir
->status
& CNTXT_NOFIND
)
2587 refresh_folder_list(c
, FPROC(sparms
)->fs
->no_dirs
, TRUE
, FPROC(sparms
)->fs
->cache_streamp
);
2593 /*------------- Print list of folders ---------*/
2595 print_folders(FPROC(sparms
));
2596 ps_global
->mangled_footer
++;
2600 /*----- Select the current folder, or toggle checkbox -----*/
2602 /*---------- Select set of folders ----------*/
2604 if(sparms
->text
.handles
2605 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
))){
2606 if(cmd
== MC_SELCUR
){
2607 rv
= folder_select_toggle(sparms
->text
.handles
->h
.f
.context
,
2608 sparms
->text
.handles
->h
.f
.index
,
2609 (NEWS_TEST(sparms
->text
.handles
->h
.f
.context
)
2610 && FPROC(sparms
)->fs
->list_cntxt
)
2611 ? ng_scroll_edit
: folder_select_update
);
2612 if(!rv
) ps_global
->mangled_screen
= 1;
2615 switch(folder_select(ps_global
,
2616 sparms
->text
.handles
->h
.f
.context
,
2617 sparms
->text
.handles
->h
.f
.index
)){
2619 rv
= 1; /* rebuild screen */
2623 ps_global
->mangled_screen
++;
2627 if((sparms
->text
.handles
->h
.f
.context
->use
& CNTXT_ZOOM
)
2628 && !selected_folders(sparms
->text
.handles
->h
.f
.context
)){
2629 sparms
->text
.handles
->h
.f
.context
->use
&= ~CNTXT_ZOOM
;
2630 rv
= 1; /* make sure to redraw */
2633 if(rv
){ /* remember where to start */
2636 FPROC(sparms
)->fs
->context
= sparms
->text
.handles
->h
.f
.context
;
2637 if((fp
= folder_entry(sparms
->text
.handles
->h
.f
.index
,
2638 FOLDERS(sparms
->text
.handles
->h
.f
.context
))) != NULL
){
2639 if(strlen(FLDR_NAME(fp
)) < MAXFOLDER
- 1){
2640 strncpy(FPROC(sparms
)->fs
->first_folder
, FLDR_NAME(fp
), MAXFOLDER
);
2641 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2647 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
2648 _("Empty folder collection. No folder to select!"));
2653 /*---------- Display folders ----------*/
2655 if(sparms
->text
.handles
2656 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
))){
2660 if((n
= selected_folders(sparms
->text
.handles
->h
.f
.context
)) != 0){
2661 if(sparms
->text
.handles
->h
.f
.context
->use
& CNTXT_ZOOM
){
2662 sparms
->text
.handles
->h
.f
.context
->use
&= ~CNTXT_ZOOM
;
2663 q_status_message(SM_ORDER
, 0, 3,
2664 _("Folder List Zoom mode is now off"));
2667 q_status_message1(SM_ORDER
, 0, 3,
2668 _("In Zoomed list of %s folders. Use \"Z\" to restore regular list"),
2670 sparms
->text
.handles
->h
.f
.context
->use
|= CNTXT_ZOOM
;
2673 /* exit scrolltool to rebuild screen */
2676 /* Set where to start after it's rebuilt */
2677 FPROC(sparms
)->fs
->context
= sparms
->text
.handles
->h
.f
.context
;
2678 FPROC(sparms
)->fs
->first_folder
[0] = '\0';
2679 if((fp
= folder_entry(sparms
->text
.handles
->h
.f
.index
,
2680 FOLDERS(sparms
->text
.handles
->h
.f
.context
)))
2681 && !((sparms
->text
.handles
->h
.f
.context
->use
& CNTXT_ZOOM
)
2683 && strlen(FLDR_NAME(fp
)) < MAXFOLDER
- 1){
2684 strncpy(FPROC(sparms
)->fs
->first_folder
, FLDR_NAME(fp
), MAXFOLDER
);
2685 FPROC(sparms
)->fs
->first_folder
[MAXFOLDER
-1] = '\0';
2689 q_status_message(SM_ORDER
, 0, 3,
2690 _("No selected folders to Zoom on"));
2693 q_status_message(SM_ORDER
, 0, 4, _("No Folders to Zoom on!"));
2697 /*----- Ask user to abandon selection before exiting -----*/
2699 if(sparms
->text
.handles
2700 && FOLDERS(sparms
->text
.handles
->h
.f
.context
)){
2704 folder_n
= folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
));
2706 for(i
= 0; i
< folder_n
; i
++){
2707 fp
= folder_entry(i
, FOLDERS(sparms
->text
.handles
->h
.f
.context
));
2712 if(i
< folder_n
/* some selections have been made */
2713 && want_to(_("Really abandon your selections "),
2714 'y', 'x', NO_HELP
, WT_NORM
) != 'y'){
2721 /*------------New Msg command --------------*/
2724 * Derived from code provided by
2725 * Rostislav Neplokh neplokh@andrew.cmu.edu and
2726 * Robert Siemborski (rjs3@andrew).
2728 if(sparms
->text
.handles
2729 && folder_total(FOLDERS(sparms
->text
.handles
->h
.f
.context
))){
2732 folder
= folder_entry(sparms
->text
.handles
->h
.f
.index
,
2733 FOLDERS(sparms
->text
.handles
->h
.f
.context
));
2736 strncpy(tmp_output
, _("Invalid Folder Name"), sizeof(tmp_output
)-1);
2737 tmp_output
[sizeof(tmp_output
)-1] = '\0';
2739 else if(folder
->isdir
&& !folder
->isfolder
){
2740 snprintf(tmp_output
, sizeof(tmp_output
), _("\"%s\" is a directory"), folder
->name
);
2743 char mailbox_name
[MAXPATH
+1];
2744 unsigned long tot
, rec
;
2747 context_apply(mailbox_name
,
2748 sparms
->text
.handles
->h
.f
.context
,
2749 folder
->name
, MAXPATH
+1);
2751 we_cancel
= busy_cue(NULL
, NULL
, 1);
2753 if(get_recent_in_folder(mailbox_name
, &rec
, NULL
, &tot
, NULL
))
2754 snprintf(tmp_output
, sizeof(tmp_output
),
2755 _("%lu total message%s, %lu of them recent"),
2756 tot
, plural(tot
), rec
);
2758 snprintf(tmp_output
, sizeof(tmp_output
),
2759 _("%s: Trouble checking for recent mail"), folder
->name
);
2762 cancel_busy_cue(-1);
2766 strncpy(tmp_output
, _("No folder to check! Can't get recent info"),
2767 sizeof(tmp_output
)-1);
2768 tmp_output
[sizeof(tmp_output
)-1] = '\0';
2771 q_status_message(SM_ORDER
, 0, 3, tmp_output
);
2775 /*--------------- Invalid Command --------------*/
2777 q_status_message1(SM_ORDER
, 0, 2, "fix this: cmd = %s", comatose(cmd
));
2786 folder_lister_clickclick(SCROLL_S
*sparms
)
2788 if(!FPROC(sparms
)->fs
->list_cntxt
)
2789 return(folder_lister_choice(sparms
));
2791 return(folder_processor(MC_SELCUR
, ps_global
->msgmap
, sparms
));
2795 folder_lister_choice(SCROLL_S
*sparms
)
2797 int rv
= 0, empty
= 0;
2798 int index
= (sparms
->text
.handles
)
2799 ? sparms
->text
.handles
->h
.f
.index
: 0;
2800 CONTEXT_S
*cntxt
= (sparms
->text
.handles
)
2801 ? sparms
->text
.handles
->h
.f
.context
: NULL
;
2805 FPROC(sparms
)->fs
->context
= cntxt
;
2807 if(!LUU_YES(cntxt
->update
)){
2808 cntxt
->update
= LUU_INIT
;
2809 refresh_folder_list(cntxt
, FPROC(sparms
)->fs
->no_dirs
, TRUE
,
2810 FPROC(sparms
)->fs
->cache_streamp
);
2811 if(!LUU_YES(cntxt
->update
))
2812 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Collection not updated"));
2819 if(index
< 0 || (cntxt
->dir
->status
& CNTXT_NOFIND
)){
2820 rv
= 1; /* leave scrolltool to rebuild screen */
2821 FPROC(sparms
)->fs
->context
= cntxt
;
2822 FPROC(sparms
)->fs
->first_folder
[0] = '\0';
2824 else if(folder_total(FOLDERS(cntxt
))){
2825 if(folder_lister_select(FPROC(sparms
)->fs
, cntxt
, index
,
2826 sparms
->text
.handles
?
2827 sparms
->text
.handles
->is_dual_do_open
: 0)){
2828 rv
= 1; /* leave scrolltool to rebuild screen */
2830 else if(FPROC(sparms
)->fs
->list_cntxt
== cntxt
){
2831 int n
= 0, i
, folder_n
;
2833 STRLIST_S
*sl
= NULL
, **slp
;
2835 /* Scan folder list for selected items */
2836 folder_n
= folder_total(FOLDERS(cntxt
));
2838 for(i
= 0; i
< folder_n
; i
++){
2839 fp
= folder_entry(i
, FOLDERS(cntxt
));
2842 if((*FPROC(sparms
)->fs
->f
.valid
)(fp
,
2843 FPROC(sparms
)->fs
)){
2844 *slp
= new_strlist(NULL
);
2845 (*slp
)->name
= folder_lister_fullname(
2846 FPROC(sparms
)->fs
, FLDR_NAME(fp
));
2848 slp
= &(*slp
)->next
;
2857 if((FPROC(sparms
)->rv
= sl
) != NULL
)
2858 FPROC(sparms
)->done
= rv
= 1;
2860 q_status_message(SM_ORDER
, 0, 1, LISTMODE_GRIPE
);
2863 rv
= folder_lister_finish(sparms
, cntxt
, index
);
2872 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Empty folder list!"));
2879 folder_lister_finish(SCROLL_S
*sparms
, CONTEXT_S
*cntxt
, int index
)
2881 FOLDER_S
*f
= folder_entry(index
, FOLDERS(cntxt
));
2884 if((*FPROC(sparms
)->fs
->f
.valid
)(f
, FPROC(sparms
)->fs
)){
2886 * Package up the selected folder names and return...
2888 FPROC(sparms
)->fs
->context
= cntxt
;
2889 FPROC(sparms
)->rv
= new_strlist(NULL
);
2890 FPROC(sparms
)->rv
->name
= folder_lister_fullname(FPROC(sparms
)->fs
,
2892 FPROC(sparms
)->done
= rv
= 1;
2900 * This is so that when you Save and use ^T to go to the folder list, and
2901 * you're in a directory with no folders, you have a way to add a new
2902 * folder there. The add actually gets done by the caller. This is just a
2903 * way to let the user type in the name.
2906 folder_lister_addmanually(SCROLL_S
*sparms
)
2908 int rc
, flags
= OE_APPEND_CURRENT
, cnt
= 0, rv
= 0;
2909 char addname
[MAXFOLDER
+1];
2911 CONTEXT_S
*cntxt
= (sparms
->text
.handles
)
2912 ? sparms
->text
.handles
->h
.f
.context
2913 : FPROC(sparms
)->fs
->context
;
2916 * Get the foldername from the user.
2921 rc
= optionally_enter(addname
, -FOOTER_ROWS(ps_global
), 0,
2922 sizeof(addname
), _("Name of new folder : "),
2923 NULL
, help
, &flags
);
2924 removing_leading_and_trailing_white_space(addname
);
2927 help
= (help
== NO_HELP
) ? h_save_addman
: NO_HELP
;
2931 if(F_OFF(F_ENABLE_DOT_FOLDERS
,ps_global
) && *addname
== '.'){
2933 q_status_message(SM_ORDER
,3,3,
2934 _("Folder name can't begin with dot"));
2936 q_status_message1(SM_ORDER
,3,3,
2937 _("Config feature \"%s\" enables names beginning with dot"),
2938 pretty_feature_name(feature_list_name(F_ENABLE_DOT_FOLDERS
), -1));
2940 display_message(NO_OP_COMMAND
);
2943 else if(!strucmp(addname
, ps_global
->inbox_name
)){
2944 q_status_message1(SM_ORDER
, 3, 3,
2945 _("Can't add folder named %s"),
2946 ps_global
->inbox_name
);
2955 FPROC(sparms
)->fs
->context
= cntxt
;
2956 FPROC(sparms
)->rv
= new_strlist(NULL
);
2957 FPROC(sparms
)->rv
->name
= folder_lister_fullname(FPROC(sparms
)->fs
,
2959 FPROC(sparms
)->done
= rv
= 1;
2967 folder_lister_km_manager(SCROLL_S
*sparms
, int handle_hidden
)
2971 /* if we're "in" a sub-directory, offer way out */
2972 if((sparms
->text
.handles
)
2973 ? sparms
->text
.handles
->h
.f
.context
->dir
->prev
2974 : FPROC(sparms
)->fs
->context
->dir
->prev
){
2977 * Leave the command characters alone and just change
2978 * the labels and the bind.cmd for KM_COL_KEY.
2979 * Also, leave KM_MAIN_KEY alone instead of trying to
2980 * turn it off in the else clause when it is redundant.
2982 sparms
->keys
.menu
->keys
[KM_COL_KEY
].label
= N_("ParentDir");
2983 sparms
->keys
.menu
->keys
[KM_COL_KEY
].bind
.cmd
= MC_PARENT
;
2985 else if((FPROC(sparms
)->fs
->context
->next
2986 || FPROC(sparms
)->fs
->context
->prev
)
2987 && !FPROC(sparms
)->fs
->combined_view
){
2988 sparms
->keys
.menu
->keys
[KM_COL_KEY
].label
= N_("ClctnList");
2989 sparms
->keys
.menu
->keys
[KM_COL_KEY
].bind
.cmd
= MC_EXIT
;
2992 sparms
->keys
.menu
->keys
[KM_COL_KEY
].label
= N_("Main Menu");
2993 sparms
->keys
.menu
->keys
[KM_COL_KEY
].bind
.cmd
= MC_MAIN
;
2996 if(F_OFF(F_ENABLE_AGG_OPS
,ps_global
)){
2997 clrbitn(KM_ZOOM_KEY
, sparms
->keys
.bitmap
);
2998 clrbitn(KM_SELECT_KEY
, sparms
->keys
.bitmap
);
2999 clrbitn(KM_SELCUR_KEY
, sparms
->keys
.bitmap
);
3002 if(sparms
->text
.handles
3003 && (fp
= folder_entry(sparms
->text
.handles
->h
.f
.index
,
3004 FOLDERS(sparms
->text
.handles
->h
.f
.context
)))){
3005 if(fp
->isdir
&& !sparms
->text
.handles
->is_dual_do_open
){
3006 sparms
->keys
.menu
->keys
[KM_SEL_KEY
].label
= "[" N_("View Dir") "]";
3007 menu_add_binding(sparms
->keys
.menu
, 'v', MC_CHOICE
);
3008 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3009 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3010 setbitn(KM_SEL_KEY
, sparms
->keys
.bitmap
);
3011 clrbitn(KM_ALTVIEW_KEY
, sparms
->keys
.bitmap
);
3012 clrbitn(KM_EXPORT_KEY
, sparms
->keys
.bitmap
);
3013 clrbitn(KM_IMPORT_KEY
, sparms
->keys
.bitmap
);
3016 sparms
->keys
.menu
->keys
[KM_SEL_KEY
].label
= "[" N_("View Fldr") "]";
3017 menu_add_binding(sparms
->keys
.menu
, 'v', MC_CHOICE
);
3018 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3019 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3020 setbitn(KM_SEL_KEY
, sparms
->keys
.bitmap
);
3021 clrbitn(KM_ALTVIEW_KEY
, sparms
->keys
.bitmap
);
3022 setbitn(KM_EXPORT_KEY
, sparms
->keys
.bitmap
);
3023 setbitn(KM_IMPORT_KEY
, sparms
->keys
.bitmap
);
3026 else if(FPROC(sparms
)->fs
->combined_view
3027 && sparms
->text
.handles
&& sparms
->text
.handles
->h
.f
.context
3028 && !sparms
->text
.handles
->h
.f
.context
->dir
->prev
){
3029 sparms
->keys
.menu
->keys
[KM_SEL_KEY
].label
= "[" N_("View Cltn") "]";
3030 menu_add_binding(sparms
->keys
.menu
, 'v', MC_CHOICE
);
3031 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3032 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3033 setbitn(KM_SEL_KEY
, sparms
->keys
.bitmap
);
3034 clrbitn(KM_ALTVIEW_KEY
, sparms
->keys
.bitmap
);
3035 clrbitn(KM_EXPORT_KEY
, sparms
->keys
.bitmap
);
3036 clrbitn(KM_IMPORT_KEY
, sparms
->keys
.bitmap
);
3039 clrbitn(KM_SEL_KEY
, sparms
->keys
.bitmap
);
3040 clrbitn(KM_ALTVIEW_KEY
, sparms
->keys
.bitmap
);
3041 clrbitn(KM_EXPORT_KEY
, sparms
->keys
.bitmap
);
3042 clrbitn(KM_IMPORT_KEY
, sparms
->keys
.bitmap
);
3045 if((sparms
->text
.handles
&&
3046 sparms
->text
.handles
->h
.f
.context
&&
3047 sparms
->text
.handles
->h
.f
.context
->use
& CNTXT_INCMNG
) ||
3048 (FPROC(sparms
) && FPROC(sparms
)->fs
&&
3049 FPROC(sparms
)->fs
->context
&&
3050 FPROC(sparms
)->fs
->context
->use
& CNTXT_INCMNG
))
3051 setbitn(KM_SHUFFLE_KEY
, sparms
->keys
.bitmap
);
3053 clrbitn(KM_SHUFFLE_KEY
, sparms
->keys
.bitmap
);
3055 if(F_ON(F_TAB_CHK_RECENT
, ps_global
)){
3056 menu_clear_binding(sparms
->keys
.menu
, TAB
);
3057 menu_init_binding(sparms
->keys
.menu
, TAB
, MC_CHK_RECENT
, "Tab",
3058 /* TRANSLATORS: New Messages */
3059 N_("NewMsgs"), KM_RECENT_KEY
);
3060 setbitn(KM_RECENT_KEY
, sparms
->keys
.bitmap
);
3063 menu_clear_binding(sparms
->keys
.menu
, TAB
);
3064 menu_add_binding(sparms
->keys
.menu
, TAB
, MC_NEXT_HANDLE
);
3065 clrbitn(KM_RECENT_KEY
, sparms
->keys
.bitmap
);
3068 /* May have to "undo" what scrolltool "did" */
3069 if(F_ON(F_ARROW_NAV
, ps_global
)){
3070 if(F_ON(F_RELAXED_ARROW_NAV
, ps_global
)){
3071 menu_clear_binding(sparms
->keys
.menu
, KEY_LEFT
);
3072 menu_add_binding(sparms
->keys
.menu
, KEY_LEFT
, MC_PREV_HANDLE
);
3073 menu_clear_binding(sparms
->keys
.menu
, KEY_RIGHT
);
3074 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_NEXT_HANDLE
);
3077 menu_clear_binding(sparms
->keys
.menu
, KEY_UP
);
3078 menu_add_binding(sparms
->keys
.menu
, KEY_UP
, MC_PREV_HANDLE
);
3079 menu_clear_binding(sparms
->keys
.menu
, KEY_DOWN
);
3080 menu_add_binding(sparms
->keys
.menu
, KEY_DOWN
, MC_NEXT_HANDLE
);
3087 folder_lister_km_sel_manager(SCROLL_S
*sparms
, int handle_hidden
)
3091 /* if we're "in" a sub-directory, offer way out */
3092 if((sparms
->text
.handles
)
3093 ? sparms
->text
.handles
->h
.f
.context
->dir
->prev
3094 : FPROC(sparms
)->fs
->context
->dir
->prev
){
3095 sparms
->keys
.menu
->keys
[FC_COL_KEY
].name
= "<";
3096 /* TRANSLATORS: go to parent directory one level up */
3097 sparms
->keys
.menu
->keys
[FC_COL_KEY
].label
= N_("ParentDir");
3098 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.cmd
= MC_PARENT
;
3099 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[0] = '<';
3100 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[1] = ',';
3101 if(F_ON(F_ARROW_NAV
,ps_global
)){
3102 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.nch
= 3;
3103 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[2] = KEY_LEFT
;
3106 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.nch
= 2;
3108 /* ExitSelect in position 1 */
3109 setbitn(FC_EXIT_KEY
, sparms
->keys
.bitmap
);
3111 else if((FPROC(sparms
)->fs
->context
->next
3112 || FPROC(sparms
)->fs
->context
->prev
)
3113 && !FPROC(sparms
)->fs
->combined_view
){
3114 sparms
->keys
.menu
->keys
[FC_COL_KEY
].name
= "<";
3115 /* TRANSLATORS: go to Collection List */
3116 sparms
->keys
.menu
->keys
[FC_COL_KEY
].label
= N_("ClctnList");
3117 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.cmd
= MC_COLLECTIONS
;
3118 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[0] = '<';
3119 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[1] = ',';
3120 if(F_ON(F_ARROW_NAV
,ps_global
)){
3121 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.nch
= 3;
3122 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[2] = KEY_LEFT
;
3125 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.nch
= 2;
3127 /* ExitSelect in position 1 */
3128 setbitn(FC_EXIT_KEY
, sparms
->keys
.bitmap
);
3130 else if(FPROC(sparms
)->fs
->combined_view
){
3132 * This can't be a menu_init_binding() because we don't want
3133 * to remove the ExitSelect command in position FC_EXIT_KEY.
3134 * We just turn it off until we need it again.
3136 sparms
->keys
.menu
->keys
[FC_COL_KEY
].name
= "E";
3137 sparms
->keys
.menu
->keys
[FC_COL_KEY
].label
= N_("ExitSelect");
3138 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.cmd
= MC_EXIT
;
3139 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.nch
= 1;
3140 sparms
->keys
.menu
->keys
[FC_COL_KEY
].bind
.ch
[0] = 'e';
3142 /* turn off ExitSelect in position 1, it's in 2 now */
3143 clrbitn(FC_EXIT_KEY
, sparms
->keys
.bitmap
);
3146 /* clean up per-entry bindings */
3147 clrbitn(FC_SEL_KEY
, sparms
->keys
.bitmap
);
3148 clrbitn(FC_ALTSEL_KEY
, sparms
->keys
.bitmap
);
3149 menu_clear_binding(sparms
->keys
.menu
, ctrl('M'));
3150 menu_clear_binding(sparms
->keys
.menu
, ctrl('J'));
3151 menu_clear_binding(sparms
->keys
.menu
, '>');
3152 menu_clear_binding(sparms
->keys
.menu
, '.');
3153 menu_clear_binding(sparms
->keys
.menu
, 's');
3154 if(F_ON(F_ARROW_NAV
,ps_global
))
3155 menu_clear_binding(sparms
->keys
.menu
, KEY_RIGHT
);
3157 /* and then re-assign them as needed */
3158 if(sparms
->text
.handles
3159 && (fp
= folder_entry(sparms
->text
.handles
->h
.f
.index
,
3160 FOLDERS(sparms
->text
.handles
->h
.f
.context
)))){
3161 setbitn(FC_SEL_KEY
, sparms
->keys
.bitmap
);
3162 sparms
->keys
.menu
->keys
[FC_SEL_KEY
].name
= ">";
3163 menu_add_binding(sparms
->keys
.menu
, '>', MC_CHOICE
);
3164 menu_add_binding(sparms
->keys
.menu
, '.', MC_CHOICE
);
3165 if(F_ON(F_ARROW_NAV
,ps_global
))
3166 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_CHOICE
);
3167 if(fp
->isdir
&& !sparms
->text
.handles
->is_dual_do_open
){
3168 sparms
->keys
.menu
->keys
[KM_SEL_KEY
].label
= "[" N_("View Dir") "]";
3169 menu_add_binding(sparms
->keys
.menu
, 'v', MC_CHOICE
);
3170 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3171 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3172 setbitn(KM_SEL_KEY
, sparms
->keys
.bitmap
);
3173 clrbitn(KM_ALTVIEW_KEY
, sparms
->keys
.bitmap
);
3174 clrbitn(KM_EXPORT_KEY
, sparms
->keys
.bitmap
);
3175 clrbitn(KM_IMPORT_KEY
, sparms
->keys
.bitmap
);
3178 sparms
->keys
.menu
->keys
[FC_SEL_KEY
].name
= "S";
3179 sparms
->keys
.menu
->keys
[FC_SEL_KEY
].label
= "[" N_("Select") "]";
3181 menu_add_binding(sparms
->keys
.menu
, 's', MC_CHOICE
);
3182 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3183 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3186 if(F_ON(F_ARROW_NAV
,ps_global
))
3187 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_CHOICE
);
3189 else if(FPROC(sparms
)->fs
->combined_view
3190 && sparms
->text
.handles
&& sparms
->text
.handles
->h
.f
.context
3191 && !sparms
->text
.handles
->h
.f
.context
->dir
->prev
){
3192 setbitn(FC_SEL_KEY
, sparms
->keys
.bitmap
);
3193 sparms
->keys
.menu
->keys
[FC_SEL_KEY
].name
= ">";
3194 sparms
->keys
.menu
->keys
[FC_SEL_KEY
].label
= "[" N_("View Cltn") "]";
3195 menu_add_binding(sparms
->keys
.menu
, '>', MC_CHOICE
);
3196 menu_add_binding(sparms
->keys
.menu
, '.', MC_CHOICE
);
3197 if(F_ON(F_ARROW_NAV
,ps_global
))
3198 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_CHOICE
);
3200 menu_add_binding(sparms
->keys
.menu
, ctrl('M'), MC_CHOICE
);
3201 menu_add_binding(sparms
->keys
.menu
, ctrl('J'), MC_CHOICE
);
3204 /* May have to "undo" what scrolltool "did" */
3205 if(F_ON(F_ARROW_NAV
, ps_global
)){
3206 if(F_ON(F_RELAXED_ARROW_NAV
, ps_global
)){
3207 menu_clear_binding(sparms
->keys
.menu
, KEY_LEFT
);
3208 menu_add_binding(sparms
->keys
.menu
, KEY_LEFT
, MC_PREV_HANDLE
);
3209 menu_clear_binding(sparms
->keys
.menu
, KEY_RIGHT
);
3210 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_NEXT_HANDLE
);
3213 menu_clear_binding(sparms
->keys
.menu
, KEY_UP
);
3214 menu_add_binding(sparms
->keys
.menu
, KEY_UP
, MC_PREV_HANDLE
);
3215 menu_clear_binding(sparms
->keys
.menu
, KEY_DOWN
);
3216 menu_add_binding(sparms
->keys
.menu
, KEY_DOWN
, MC_NEXT_HANDLE
);
3223 folder_lister_km_sub_manager(SCROLL_S
*sparms
, int handle_hidden
)
3226 * Folder_processor() also modifies the keymenu.
3228 if(FPROC(sparms
)->fs
->list_cntxt
){
3229 clrbitn(SB_LIST_KEY
, sparms
->keys
.bitmap
);
3230 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].name
= "X";
3231 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].label
= "[" N_("Set/Unset") "]";
3232 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].bind
.cmd
= MC_SELCUR
;
3233 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].bind
.ch
[0] = 'x';
3236 clrbitn(SB_SUB_KEY
, sparms
->keys
.bitmap
);
3237 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].name
= "S";
3238 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].label
= "[" N_("Subscribe") "]";
3239 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].bind
.cmd
= MC_CHOICE
;
3240 sparms
->keys
.menu
->keys
[SB_SEL_KEY
].bind
.ch
[0] = 's';
3243 /* May have to "undo" what scrolltool "did" */
3244 if(F_ON(F_ARROW_NAV
, ps_global
)){
3245 if(F_ON(F_RELAXED_ARROW_NAV
, ps_global
)){
3246 menu_clear_binding(sparms
->keys
.menu
, KEY_LEFT
);
3247 menu_add_binding(sparms
->keys
.menu
, KEY_LEFT
, MC_PREV_HANDLE
);
3248 menu_clear_binding(sparms
->keys
.menu
, KEY_RIGHT
);
3249 menu_add_binding(sparms
->keys
.menu
, KEY_RIGHT
, MC_NEXT_HANDLE
);
3252 menu_clear_binding(sparms
->keys
.menu
, KEY_UP
);
3253 menu_add_binding(sparms
->keys
.menu
, KEY_UP
, MC_PREV_HANDLE
);
3254 menu_clear_binding(sparms
->keys
.menu
, KEY_DOWN
);
3255 menu_add_binding(sparms
->keys
.menu
, KEY_DOWN
, MC_NEXT_HANDLE
);
3263 folder_select(struct pine
*ps
, CONTEXT_S
*context
, int cur_index
)
3265 int i
, j
, n
, total
, old_tot
, diff
,
3266 q
= 0, rv
= 0, narrow
= 0;
3267 HelpType help
= NO_HELP
;
3270 static ESCKEY_S self_opts2
[] = {
3271 /* TRANSLATORS: keymenu descriptions, select all folders, current folder, select
3272 based on folder properties, or select based on text contents in folders */
3273 {'a', 'a', "A", N_("select All")},
3274 {'c', 'c', "C", N_("select Cur")},
3275 {'p', 'p', "P", N_("Properties")},
3276 {'t', 't', "T", N_("Text")},
3277 {-1, 0, NULL
, NULL
},
3280 extern ESCKEY_S sel_opts1
[];
3281 extern char *sel_pmt2
;
3284 f
= folder_entry(cur_index
, FOLDERS(context
));
3286 sel_opts
= self_opts2
;
3287 if((old_tot
= selected_folders(context
)) != 0){
3288 sel_opts1
[1].label
= f
->selected
? N_("unselect Cur") : N_("select Cur");
3289 sel_opts
+= 2; /* disable extra options */
3290 switch(q
= radio_buttons(SEL_ALTER_PMT
, -FOOTER_ROWS(ps_global
),
3291 sel_opts1
, 'c', 'x', help
, RB_NORM
)){
3292 case 'f' : /* flip selection */
3293 n
= folder_total(FOLDERS(context
));
3294 for(total
= i
= 0; i
< n
; i
++)
3295 if((f
= folder_entry(i
, FOLDERS(context
))) != NULL
)
3296 f
->selected
= !f
->selected
;
3298 return(1); /* repaint */
3300 case 'n' : /* narrow selection */
3302 case 'b' : /* broaden selection */
3303 q
= 0; /* but don't offer criteria prompt */
3304 if(context
->use
& CNTXT_INCMNG
){
3305 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3306 _("Select \"%s\" not supported in Incoming Folders"),
3307 narrow
? "Narrow" : "Broaden");
3313 case 'c' : /* Un/Select Current */
3314 case 'a' : /* Unselect All */
3315 case 'x' : /* cancel */
3319 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3320 _("Unsupported Select option"));
3325 if(context
->use
& CNTXT_INCMNG
&& F_ON(F_ENABLE_INCOMING_CHECKING
, ps_global
)){
3326 if(F_ON(F_INCOMING_CHECKING_RECENT
, ps_global
)){
3327 self_opts2
[N_RECENT
].ch
= 'r';
3328 self_opts2
[N_RECENT
].rval
= 'r';
3329 self_opts2
[N_RECENT
].name
= "R";
3330 self_opts2
[N_RECENT
].label
= N_("Recent");
3333 self_opts2
[N_RECENT
].ch
= 'u';
3334 self_opts2
[N_RECENT
].rval
= 'u';
3335 self_opts2
[N_RECENT
].name
= "U";
3336 self_opts2
[N_RECENT
].label
= N_("Unseen");
3340 self_opts2
[N_RECENT
].ch
= -1;
3341 self_opts2
[N_RECENT
].rval
= 0;
3342 self_opts2
[N_RECENT
].name
= NULL
;
3343 self_opts2
[N_RECENT
].label
= NULL
;
3347 q
= radio_buttons(sel_pmt2
, -FOOTER_ROWS(ps_global
),
3348 sel_opts
, 'c', 'x', help
, RB_NORM
);
3351 * NOTE: See note about MESSAGECACHE "searched" bits above!
3354 case 'x': /* cancel */
3355 cmd_cancelled("Select command");
3358 case 'c' : /* toggle current's selected state */
3359 return(folder_select_toggle(context
, cur_index
, folder_select_update
));
3361 case 'a' : /* select/unselect all */
3362 n
= folder_total(FOLDERS(context
));
3363 for(total
= i
= 0; i
< n
; i
++)
3364 folder_entry(i
, FOLDERS(context
))->selected
= old_tot
== 0;
3366 q_status_message4(SM_ORDER
, 0, 2,
3367 "%s%s folder%s %sselected",
3368 old_tot
? "" : "All ",
3369 comatose(old_tot
? old_tot
: n
),
3370 plural(old_tot
? old_tot
: n
), old_tot
? "UN" : "");
3373 case 't' : /* Text */
3374 if(!folder_select_text(ps
, context
, narrow
))
3379 case 'p' : /* Properties */
3380 if(!folder_select_props(ps
, context
, narrow
))
3386 n
= folder_total(FOLDERS(context
));
3387 for(i
= 0; i
< n
; i
++){
3388 f
= folder_entry(i
, FOLDERS(context
));
3389 if(f
->unseen_valid
&& f
->new > 0L)
3396 n
= folder_total(FOLDERS(context
));
3397 for(i
= 0; i
< n
; i
++){
3398 f
= folder_entry(i
, FOLDERS(context
));
3399 if(f
->unseen_valid
&& f
->unseen
> 0L)
3406 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3407 _("Unsupported Select option"));
3414 /* rectify the scanned vs. selected folders */
3415 n
= folder_total(FOLDERS(context
));
3416 for(total
= i
= j
= 0; i
< n
; i
++)
3417 if(folder_entry(i
, FOLDERS(context
))->scanned
)
3421 * Any matches at all? If not, the selected set remains the same.
3422 * Note that when Narrowing, only matches in the intersection will
3423 * show up as scanned. We need to reset i to 0 to erase any already
3424 * selected messages which aren't in the intersection.
3427 for(i
= 0; i
< n
; i
++)
3428 if((f
= folder_entry(i
, FOLDERS(context
))) != NULL
){
3431 f
->selected
= f
->scanned
;
3439 if(!(diff
= (total
= selected_folders(context
)) - old_tot
)){
3441 q_status_message4(SM_ORDER
, 0, 2,
3442 "%s. %s folder%s remain%s selected.",
3443 j
? _("No change resulted")
3444 : _("No messages in intersection"),
3445 comatose(old_tot
), plural(old_tot
),
3446 (old_tot
== 1L) ? "s" : "");
3447 else if(old_tot
&& j
)
3448 q_status_message(SM_ORDER
, 0, 2,
3449 _("No change resulted. Matching folders already selected."));
3451 q_status_message1(SM_ORDER
| SM_DING
, 0, 2,
3452 "Select failed! No %sfolders selected.",
3453 old_tot
? "additional " : "");
3456 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
3457 "Select matched %d folder%s. %s %sfolder%s %sselected.",
3458 (diff
> 0) ? diff
: old_tot
+ diff
,
3459 plural((diff
> 0) ? diff
: old_tot
+ diff
),
3460 comatose((diff
> 0) ? total
: -diff
),
3461 (diff
> 0) ? "total " : "",
3462 plural((diff
> 0) ? total
: -diff
),
3463 (diff
> 0) ? "" : "UN");
3464 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
3465 q_status_message(SM_ORDER
, 0, 2, tmp_20k_buf
);
3468 q_status_message2(SM_ORDER
, 0, 2, "Select matched %s folder%s.",
3469 comatose(diff
), plural(diff
));
3478 folder_lister_select(FSTATE_S
*fs
, CONTEXT_S
*context
, int index
, int is_dual_do_open
)
3482 FOLDER_S
*f
= folder_entry(index
, FOLDERS(context
));
3484 /*--- Entering a directory? ---*/
3485 if(f
->isdir
&& !is_dual_do_open
){
3486 fp
= next_folder_dir(context
, f
->name
, TRUE
, fs
->cache_streamp
);
3488 /* Provide context in new collection header */
3489 fp
->desc
= folder_lister_desc(context
, fp
);
3491 /* Insert new directory into list */
3492 free_folder_list(context
);
3493 fp
->prev
= context
->dir
;
3494 fp
->status
|= CNTXT_SUBDIR
;
3496 q_status_message2(SM_ORDER
, 0, 3, "Now in %sdirectory: %s",
3497 folder_total(FOLDERS(context
))
3498 ? "" : "EMPTY ", fp
->ref
);
3502 rv
= folder_lister_parent(fs
, context
, index
, 1);
3509 folder_lister_parent(FSTATE_S
*fs
, CONTEXT_S
*context
, int index
, int force_parent
)
3514 if(!force_parent
&& (fp
= context
->dir
->prev
)){
3515 char *s
, oldir
[MAILTMPLEN
];
3517 folder_select_preserve(context
);
3519 if((s
= strrindex(context
->dir
->ref
, context
->dir
->delim
)) != NULL
){
3522 u
= strrindex(context
->dir
->ref
, context
->dir
->delim
);
3523 v
= strrindex(context
->dir
->ref
, '}');
3526 strncpy(oldir
, s
+1, sizeof(oldir
)-1);
3527 oldir
[sizeof(oldir
)-1] = '\0';
3532 /* remember current directory for hiliting in new list */
3533 fs
->context
= context
;
3534 if(strlen(oldir
) < MAXFOLDER
- 1){
3535 strncpy(fs
->first_folder
, oldir
, MAXFOLDER
);
3536 fs
->first_folder
[MAXFOLDER
-1] = '\0';
3541 free_fdir(&context
->dir
, 0);
3542 fp
->status
|= CNTXT_NOFIND
;
3546 if(fp
->status
& CNTXT_SUBDIR
)
3547 q_status_message1(SM_ORDER
, 0, 3, _("Now in directory: %s"),
3548 strsquish(tmp_20k_buf
+ 500, SIZEOF_20KBUF
-500, fp
->ref
,
3549 ps_global
->ttyo
->screen_cols
- 22));
3551 q_status_message(SM_ORDER
, 0, 3,
3552 _("Returned to collection's top directory"));
3562 folder_lister_fullname(FSTATE_S
*fs
, char *name
)
3564 if(fs
->context
->dir
->status
& CNTXT_SUBDIR
){
3565 char tmp
[2*MAILTMPLEN
+1], tmp2
[2*MAILTMPLEN
+1], *p
;
3567 if(fs
->context
->dir
->ref
){
3568 snprintf(tmp
, sizeof(tmp
), "%.*s%.*s",
3569 MAILTMPLEN
, /* MAILTMPLEN == sizeof(tmp)/2 */
3570 ((fs
->relative_path
|| (fs
->context
->use
& CNTXT_SAVEDFLT
))
3571 && (p
= strstr(fs
->context
->context
, "%s")) && !*(p
+2)
3572 && !strncmp(fs
->context
->dir
->ref
, fs
->context
->context
,
3573 p
- fs
->context
->context
))
3574 ? fs
->context
->dir
->ref
+ (p
- fs
->context
->context
)
3575 : fs
->context
->dir
->ref
,
3577 tmp
[sizeof(tmp
)-1] = '\0';
3581 * If the applied name is still ambiguous (defined
3582 * that way by the user (i.e., "mail/[]"), then
3583 * we better fix it up...
3585 if(context_isambig(tmp
)
3586 && !fs
->relative_path
3587 && !(fs
->context
->use
& CNTXT_SAVEDFLT
)){
3588 /* if it's in the primary collection, the names relative */
3589 if(fs
->context
->dir
->ref
){ /* MAILTMPLEN = sizeof(tmp)/2 */
3590 if(IS_REMOTE(fs
->context
->context
)
3591 && (p
= strrindex(fs
->context
->context
, '}'))){
3592 snprintf(tmp2
, sizeof(tmp2
), "%.*s%.*s",
3593 (int) MIN(p
- fs
->context
->context
+ 1, sizeof(tmp
)/2),
3594 fs
->context
->context
,
3596 tmp2
[sizeof(tmp2
)-1] = '\0';
3599 build_path(tmp2
, ps_global
->ui
.homedir
, tmp
, sizeof(tmp2
));
3602 (void) context_apply(tmp2
, fs
->context
, tmp
, sizeof(tmp2
));
3604 return(cpystr(tmp2
));
3607 return(cpystr(tmp
));
3610 return(cpystr(name
));
3615 * Export a folder from pine space to user's space. It will still be a regular
3616 * mail folder but it will be in the user's home directory or something like
3620 folder_export(SCROLL_S
*sparms
)
3623 MAILSTREAM
*stream
, *ourstream
= NULL
;
3624 char expanded_file
[MAILTMPLEN
], *p
,
3625 tmp
[MAILTMPLEN
], *fname
, *fullname
= NULL
,
3626 filename
[MAXPATH
+1], full_filename
[MAXPATH
+1],
3627 deefault
[MAXPATH
+1];
3628 int open_inbox
= 0, we_cancel
= 0, width
,
3629 index
= (sparms
&& sparms
->text
.handles
)
3630 ? sparms
->text
.handles
->h
.f
.index
: 0;
3631 CONTEXT_S
*savecntxt
,
3632 *cntxt
= (sparms
&& sparms
->text
.handles
)
3633 ? sparms
->text
.handles
->h
.f
.context
: NULL
;
3634 static HISTORY_S
*history
= NULL
;
3636 dprint((4, "\n - folder export -\n"));
3639 if(folder_total(FOLDERS(cntxt
))){
3640 f
= folder_entry(index
, FOLDERS(cntxt
));
3641 if((*FPROC(sparms
)->fs
->f
.valid
)(f
, FPROC(sparms
)->fs
)){
3642 savecntxt
= FPROC(sparms
)->fs
->context
; /* necessary? */
3643 FPROC(sparms
)->fs
->context
= cntxt
;
3644 strncpy(deefault
, FLDR_NAME(f
), sizeof(deefault
)-1);
3645 deefault
[sizeof(deefault
)-1] = '\0';
3646 fname
= folder_lister_fullname(FPROC(sparms
)->fs
, FLDR_NAME(f
));
3647 FPROC(sparms
)->fs
->context
= savecntxt
;
3650 * We have to allow for INBOX and nicknames in
3651 * the incoming collection. Mimic what happens in
3654 strncpy(expanded_file
, fname
, sizeof(expanded_file
));
3655 expanded_file
[sizeof(expanded_file
)-1] = '\0';
3657 if(strucmp(fname
, ps_global
->inbox_name
) == 0
3658 || strucmp(fname
, ps_global
->VAR_INBOX_PATH
) == 0)
3661 if(!open_inbox
&& cntxt
&& context_isambig(fname
)){
3662 if((p
=folder_is_nick(fname
, FOLDERS(cntxt
), 0)) != NULL
){
3663 strncpy(expanded_file
, p
, sizeof(expanded_file
));
3664 expanded_file
[sizeof(expanded_file
)-1] = '\0';
3666 else if ((cntxt
->use
& CNTXT_INCMNG
)
3667 && (folder_index(fname
, cntxt
, FI_FOLDER
) < 0)
3668 && !is_absolute_path(fname
)){
3669 q_status_message1(SM_ORDER
, 3, 4,
3670 _("Can't find Incoming Folder %s."), fname
);
3676 fullname
= ps_global
->VAR_INBOX_PATH
;
3679 * We don't want to interpret this name in the context
3680 * of the reference string, that was already done
3681 * above in folder_lister_fullname(), just in the
3682 * regular context. We also don't want to lose the
3683 * reference string because we will still be in the
3684 * subdirectory after this operation completes. So
3685 * temporarily zero out the reference.
3689 tmpdir
= (cntxt
? cntxt
->dir
: NULL
);
3691 fullname
= context_apply(tmp
, cntxt
, expanded_file
,
3693 cntxt
->dir
= tmpdir
;
3697 ps_global
->ttyo
? ps_global
->ttyo
->screen_cols
: 80);
3698 stream
= sp_stream_get(fullname
, SP_MATCH
| SP_RO_OK
);
3699 if(!stream
&& fullname
){
3701 * Just using filename and full_filename as convenient
3702 * temporary buffers here.
3704 snprintf(filename
, sizeof(filename
), "Opening \"%s\"",
3705 short_str(fullname
, full_filename
, sizeof(full_filename
),
3708 filename
[sizeof(filename
)-1] = '\0';
3709 we_cancel
= busy_cue(filename
, NULL
, 0);
3710 stream
= pine_mail_open(NULL
, fullname
,
3711 OP_READONLY
|SP_USEPOOL
|SP_TEMPUSE
,
3720 * We have a stream for the folder we want to
3723 if(stream
&& stream
->nmsgs
> 0L){
3725 static ESCKEY_S eopts
[] = {
3726 {ctrl('T'), 10, "^T", N_("To Files")},
3727 {-1, 0, NULL
, NULL
},
3728 {-1, 0, NULL
, NULL
}};
3730 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
3731 eopts
[r
].ch
= ctrl('I');
3733 eopts
[r
].name
= "TAB";
3734 /* TRANSLATORS: Complete is a verb, complete the name of a folder */
3735 eopts
[r
].label
= _("Complete");
3741 full_filename
[0] = '\0';
3743 r
= get_export_filename(ps_global
, filename
, deefault
,
3745 sizeof(filename
)-20, fname
, NULL
,
3747 -FOOTER_ROWS(ps_global
),
3748 GE_IS_EXPORT
| GE_NO_APPEND
, &history
);
3753 cmd_cancelled("Export folder");
3757 q_status_message1(SM_ORDER
, 0, 2,
3758 _("Can't export to file outside of %s"),
3759 ps_global
->VAR_OPER_DIR
);
3767 ps_global
->mm_log_error
= 0;
3770 * Do the creation in standard unix format, so it
3771 * is readable by all.
3773 rplstr(full_filename
, sizeof(full_filename
), 0, "#driver.unix/");
3774 ok
= pine_mail_create(NULL
, full_filename
) != 0L;
3776 * ff points to the original filename, without the
3777 * driver prefix. Only mail_create knows how to
3778 * handle driver prefixes.
3780 ff
= full_filename
+ strlen("#driver.unix/");
3783 if(!ps_global
->mm_log_error
)
3784 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
3785 _("Error creating file"));
3789 MSGNO_S
*tmpmap
= NULL
;
3791 snmsgs
= stream
->nmsgs
;
3792 mn_init(&tmpmap
, snmsgs
);
3793 for(l
= 1L; l
<= snmsgs
; l
++)
3795 mn_set_cur(tmpmap
, l
);
3797 mn_add_cur(tmpmap
, l
);
3799 blank_keymenu(ps_global
->ttyo
->screen_rows
-2, 0);
3800 we_cancel
= busy_cue(_("Copying folder"), NULL
, 0);
3801 l
= save(ps_global
, stream
, NULL
, ff
, tmpmap
, 0);
3808 q_status_message2(SM_ORDER
, 0, 3,
3809 "Folder %s exported to %s",
3812 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3813 _("Error exporting to %s"),
3816 "Error exporting to %s: expected %ld msgs, saved %ld\n",
3817 filename
, snmsgs
, l
));
3823 q_status_message1(SM_ORDER
|SM_DING
, 3, 3,
3824 _("No messages in %s to export"), fname
);
3826 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
3827 _("Can't open folder for exporting"));
3830 fs_give((void **) &fname
);
3833 pine_mail_close(ourstream
);
3838 q_status_message(SM_ORDER
| SM_DING
, 3, 3, _("Empty folder list!"));
3843 * Import a folder from user's space back to pine space.
3844 * We're just importing a regular mail folder, and saving all the messages
3845 * to another folder. It may seem more magical to the user but it isn't.
3846 * The import folder is a local folder, the new one can be remote or whatever.
3848 * add_folder -- return new folder name here
3849 * len -- length of add_folder
3851 * Returns 1 if we may have to redraw screen, 0 otherwise
3854 folder_import(SCROLL_S
*sparms
, char *add_folder
, size_t len
)
3856 MAILSTREAM
*istream
= NULL
;
3858 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1];
3859 static HISTORY_S
*history
= NULL
;
3860 static ESCKEY_S eopts
[] = {
3861 {ctrl('T'), 10, "^T", N_("To Files")},
3862 {-1, 0, NULL
, NULL
},
3863 {-1, 0, NULL
, NULL
}};
3865 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
3866 eopts
[r
].ch
= ctrl('I');
3868 eopts
[r
].name
= "TAB";
3869 eopts
[r
].label
= N_("Complete");
3875 full_filename
[0] = '\0';
3877 /* get a folder to import */
3878 r
= get_export_filename(ps_global
, filename
, NULL
, full_filename
,
3879 sizeof(filename
)-20, "messages", "IMPORT",
3881 -FOOTER_ROWS(ps_global
), GE_IS_IMPORT
, &history
);
3886 cmd_cancelled("Import folder");
3890 q_status_message1(SM_ORDER
, 0, 2,
3891 _("Can't import file outside of %s"),
3892 ps_global
->VAR_OPER_DIR
);
3897 ps_global
->mm_log_error
= 0;
3898 if(full_filename
&& full_filename
[0])
3899 istream
= pine_mail_open(NULL
, full_filename
,
3900 OP_READONLY
| SP_TEMPUSE
, NULL
);
3902 if(istream
&& istream
->nmsgs
> 0L){
3905 char newfolder
[MAILTMPLEN
], nmsgs
[32];
3906 MSGNO_S
*tmpmap
= NULL
;
3907 CONTEXT_S
*cntxt
, *ourcntxt
;
3909 cntxt
= (sparms
&& sparms
->text
.handles
)
3910 ? sparms
->text
.handles
->h
.f
.context
: NULL
;
3912 newfolder
[0] = '\0';
3913 snprintf(nmsgs
, sizeof(nmsgs
), "%s msgs ", comatose(istream
->nmsgs
));
3914 nmsgs
[sizeof(nmsgs
)-1] = '\0';
3917 * Select a folder to save the messages to.
3919 if(save_prompt(ps_global
, &cntxt
, newfolder
, sizeof(newfolder
),
3920 nmsgs
, NULL
, 0L, NULL
, NULL
, NULL
)){
3922 if((cntxt
== ourcntxt
) && newfolder
[0]){
3924 strncpy(add_folder
, newfolder
, len
-1);
3925 add_folder
[len
-1] = '\0';
3926 free_folder_list(cntxt
);
3929 mn_init(&tmpmap
, istream
->nmsgs
);
3930 for(l
= 1; l
<= istream
->nmsgs
; l
++)
3932 mn_set_cur(tmpmap
, l
);
3934 mn_add_cur(tmpmap
, l
);
3936 blank_keymenu(ps_global
->ttyo
->screen_rows
-2, 0);
3937 we_cancel
= busy_cue("Importing messages", NULL
, 0);
3938 l
= save(ps_global
, istream
, cntxt
, newfolder
, tmpmap
,
3945 if(l
== istream
->nmsgs
)
3946 q_status_message2(SM_ORDER
, 0, 3,
3947 "Folder %s imported to %s",
3948 full_filename
, newfolder
);
3950 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3951 _("Error importing to %s"),
3956 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3957 _("No messages in file %s"),
3959 else if(!ps_global
->mm_log_error
)
3960 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
3961 _("Can't open file %s for import"), full_filename
);
3965 pine_mail_close(istream
);
3972 folder_select_toggle(CONTEXT_S
*context
, int index
, int (*func
) (CONTEXT_S
*, int))
3976 if((f
= folder_entry(index
, FOLDERS(context
))) != NULL
){
3977 f
->selected
= !f
->selected
;
3978 return((*func
)(context
, index
));
3985 * Find the next '}' that isn't part of a "${"
3986 * that appear for environment variables. We need
3987 * this for configuration, because we want to edit
3988 * the original pinerc entry, and not the digested
3992 end_bracket_no_nest(char *str
)
3996 for(p
= str
; *p
; p
++){
3997 if(*p
== '$' && *(p
+1) == '{'){
3998 while(*p
&& *p
!= '}')
4006 /* if we get here then there was no trailing '}' */
4011 /*----------------------------------------------------------------------
4014 Args: context -- context we're adding in
4015 which -- which config file to operate on
4016 varnum -- which varnum to operate on
4017 add_folder -- return new folder here
4018 add_folderlen -- length of add_folder
4019 possible_stream -- possible stream for re-use
4020 def -- default value to start out with for add_folder
4021 (for now, only for inbox-path editing)
4023 Result: returns nonzero on successful add, 0 otherwise
4026 add_new_folder(CONTEXT_S
*context
, EditWhich which
, int varnum
, char *add_folder
,
4027 size_t add_folderlen
, MAILSTREAM
*possible_stream
, char *def
)
4029 char tmp
[MAX(MAXFOLDER
,6*MAX_SCREEN_COLS
)+1], nickname
[32],
4030 *p
= NULL
, *return_val
= NULL
, buf
[MAILTMPLEN
],
4031 buf2
[MAILTMPLEN
], def_in_prompt
[MAILTMPLEN
], orig_folder
[2*MAXFOLDER
+10];
4033 PINERC_S
*prc
= NULL
;
4034 int i
, rc
, offset
, exists
, cnt
= 0, isdir
= 0;
4035 int maildrop
= 0, flags
= 0, inbox
= 0, require_a_subfolder
= 0;
4036 char *maildropfolder
= NULL
, *maildroplongname
= NULL
;
4037 char *default_mail_drop_host
= NULL
,
4038 *default_mail_drop_folder
= NULL
,
4039 *default_dstn_host
= NULL
,
4040 *default_dstn_folder
= NULL
,
4043 char mdmbox
[MAILTMPLEN
], ctmp
[MAILTMPLEN
];
4044 MAILSTREAM
*create_stream
= NULL
;
4046 static ESCKEY_S add_key
[] = {{ctrl('X'),12,"^X", NULL
},
4047 {-1, 0, NULL
, NULL
}};
4049 dprint((4, "\n - add_new_folder - \n"));
4051 nickname
[0] = orig_folder
[0] = add_folder
[0] = '\0';
4052 inbox
= (varnum
== V_INBOX_PATH
);
4054 if(inbox
|| context
->use
& CNTXT_INCMNG
){
4055 char inbox_host
[MAXPATH
], *beg
, *end
= NULL
;
4057 static ESCKEY_S host_key
[4];
4059 if(ps_global
->restricted
)
4064 prc
= ps_global
->prc
;
4067 prc
= ps_global
->post_prc
;
4073 readonly
= prc
? prc
->readonly
: 1;
4076 if(prc
&& prc
->quit_to_edit
){
4077 quit_to_edit_msg(prc
);
4082 q_status_message(SM_ORDER
,3,5,
4083 _("Cancelled: config file not editable"));
4088 * When adding an Incoming folder we can't supply the inbox host
4089 * as a default, because then the user has no way to type just
4090 * a plain RETURN to mean "no host, I want a local folder".
4091 * So we supply it as a ^X command instead. We could supply it
4092 * as the initial value of the string...
4094 * When editing inbox-path we will supply the default value as an
4095 * initial value of the string which can be edited. They can edit it
4096 * or erase it entirely to mean no host.
4101 copydef
= cpystr(def
);
4102 (void) removing_double_quotes(copydef
);
4104 if(check_for_move_mbox(copydef
, mdmbox
, sizeof(mdmbox
), &dstnmbox
)){
4107 * Current inbox is using a mail drop. Get the default
4108 * host value for the maildrop.
4112 && (mdmbox
[0] == '{'
4113 || (mdmbox
[0] == '*' && mdmbox
[1] == '{'))
4114 && (end
= end_bracket_no_nest(mdmbox
+1))
4115 && end
-mdmbox
< add_folderlen
){
4117 if(mdmbox
[0] == '{')
4118 default_mail_drop_host
= cpystr(mdmbox
+1);
4120 default_mail_drop_host
= cpystr(mdmbox
+2);
4123 if(!default_mail_drop_host
)
4124 default_mail_drop_folder
= cpystr(mdmbox
);
4125 else if(end
&& *(end
+1))
4126 default_mail_drop_folder
= cpystr(end
+1);
4130 && (*dstnmbox
== '{'
4131 || (*dstnmbox
== '*' && *++dstnmbox
== '{'))
4132 && (end
= end_bracket_no_nest(dstnmbox
+1))
4133 && end
-dstnmbox
< add_folderlen
){
4135 default_dstn_host
= cpystr(dstnmbox
+1);
4138 if(!default_dstn_host
)
4139 default_dstn_folder
= cpystr(dstnmbox
);
4140 else if(end
&& *(end
+1))
4141 default_dstn_folder
= cpystr(end
+1);
4149 && (*dstnmbox
== '{'
4150 || (*dstnmbox
== '*' && *++dstnmbox
== '{'))
4151 && (end
= end_bracket_no_nest(dstnmbox
+1))
4152 && end
-dstnmbox
< add_folderlen
){
4154 default_dstn_host
= cpystr(dstnmbox
+1);
4157 if(!default_dstn_host
)
4158 default_dstn_folder
= cpystr(dstnmbox
);
4159 else if(end
&& *(end
+1))
4160 default_dstn_folder
= cpystr(end
+1);
4164 fs_give((void **) ©def
);
4171 host_key
[i
].rval
= 0;
4172 host_key
[i
].name
= "";
4173 host_key
[i
++].label
= "";
4175 inbox_host
[0] = '\0';
4176 if(!inbox
&& (beg
= ps_global
->VAR_INBOX_PATH
)
4177 && (*beg
== '{' || (*beg
== '*' && *++beg
== '{'))
4178 && (end
= strindex(ps_global
->VAR_INBOX_PATH
, '}'))){
4179 strncpy(inbox_host
, beg
+1, end
- beg
);
4180 inbox_host
[end
- beg
- 1] = '\0';
4181 host_key
[i
].ch
= ctrl('X');
4182 host_key
[i
].rval
= 12;
4183 host_key
[i
].name
= "^X";
4184 host_key
[i
++].label
= N_("Use Inbox Host");
4188 host_key
[i
].rval
= 0;
4189 host_key
[i
].name
= "";
4190 host_key
[i
++].label
= "";
4193 if(!maildrop
&& !maildropfolder
){
4194 host_key
[i
].ch
= ctrl('W');
4195 host_key
[i
].rval
= 13;
4196 host_key
[i
].name
= "^W";
4197 /* TRANSLATORS: a mail drop is a place where mail is copied to so you
4199 host_key
[i
++].label
= N_("Use a Mail Drop");
4202 host_key
[i
].ch
= ctrl('W');
4203 host_key
[i
].rval
= 13;
4204 host_key
[i
].name
= "^W";
4205 host_key
[i
++].label
= N_("Do Not use a Mail Drop");
4208 host_key
[i
].ch
= -1;
4209 host_key
[i
].rval
= 0;
4210 host_key
[i
].name
= NULL
;
4211 host_key
[i
].label
= NULL
;
4214 snprintf(tmp
, sizeof(tmp
), _("Name of Mail Drop server : "));
4215 else if(maildropfolder
)
4216 snprintf(tmp
, sizeof(tmp
), _("Name of server to contain destination folder : "));
4218 snprintf(tmp
, sizeof(tmp
), _("Name of Inbox server : "));
4220 snprintf(tmp
, sizeof(tmp
), _("Name of server to contain added folder : "));
4222 tmp
[sizeof(tmp
)-1] = '\0';
4226 /* set up defaults */
4228 flags
= OE_APPEND_CURRENT
;
4229 if(maildrop
&& default_mail_drop_host
){
4230 strncpy(add_folder
, default_mail_drop_host
, add_folderlen
);
4231 add_folder
[add_folderlen
-1] = '\0';
4233 else if(!maildrop
&& default_dstn_host
){
4234 strncpy(add_folder
, default_dstn_host
, add_folderlen
);
4235 add_folder
[add_folderlen
-1] = '\0';
4238 add_folder
[0] = '\0';
4242 add_folder
[0] = '\0';
4246 rc
= optionally_enter(add_folder
, -FOOTER_ROWS(ps_global
), 0,
4247 add_folderlen
, tmp
, host_key
, help
, &flags
);
4248 removing_leading_and_trailing_white_space(add_folder
);
4251 * User went for the whole enchilada and entered a maildrop
4252 * completely without going through the steps.
4253 * Split it up as if they did and then skip over
4256 if(check_for_move_mbox(add_folder
, mdmbox
, sizeof(mdmbox
),
4260 fs_give((void **) &maildropfolder
);
4262 maildropfolder
= cpystr(mdmbox
);
4264 strncpy(add_folder
, dstnmbox
, add_folderlen
);
4265 add_folder
[add_folderlen
-1] = '\0';
4267 goto skip_over_folder_input
;
4271 * Now check to see if they entered a whole c-client
4272 * spec that isn't a mail drop.
4274 if(add_folder
[0] == '{'
4275 && add_folder
[1] != '\0'
4276 && (p
= srchstr(add_folder
, "}"))
4278 offset
= p
+1 - add_folder
;
4279 goto skip_over_folder_input
;
4283 * And check to see if they entered "INBOX".
4285 if(!strucmp(add_folder
, ps_global
->inbox_name
)){
4287 goto skip_over_folder_input
;
4290 /* remove surrounding braces */
4291 if(add_folder
[0] == '{' && add_folder
[1] != '\0'){
4294 q
= add_folder
+ strlen(add_folder
) - 1;
4297 for(q
= add_folder
; *q
; q
++)
4303 if(maildropfolder
&& inbox
)
4304 helper(h_inbox_add_maildrop_destn
,
4305 _("HELP FOR DESTINATION SERVER "), HLPD_SIMPLE
);
4306 else if(maildropfolder
&& !inbox
)
4307 helper(h_incoming_add_maildrop_destn
,
4308 _("HELP FOR DESTINATION SERVER "), HLPD_SIMPLE
);
4309 else if(maildrop
&& inbox
)
4310 helper(h_inbox_add_maildrop
, _("HELP FOR MAILDROP NAME "),
4312 else if(maildrop
&& !inbox
)
4313 helper(h_incoming_add_maildrop
, _("HELP FOR MAILDROP NAME "),
4316 helper(h_incoming_add_inbox
, _("HELP FOR INBOX SERVER "),
4319 helper(h_incoming_add_folder_host
, _("HELP FOR SERVER NAME "),
4322 ps_global
->mangled_screen
= 1;
4325 strncpy(add_folder
, inbox_host
, add_folderlen
);
4326 flags
|= OE_APPEND_CURRENT
;
4332 fs_give((void **) &maildropfolder
);
4337 default_mail_drop_host
= default_dstn_host
;
4338 default_dstn_host
= NULL
;
4339 default_mail_drop_folder
= default_dstn_folder
;
4340 default_dstn_folder
= NULL
;
4344 goto get_folder_name
;
4347 q_status_message(SM_ORDER
,0,2,
4348 inbox
? _("INBOX change cancelled")
4349 : _("Addition of new folder cancelled"));
4351 fs_give((void **) &maildropfolder
);
4354 if(default_mail_drop_host
)
4355 fs_give((void **) &default_mail_drop_host
);
4357 if(default_mail_drop_folder
)
4358 fs_give((void **) &default_mail_drop_folder
);
4360 if(default_dstn_host
)
4361 fs_give((void **) &default_dstn_host
);
4363 if(default_dstn_folder
)
4364 fs_give((void **) &default_dstn_folder
);
4374 /* set up default folder, if any */
4375 def_in_prompt
[0] = '\0';
4377 if(maildrop
&& default_mail_drop_folder
){
4378 strncpy(def_in_prompt
, default_mail_drop_folder
,
4379 sizeof(def_in_prompt
));
4380 def_in_prompt
[sizeof(def_in_prompt
)-1] = '\0';
4382 else if(!maildrop
&& default_dstn_folder
){
4383 strncpy(def_in_prompt
, default_dstn_folder
,
4384 sizeof(def_in_prompt
));
4385 def_in_prompt
[sizeof(def_in_prompt
)-1] = '\0';
4389 if((offset
= strlen(add_folder
)) != 0){ /* must be host for incoming */
4392 snprintf(tmp
, sizeof(tmp
),
4393 "Maildrop folder on \"%s\" to copy mail from%s%s%s : ",
4394 short_str(add_folder
, buf
, sizeof(buf
), 15, EndDots
),
4395 def_in_prompt
[0] ? " [" : "",
4396 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4397 def_in_prompt
[0] ? "]" : "");
4398 else if(maildropfolder
)
4399 snprintf(tmp
, sizeof(tmp
),
4400 "Folder on \"%s\" to copy mail to%s%s%s : ",
4401 short_str(add_folder
, buf
, sizeof(buf
), 20, EndDots
),
4402 def_in_prompt
[0] ? " [" : "",
4403 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4404 def_in_prompt
[0] ? "]" : "");
4406 snprintf(tmp
, sizeof(tmp
),
4407 "Folder on \"%s\" to use for INBOX%s%s%s : ",
4408 short_str(add_folder
, buf
, sizeof(buf
), 20, EndDots
),
4409 def_in_prompt
[0] ? " [" : "",
4410 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4411 def_in_prompt
[0] ? "]" : "");
4413 snprintf(tmp
, sizeof(tmp
),
4414 "Folder on \"%s\" to add%s%s%s : ",
4415 short_str(add_folder
, buf
, sizeof(buf
), 25, EndDots
),
4416 def_in_prompt
[0] ? " [" : "",
4417 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4418 def_in_prompt
[0] ? "]" : "");
4420 tmp
[sizeof(tmp
)-1] = '\0';
4422 for(i
= offset
;i
>= 0; i
--)
4423 add_folder
[i
+1] = add_folder
[i
];
4425 add_folder
[0] = '{';
4426 add_folder
[++offset
] = '}';
4427 add_folder
[++offset
] = '\0'; /* +2, total */
4431 snprintf(tmp
, sizeof(tmp
),
4432 "Folder to copy mail from%s%s%s : ",
4433 def_in_prompt
[0] ? " [" : "",
4434 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4435 def_in_prompt
[0] ? "]" : "");
4436 else if(maildropfolder
)
4437 snprintf(tmp
, sizeof(tmp
),
4438 "Folder to copy mail to%s%s%s : ",
4439 def_in_prompt
[0] ? " [" : "",
4440 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4441 def_in_prompt
[0] ? "]" : "");
4443 snprintf(tmp
, sizeof(tmp
),
4444 "Folder name to use for INBOX%s%s%s : ",
4445 def_in_prompt
[0] ? " [" : "",
4446 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4447 def_in_prompt
[0] ? "]" : "");
4449 snprintf(tmp
, sizeof(tmp
),
4450 "Folder name to add%s%s%s : ",
4451 def_in_prompt
[0] ? " [" : "",
4452 short_str(def_in_prompt
, buf2
, sizeof(buf2
), 20, MidDots
),
4453 def_in_prompt
[0] ? "]" : "");
4455 tmp
[sizeof(tmp
)-1] = '\0';
4463 add_key
[0].label
= N_("Create Folder");
4465 rplstr(tmp
, sizeof(tmp
), 6, N_("Directory"));
4468 add_key
[0].label
= N_("Create Directory");
4470 rplstr(tmp
, sizeof(tmp
), 9, N_("Folder"));
4473 flags
= OE_APPEND_CURRENT
;
4474 rc
= optionally_enter(&add_folder
[offset
], -FOOTER_ROWS(ps_global
), 0,
4475 add_folderlen
- offset
, tmp
,
4476 ((context
->dir
->delim
) && !maildrop
)
4480 if(rc
== 0 && def_in_prompt
[0] && !add_folder
[offset
]){
4481 strncpy(&add_folder
[offset
], def_in_prompt
, add_folderlen
-offset
);
4482 add_folder
[add_folderlen
-1] = '\0';
4485 removing_leading_and_trailing_white_space(&add_folder
[offset
]);
4487 /* for non-local folders, transform UTF-8 to MUTF7 */
4488 if(offset
> 0 && add_folder
[0] == '{'){
4489 unsigned char *mutf7
= utf8_to_mutf7((unsigned char *)&add_folder
[offset
]);
4491 strncpy(orig_folder
, &add_folder
[offset
], 2*MAXFOLDER
+10);
4492 strncpy(&add_folder
[offset
], (char *) mutf7
, add_folderlen
-offset
);
4493 add_folder
[add_folderlen
-1] = '\0';
4494 fs_give((void **)&mutf7
);
4498 if(rc
== 0 && !(inbox
|| context
->use
& CNTXT_INCMNG
)
4499 && check_for_move_mbox(add_folder
, NULL
, 0L, NULL
)){
4500 q_status_message(SM_ORDER
, 6, 6,
4501 _("#move folders may only be the INBOX or in the Incoming Collection"));
4502 display_message(NO_OP_COMMAND
);
4506 if(rc
== 0 && add_folder
[offset
]){
4507 if(F_OFF(F_ENABLE_DOT_FOLDERS
,ps_global
)
4508 && add_folder
[offset
] == '.'){
4510 q_status_message(SM_ORDER
,3,3,
4511 _("Folder name can't begin with dot"));
4513 q_status_message1(SM_ORDER
,3,3,
4514 _("Config feature \"%s\" enables names beginning with dot"),
4515 pretty_feature_name(feature_list_name(F_ENABLE_DOT_FOLDERS
), -1));
4517 display_message(NO_OP_COMMAND
);
4521 /* if last char is delim, blast from new folder */
4522 for(p
= &add_folder
[offset
]; *p
&& *(p
+ 1); p
++)
4523 ; /* find last char in folder */
4526 if(*p
&& *p
!= context
->dir
->delim
){
4527 *++p
= context
->dir
->delim
;
4531 if(F_ON(F_QUELL_EMPTY_DIRS
, ps_global
))
4532 require_a_subfolder
++;
4534 else if(*p
== context
->dir
->delim
){
4535 q_status_message(SM_ORDER
|SM_DING
, 3, 3,
4536 _("Can't have trailing directory delimiters!"));
4537 display_message('X');
4545 isdir
= !isdir
; /* toggle directory creation */
4548 helper(h_incoming_add_folder_name
, _("HELP FOR FOLDER NAME "),
4551 else if(rc
== 1 || add_folder
[0] == '\0') {
4552 q_status_message(SM_ORDER
,0,2,
4553 inbox
? _("INBOX change cancelled")
4554 : _("Addition of new folder cancelled"));
4556 fs_give((void **) &maildropfolder
);
4559 if(default_mail_drop_host
)
4560 fs_give((void **) &default_mail_drop_host
);
4562 if(default_mail_drop_folder
)
4563 fs_give((void **) &default_mail_drop_folder
);
4565 if(default_dstn_host
)
4566 fs_give((void **) &default_dstn_host
);
4568 if(default_dstn_folder
)
4569 fs_give((void **) &default_dstn_folder
);
4576 if(maildrop
&& !maildropfolder
){
4577 maildropfolder
= cpystr(add_folder
);
4579 goto get_folder_name
;
4582 skip_over_folder_input
:
4584 if(require_a_subfolder
){
4585 /* add subfolder name to directory name */
4586 offset
= strlen(add_folder
);
4589 if(offset
> 0){ /* it had better be */
4592 save_delim
= add_folder
[offset
-1];
4593 add_folder
[offset
-1] = '\0';
4595 snprintf(tmp
, sizeof(tmp
),
4596 "Name of subfolder to add in \"%s\" : ",
4597 short_str(add_folder
, buf
, sizeof(buf
), 15, FrontDots
));
4599 tmp
[sizeof(tmp
)-1] = '\0';
4600 add_folder
[offset
-1] = save_delim
;
4604 flags
= OE_APPEND_CURRENT
;
4605 rc
= optionally_enter(&add_folder
[offset
], -FOOTER_ROWS(ps_global
), 0,
4606 add_folderlen
- offset
, tmp
,
4607 NULL
, NO_HELP
, &flags
);
4609 removing_leading_and_trailing_white_space(&add_folder
[offset
]);
4611 /* for non-local folders, transform UTF-8 to MUTF7 */
4612 if(offset
> 0 && add_folder
[0] == '{'){
4613 unsigned char *mutf7
= utf8_to_mutf7((unsigned char *)&add_folder
[offset
]);
4615 strncpy(orig_folder
, &add_folder
[offset
], 2*MAXFOLDER
+10);
4616 strncpy(&add_folder
[offset
], (char *) mutf7
, add_folderlen
-offset
);
4617 add_folder
[add_folderlen
-1] = '\0';
4618 fs_give((void **)&mutf7
);
4623 if(rc
== 0 && !add_folder
[offset
]){
4624 q_status_message(SM_ORDER
, 4, 4,
4625 _("A subfolder name is required, there is no default subfolder name"));
4629 if(rc
== 0 && add_folder
[offset
]){
4634 helper(h_emptydir_subfolder_name
, _("HELP FOR SUBFOLDER NAME "),
4637 else if(rc
== 1 || add_folder
[0] == '\0') {
4638 q_status_message(SM_ORDER
,0,2, _("Addition of new folder cancelled"));
4643 /* the directory is implicit now */
4647 if(context
== ps_global
->context_list
4648 && !(context
->dir
&& context
->dir
->ref
)
4649 && !strucmp(ps_global
->inbox_name
, add_folder
)){
4650 q_status_message1(SM_ORDER
,3,3,
4651 _("Cannot add folder %s in current context"),
4656 create_stream
= sp_stream_get(context_apply(ctmp
, context
, add_folder
,
4660 if(!create_stream
&& possible_stream
)
4661 create_stream
= context_same_stream(context
, add_folder
, possible_stream
);
4664 if(!inbox
&& context
->use
& CNTXT_INCMNG
){
4665 snprintf(tmp
, sizeof(tmp
), _("Nickname for folder \"%s\" : "), orig_folder
[0] ? orig_folder
: &add_folder
[offset
]);
4666 tmp
[sizeof(tmp
)-1] = '\0';
4668 int flags
= OE_APPEND_CURRENT
;
4670 rc
= optionally_enter(nickname
, -FOOTER_ROWS(ps_global
), 0,
4671 sizeof(nickname
), tmp
, NULL
, help
, &flags
);
4672 removing_leading_and_trailing_white_space(nickname
);
4674 if(strucmp(ps_global
->inbox_name
, nickname
))
4677 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
4678 _("Nickname cannot be \"%s\""), nickname
);
4683 help
= help
== NO_HELP
4684 ? h_incoming_add_folder_nickname
: NO_HELP
;
4686 else if(rc
== 1 || (rc
!= 3 && !*nickname
)){
4687 q_status_message(SM_ORDER
,0,2,
4688 inbox
? _("INBOX change cancelled")
4689 : _("Addition of new folder cancelled"));
4691 fs_give((void **) &maildropfolder
);
4694 if(default_mail_drop_host
)
4695 fs_give((void **) &default_mail_drop_host
);
4697 if(default_mail_drop_folder
)
4698 fs_give((void **) &default_mail_drop_folder
);
4700 if(default_dstn_host
)
4701 fs_give((void **) &default_dstn_host
);
4703 if(default_dstn_folder
)
4704 fs_give((void **) &default_dstn_folder
);
4712 * Already exist? First, make sure this name won't collide with
4713 * anything else in the list. Next, quickly test to see if it
4714 * the actual mailbox exists so we know any errors from
4715 * context_create() are really bad...
4717 for(offset
= 0; offset
< folder_total(FOLDERS(context
)); offset
++){
4718 f
= folder_entry(offset
, FOLDERS(context
));
4719 if(!strucmp(FLDR_NAME(f
), nickname
[0] ? nickname
: add_folder
)){
4720 q_status_message1(SM_ORDER
| SM_DING
, 0, 3,
4721 _("Incoming folder \"%s\" already exists"),
4722 nickname
[0] ? nickname
: add_folder
);
4724 fs_give((void **) &maildropfolder
);
4727 if(default_mail_drop_host
)
4728 fs_give((void **) &default_mail_drop_host
);
4730 if(default_mail_drop_folder
)
4731 fs_give((void **) &default_mail_drop_folder
);
4733 if(default_dstn_host
)
4734 fs_give((void **) &default_dstn_host
);
4736 if(default_dstn_folder
)
4737 fs_give((void **) &default_dstn_folder
);
4744 ps_global
->c_client_error
[0] = '\0';
4745 exists
= folder_exists(context
, add_folder
);
4746 if(exists
== FEX_ERROR
){
4747 if(ps_global
->c_client_error
[0] != '\0')
4748 q_status_message1(SM_ORDER
, 3, 3, "%s",
4749 ps_global
->c_client_error
);
4751 q_status_message1(SM_ORDER
, 3, 3, _("Error checking for %s"), add_folder
);
4757 exists
= FEX_ISFILE
;
4759 * If inbox is a maildropfolder, try to create the destination
4760 * folder. But it shouldn't cause a fatal error.
4762 if(maildropfolder
&& (folder_exists(NULL
, add_folder
) == FEX_NOENT
))
4763 context_create(NULL
, NULL
, add_folder
);
4766 if(exists
== FEX_ERROR
4767 || (exists
== FEX_NOENT
4768 && !context_create(context
, create_stream
, add_folder
)
4769 && !((context
->use
& CNTXT_INCMNG
)
4770 && !context_isambig(add_folder
)))){
4772 fs_give((void **) &maildropfolder
);
4775 if(default_mail_drop_host
)
4776 fs_give((void **) &default_mail_drop_host
);
4778 if(default_mail_drop_folder
)
4779 fs_give((void **) &default_mail_drop_folder
);
4781 if(default_dstn_host
)
4782 fs_give((void **) &default_dstn_host
);
4784 if(default_dstn_folder
)
4785 fs_give((void **) &default_dstn_folder
);
4788 return(FALSE
); /* c-client should've reported error */
4791 if(isdir
&& p
) /* whack off trailing delim */
4794 if(inbox
|| context
->use
& CNTXT_INCMNG
){
4795 char **apval
= NULL
;
4796 char ***alval
= NULL
;
4799 apval
= APVAL(&ps_global
->vars
[varnum
], which
);
4801 fs_give((void **) apval
);
4804 alval
= ALVAL(&ps_global
->vars
[varnum
], which
);
4807 *alval
= (char **) fs_get(2*sizeof(char *));
4810 for(offset
=0; (*alval
)[offset
]; offset
++)
4813 fs_resize((void **) alval
, (offset
+ 2) * sizeof(char *));
4818 * If we're using a Mail Drop we have to assemble the correct
4819 * c-client string to do that. Mail drop syntax looks like
4821 * #move <DELIM> <FromMailbox> <DELIM> <ToMailbox>
4823 * DELIM is any character which does not appear in either of
4824 * the mailbox names.
4826 * And then the nickname is still in front of that mess.
4829 char *delims
= " +-_:!|ABCDEFGHIJKLMNOPQRSTUVWXYZ";
4833 len
= 5 + 2 + strlen(maildropfolder
) + strlen(add_folder
);
4834 maildroplongname
= (char *) fs_get((len
+1) * sizeof(char));
4836 for(c
= delims
; *c
; c
++){
4837 if(!strindex(maildropfolder
, *c
) &&
4838 !strindex(add_folder
, *c
))
4843 snprintf(maildroplongname
, len
+1, "#move%c%s%c%s",
4844 *c
, maildropfolder
, *c
, add_folder
);
4845 if(strlen(maildroplongname
) < add_folderlen
){
4846 strncpy(add_folder
, maildroplongname
, add_folderlen
);
4847 add_folder
[add_folderlen
-1] = '\0';
4851 q_status_message2(SM_ORDER
,0,2,
4852 "Can't find delimiter for \"#move %s %s\"",
4853 maildropfolder
, add_folder
);
4855 "Can't find delimiter for \"#move %s %s\"",
4856 maildropfolder
? maildropfolder
: "?",
4857 add_folder
? add_folder
: "?"));
4860 fs_give((void **) &maildropfolder
);
4863 if(default_mail_drop_host
)
4864 fs_give((void **) &default_mail_drop_host
);
4866 if(default_mail_drop_folder
)
4867 fs_give((void **) &default_mail_drop_folder
);
4869 if(default_dstn_host
)
4870 fs_give((void **) &default_dstn_host
);
4872 if(default_dstn_folder
)
4873 fs_give((void **) &default_dstn_folder
);
4879 if(maildroplongname
)
4880 fs_give((void **) &maildroplongname
);
4884 *apval
= cpystr(add_folder
);
4886 (*alval
)[offset
] = put_pair(nickname
, add_folder
);
4887 (*alval
)[offset
+1] = NULL
;
4890 set_current_val(&ps_global
->vars
[varnum
], TRUE
, FALSE
);
4892 prc
->outstanding_pinerc_changes
= 1;
4894 if(context
->use
& CNTXT_INCMNG
){
4895 if(!inbox
&& add_folder
&& add_folder
[0] && alval
&& *alval
&& (*alval
)[offset
]){
4897 * Instead of re-initing we try to insert the
4898 * added folder so that we preserve the last_unseen_update
4901 f
= new_folder(add_folder
, line_hash((*alval
)[offset
]));
4903 if(nickname
&& nickname
[0]){
4904 f
->nickname
= cpystr(nickname
);
4905 f
->name_len
= strlen(f
->nickname
);
4908 if(F_ON(F_ENABLE_INCOMING_CHECKING
, ps_global
)
4909 && !ps_global
->VAR_INCCHECKLIST
)
4910 f
->last_unseen_update
= LUU_INIT
;
4912 f
->last_unseen_update
= LUU_NEVERCHK
;
4914 folder_insert(folder_total(FOLDERS(context
)), f
, FOLDERS(context
));
4917 /* re-init to make sure we got it right */
4918 reinit_incoming_folder_list(ps_global
, context
);
4922 strncpy(add_folder
, nickname
, add_folderlen
-1); /* known by new name */
4923 add_folder
[add_folderlen
-1] = '\0';
4927 q_status_message1(SM_ORDER
, 0, 3, "Folder \"%s\" created",
4928 orig_folder
[0] ? orig_folder
: add_folder
);
4929 return_val
= add_folder
;
4931 else if(context_isambig(add_folder
)){
4932 free_folder_list(context
);
4933 q_status_message2(SM_ORDER
, 0, 3, "%s \"%s\" created",
4934 isdir
? "Directory" : "Folder", orig_folder
[0] ? orig_folder
: add_folder
);
4935 return_val
= add_folder
;
4938 q_status_message1(SM_ORDER
, 0, 3,
4939 "Folder \"%s\" created outside current collection",
4940 orig_folder
[0] ? orig_folder
: add_folder
);
4943 fs_give((void **) &maildropfolder
);
4946 if(default_mail_drop_host
)
4947 fs_give((void **) &default_mail_drop_host
);
4949 if(default_mail_drop_folder
)
4950 fs_give((void **) &default_mail_drop_folder
);
4952 if(default_dstn_host
)
4953 fs_give((void **) &default_dstn_host
);
4955 if(default_dstn_folder
)
4956 fs_give((void **) &default_dstn_folder
);
4959 return(return_val
!= NULL
);
4963 /*----------------------------------------------------------------------
4964 Subscribe to a news group
4966 Args: folder -- last folder added
4967 cntxt -- The context the subscription is for
4969 Result: returns the name of the folder subscribed too
4972 This builds a complete context for the entire list of possible news groups.
4973 It also build a context to find the newly created news groups as
4974 determined by data kept in .pinerc. When the find of these new groups is
4975 done the subscribed context is searched and the items marked as new.
4976 A list of new board is never actually created.
4980 group_subscription(char *folder
, size_t len
, CONTEXT_S
*cntxt
)
4982 STRLIST_S
*folders
= NULL
;
4983 int rc
= 0, last_rc
, i
, n
, flags
,
4984 last_find_partial
= 0, we_cancel
= 0;
4985 CONTEXT_S subscribe_cntxt
;
4987 ESCKEY_S subscribe_keys
[3];
4989 subscribe_keys
[i
= 0].ch
= ctrl('T');
4990 subscribe_keys
[i
].rval
= 12;
4991 subscribe_keys
[i
].name
= "^T";
4992 subscribe_keys
[i
++].label
= N_("To All Grps");
4994 if(F_ON(F_ENABLE_TAB_COMPLETE
,ps_global
)){
4995 subscribe_keys
[i
].ch
= ctrl('I');
4996 subscribe_keys
[i
].rval
= 11;
4997 subscribe_keys
[i
].name
= "TAB";
4998 subscribe_keys
[i
++].label
= N_("Complete");
5001 subscribe_keys
[i
].ch
= -1;
5003 /*---- Build a context to find all news groups -----*/
5005 subscribe_cntxt
= *cntxt
;
5006 subscribe_cntxt
.use
|= CNTXT_FINDALL
;
5007 subscribe_cntxt
.use
&= ~(CNTXT_PSEUDO
| CNTXT_ZOOM
| CNTXT_PRESRV
);
5008 subscribe_cntxt
.next
= NULL
;
5009 subscribe_cntxt
.prev
= NULL
;
5010 subscribe_cntxt
.dir
= new_fdir(cntxt
->dir
->ref
,
5011 cntxt
->dir
->view
.internal
, '*');
5012 FOLDERS(&subscribe_cntxt
) = init_folder_entries();
5014 * Prompt for group name.
5019 flags
= OE_APPEND_CURRENT
;
5021 rc
= optionally_enter(folder
, -FOOTER_ROWS(ps_global
), 0, len
,
5022 SUBSCRIBE_PMT
, subscribe_keys
, help
, &flags
);
5023 removing_trailing_white_space(folder
);
5024 removing_leading_white_space(folder
);
5025 if((rc
== 0 && folder
[0]) || rc
== 11 || rc
== 12){
5026 we_cancel
= busy_cue(_("Fetching newsgroup list"), NULL
, 1);
5028 if(last_find_partial
){
5029 /* clean up any previous find results */
5030 free_folder_list(&subscribe_cntxt
);
5031 last_find_partial
= 0;
5034 if(rc
== 11){ /* Tab completion! */
5035 if(folder_complete_internal(&subscribe_cntxt
,
5036 folder
, len
, &n
, FC_FORCE_LIST
)){
5040 if(!(n
&& last_rc
== 11 && !(flags
& OE_USER_MODIFIED
))){
5047 if(rc
== 12){ /* list the whole enchilada */
5048 build_folder_list(NULL
, &subscribe_cntxt
, NULL
, NULL
,BFL_NONE
);
5050 else if(strlen(folder
)){
5051 char tmp
[MAILTMPLEN
];
5053 snprintf(tmp
, sizeof(tmp
), "%s%.*s*", (rc
== 11) ? "" : "*",
5054 MAILTMPLEN
-3, folder
);
5055 tmp
[sizeof(tmp
)-1] = '\0';
5056 build_folder_list(NULL
, &subscribe_cntxt
, tmp
, NULL
, BFL_NONE
);
5057 subscribe_cntxt
.dir
->status
&= ~(CNTXT_PARTFIND
|CNTXT_NOFIND
);
5060 q_status_message(SM_ORDER
, 0, 2,
5061 _("No group substring to match! Use ^T to list all news groups."));
5066 * If we did a partial find on matches, then we faked a full
5067 * find which will cause this to just return.
5069 if((i
= folder_total(FOLDERS(&subscribe_cntxt
))) != 0){
5073 * fake that we've found everything there is to find...
5075 subscribe_cntxt
.use
&= ~(CNTXT_NOFIND
|CNTXT_PARTFIND
);
5076 last_find_partial
= 1;
5079 f
= folder_entry(0, FOLDERS(&subscribe_cntxt
))->name
;
5080 if(!strcmp(f
, folder
)){
5081 rc
= 1; /* success! */
5084 else{ /* else complete the group */
5085 strncpy(folder
, f
, len
-1);
5086 folder
[len
-1] = '\0';
5090 else if(!(flags
& OE_USER_MODIFIED
)){
5092 * See if there wasn't an exact match in the lot.
5095 f
= folder_entry(i
,FOLDERS(&subscribe_cntxt
))->name
;
5096 if(!strcmp(f
, folder
))
5102 /* if so, then the user picked it from the list the
5103 * last time and didn't change it at the prompt.
5104 * Must mean they're accepting it...
5107 rc
= 1; /* success! */
5114 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
5115 _("No groups to select from!"));
5117 q_status_message1(SM_ORDER
, 3, 3,
5118 _("News group \"%s\" didn't match any existing groups"),
5120 free_folder_list(&subscribe_cntxt
);
5125 /*----- Mark groups that are currently subscribed too ------*/
5126 /* but first make sure they're found */
5127 build_folder_list(NULL
, cntxt
, "*", NULL
, BFL_LSUB
);
5128 for(i
= 0 ; i
< folder_total(FOLDERS(&subscribe_cntxt
)); i
++) {
5129 FOLDER_S
*f
= folder_entry(i
, FOLDERS(&subscribe_cntxt
));
5131 f
->subscribed
= search_folder_list(FOLDERS(cntxt
),
5136 cancel_busy_cue(-1);
5138 /*----- Call the folder lister to do all the work -----*/
5139 folders
= folders_for_subscribe(ps_global
,
5140 &subscribe_cntxt
, folder
);
5143 /* Multiple newsgroups OR Auto-select */
5144 if(folders
->next
|| F_ON(F_SELECT_WO_CONFIRM
,ps_global
))
5147 strncpy(folder
, (char *) folders
->name
, len
-1);
5148 folder
[len
-1] = '\0';
5149 free_strlist(&folders
);
5153 help
= help
== NO_HELP
? h_news_subscribe
: NO_HELP
;
5155 else if(rc
== 1 || folder
[0] == '\0'){
5162 folder
[0] = '\0'; /* make sure not to return partials */
5164 q_status_message(SM_ORDER
, 0, 3, _("Subscribe cancelled"));
5167 MAILSTREAM
*sub_stream
;
5168 int sclose
= 0, errors
= 0;
5170 if(folders
){ /*------ Actually do the subscription -----*/
5174 /* subscribe one at a time */
5177 * Open stream before subscribing so c-client knows what newsrc
5178 * to use, along with other side-effects.
5180 if((sub_stream
= mail_cmd_stream(&subscribe_cntxt
, &sclose
)) != NULL
){
5181 for(flp
= folders
; flp
; flp
= flp
->next
){
5182 (void) context_apply(tmp_20k_buf
, &subscribe_cntxt
,
5183 (char *) flp
->name
, SIZEOF_20KBUF
);
5184 if(mail_subscribe(sub_stream
, tmp_20k_buf
) == 0L){
5186 * This message may not make it to the screen,
5187 * because a c-client message about the failure
5188 * will be there. Probably best not to string
5189 * together a whole bunch of errors if there is
5192 q_status_message1(errors
?SM_INFO
: SM_ORDER
,
5194 _("Error subscribing to \"%s\""),
5195 (char *) flp
->name
);
5201 strncpy(folder
, (char *) flp
->name
, len
-1);
5202 folder
[len
-1] = '\0';
5205 /*---- Update the screen display data structures -----*/
5206 if(ALL_FOUND(cntxt
)){
5207 if(cntxt
->use
& CNTXT_PSEUDO
){
5208 folder_delete(0, FOLDERS(cntxt
));
5209 cntxt
->use
&= ~CNTXT_PSEUDO
;
5212 folder_insert(-1, new_folder((char *) flp
->name
, 0),
5218 pine_mail_close(sub_stream
);
5224 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
5225 _("Subscriptions failed, subscribed to no new groups"));
5227 q_status_message3(SM_ORDER
| (errors
? SM_DING
: 0),
5229 "Subscribed to %s new groups%s%s",
5231 errors
? ", failed on " : "",
5232 errors
? comatose((long)errors
) : "");
5234 free_strlist(&folders
);
5237 if((sub_stream
= mail_cmd_stream(&subscribe_cntxt
, &sclose
)) != NULL
){
5238 (void) context_apply(tmp_20k_buf
, &subscribe_cntxt
, folder
,
5240 if(mail_subscribe(sub_stream
, tmp_20k_buf
) == 0L){
5241 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
5242 _("Error subscribing to \"%s\""), folder
);
5245 else if(ALL_FOUND(cntxt
)){
5246 /*---- Update the screen display data structures -----*/
5247 if(cntxt
->use
& CNTXT_PSEUDO
){
5248 folder_delete(0, FOLDERS(cntxt
));
5249 cntxt
->use
&= ~CNTXT_PSEUDO
;
5252 folder_insert(-1, new_folder(folder
, 0), FOLDERS(cntxt
));
5255 pine_mail_close(sub_stream
);
5258 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
5259 _("Error subscribing to \"%s\""), folder
);
5264 if(!errors
&& folder
[0])
5265 q_status_message1(SM_ORDER
, 0, 3, _("Subscribed to \"%s\""), folder
);
5268 free_fdir(&subscribe_cntxt
.dir
, 1);
5273 /*----------------------------------------------------------------------
5276 Args: new_name -- buffer to contain new file name
5277 len -- length of new_name buffer
5278 index -- index of folder in folder list to rename
5279 context -- collection of folders making up folder list
5280 possible_stream -- may be able to use this stream
5282 Result: returns the new name of the folder, or NULL if nothing happened.
5284 When either the sent-mail or saved-message folders are renamed, immediately
5285 create a new one in their place so they always exist. The main loop above also
5286 detects this and makes the rename look like an add of the sent-mail or
5287 saved-messages folder. (This behavior may not be optimal, but it keeps things
5292 rename_folder(CONTEXT_S
*context
, int index
, char *new_name
, size_t len
, MAILSTREAM
*possible_stream
)
5294 char *folder
, prompt
[64], *name_p
= NULL
;
5297 PINERC_S
*prc
= NULL
;
5298 int rc
, ren_cur
, cnt
= 0, isdir
= 0, readonly
= 0;
5302 dprint((4, "\n - rename folder -\n"));
5304 if(NEWS_TEST(context
)){
5305 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
5306 _("Can't rename news groups!"));
5309 else if(!folder_total(FOLDERS(context
))){
5310 q_status_message(SM_ORDER
| SM_DING
, 0, 4,
5311 _("Empty folder collection. No folder to rename!"));
5314 else if((new_f
= folder_entry(index
, FOLDERS(context
)))
5315 && context
== ps_global
->context_list
5316 && !(context
->dir
&& context
->dir
->ref
)
5317 && !strucmp(FLDR_NAME(new_f
), ps_global
->inbox_name
)) {
5318 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
5319 _("Can't change special folder name \"%s\""),
5320 ps_global
->inbox_name
);
5324 ew
= config_containing_inc_fldr(new_f
);
5325 if(ps_global
->restricted
)
5330 prc
= ps_global
->prc
;
5333 prc
= ps_global
->post_prc
;
5339 readonly
= prc
? prc
->readonly
: 1;
5342 if(prc
&& prc
->quit_to_edit
&& (context
->use
& CNTXT_INCMNG
)){
5343 quit_to_edit_msg(prc
);
5347 if(readonly
&& (context
->use
& CNTXT_INCMNG
)){
5348 q_status_message(SM_ORDER
,3,5,
5349 _("Rename cancelled: folder not in editable config file"));
5353 if(context
->use
& CNTXT_INCMNG
){
5354 if(!(folder
= new_f
->nickname
))
5355 folder
= ""; /* blank nickname */
5358 folder
= FLDR_NAME(new_f
);
5360 ren_cur
= strcmp(folder
, ps_global
->cur_folder
) == 0;
5362 snprintf(prompt
, sizeof(prompt
), "%s %s to : ", _("Rename"),
5363 (context
->use
& CNTXT_INCMNG
)
5365 : (isdir
= new_f
->isdir
)
5366 ? _("directory") : _("folder"));
5367 prompt
[sizeof(prompt
)-1] = '\0';
5369 strncpy(new_name
, folder
, len
-1);
5370 new_name
[len
-1] = '\0';
5372 int flags
= OE_APPEND_CURRENT
;
5374 rc
= optionally_enter(new_name
, -FOOTER_ROWS(ps_global
), 0,
5375 len
, prompt
, NULL
, help
, &flags
);
5377 help
= help
== NO_HELP
? h_oe_foldrename
: NO_HELP
;
5381 removing_leading_and_trailing_white_space(new_name
);
5383 if(rc
== 0 && (*new_name
|| (context
->use
& CNTXT_INCMNG
))) {
5384 /* verify characters */
5385 if(F_OFF(F_ENABLE_DOT_FOLDERS
,ps_global
) && *new_name
== '.'){
5387 q_status_message(SM_ORDER
,3,3,
5388 _("Folder name can't begin with dot"));
5390 q_status_message1(SM_ORDER
,3,3,
5391 _("Config feature \"s\" enables names beginning with dot"),
5392 pretty_feature_name(feature_list_name(F_ENABLE_DOT_FOLDERS
), -1));
5394 display_message(NO_OP_COMMAND
);
5398 if(folder_index(new_name
, context
, FI_ANY
|FI_RENAME
) >= 0){
5399 q_status_message1(SM_ORDER
, 3, 3,
5400 _("Folder \"%s\" already exists"),
5401 pretty_fn(new_name
));
5402 display_message(NO_OP_COMMAND
);
5405 else if(context
== ps_global
->context_list
5406 && !(context
->dir
&& context
->dir
->ref
)
5407 && !strucmp(new_name
, ps_global
->inbox_name
)){
5408 if(context
->use
& CNTXT_INCMNG
)
5409 q_status_message1(SM_ORDER
, 3, 3, _("Can't rename incoming folder to %s"),
5412 q_status_message1(SM_ORDER
, 3, 3, _("Can't rename folder to %s"),
5415 display_message(NO_OP_COMMAND
);
5420 if(rc
!= 4) /* redraw */
5421 break; /* no redraw */
5425 if(rc
!= 1 && isdir
){ /* add trailing delim? */
5426 for(name_p
= new_name
; *name_p
&& *(name_p
+1) ; name_p
++)
5429 if(*name_p
== context
->dir
->delim
) /* lop off delim */
5434 || !(*new_name
|| (context
->use
& CNTXT_INCMNG
))
5435 || !strcmp(new_name
, folder
)){
5436 q_status_message(SM_ORDER
, 0, 2, _("Folder rename cancelled"));
5440 if(context
->use
& CNTXT_INCMNG
){
5441 char **new_list
, **lp
, ***alval
;
5444 alval
= ALVAL(&ps_global
->vars
[V_INCOMING_FOLDERS
], ew
);
5445 for(i
= 0; (*alval
)[i
]; i
++)
5448 new_list
= (char **) fs_get((i
+ 1) * sizeof(char *));
5450 for(lp
= new_list
, i
= 0; (*alval
)[i
]; i
++){
5451 /* figure out if this is the one we're renaming */
5452 expand_variables(tmp_20k_buf
, SIZEOF_20KBUF
, (*alval
)[i
], 0);
5453 if(new_f
->varhash
== line_hash(tmp_20k_buf
)){
5454 char *folder_string
= NULL
, *nickname
= NULL
;
5457 fs_give((void **) &new_f
->nickname
);
5460 new_f
->nickname
= cpystr(new_name
);
5463 * Parse folder line for nickname and folder name.
5464 * No nickname on line is OK.
5466 get_pair(tmp_20k_buf
, &nickname
, &folder_string
, 0, 0);
5469 fs_give((void **)&nickname
);
5471 *lp
= put_pair(new_name
, folder_string
);
5473 new_f
->varhash
= line_hash(*lp
++);
5476 *lp
++ = cpystr((*alval
)[i
]);
5481 set_variable_list(V_INCOMING_FOLDERS
, new_list
, TRUE
, ew
);
5482 free_list_array(&new_list
);
5487 /* Can't rename open streams */
5488 if((strm
= context_already_open_stream(context
, folder
, AOS_NONE
))
5489 || (ren_cur
&& (strm
=ps_global
->mail_stream
))){
5490 if(possible_stream
== strm
)
5491 possible_stream
= NULL
;
5493 pine_mail_actually_close(strm
);
5497 && !context_same_stream(context
, new_name
, possible_stream
))
5498 possible_stream
= NULL
;
5500 if((rc
= context_rename(context
, possible_stream
, folder
, new_name
)) != 0){
5501 if(name_p
&& *name_p
== context
->dir
->delim
)
5502 *name_p
= '\0'; /* blat trailing delim */
5504 /* insert new name? */
5505 if(!strindex(new_name
, context
->dir
->delim
)){
5506 new_f
= new_folder(new_name
, 0);
5507 new_f
->isdir
= isdir
;
5508 folder_insert(-1, new_f
, FOLDERS(context
));
5511 if(strcmp(ps_global
->VAR_DEFAULT_FCC
, folder
) == 0
5512 || strcmp(ps_global
->VAR_DEFAULT_SAVE_FOLDER
, folder
) == 0) {
5513 /* renaming sent-mail or saved-messages */
5514 if(context_create(context
, NULL
, folder
)){
5515 q_status_message3(SM_ORDER
,0,3,
5516 "Folder \"%s\" renamed to \"%s\". New \"%s\" created",
5519 (strcmp(ps_global
->VAR_DEFAULT_SAVE_FOLDER
,
5521 ? ps_global
->VAR_DEFAULT_SAVE_FOLDER
5522 : ps_global
->VAR_DEFAULT_FCC
));
5526 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
5527 "Error creating new \"%s\"", folder
);
5529 dprint((1, "Error creating \"%s\" in %s context\n",
5530 folder
? folder
: "?",
5531 context
->context
? context
->context
: "?"));
5535 q_status_message2(SM_ORDER
, 0, 3,
5536 "Folder \"%s\" renamed to \"%s\"",
5537 pretty_fn(folder
), pretty_fn(new_name
));
5539 free_folder_list(context
);
5543 if(ps_global
&& ps_global
->ttyo
){
5544 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
5545 ps_global
->mangled_footer
= 1;
5548 /* No reopen the folder we just had open */
5549 do_broach_folder(new_name
, context
, NULL
, 0L);
5556 /*----------------------------------------------------------------------
5557 Confirm and delete a folder
5559 Args: fs -- folder screen state
5561 Result: return 0 if not delete, 1 if deleted.
5564 delete_folder(CONTEXT_S
*context
, int index
, char *next_folder
, size_t len
, MAILSTREAM
**possible_streamp
)
5566 char *folder
, ques_buf
[MAX_SCREEN_COLS
+1], *target
= NULL
,
5568 MAILSTREAM
*del_stream
= NULL
, *sub_stream
, *strm
= NULL
;
5571 PINERC_S
*prc
= NULL
;
5572 int ret
, unsub_opened
= 0, close_opened
= 0, blast_folder
= 1,
5576 cmd_cancelled("Missing context in Delete");
5580 if(NEWS_TEST(context
)){
5581 folder
= folder_entry(index
, FOLDERS(context
))->name
;
5582 snprintf(ques_buf
, sizeof(ques_buf
), _("Really unsubscribe from \"%s\""), folder
);
5583 ques_buf
[sizeof(ques_buf
)-1] = '\0';
5585 ret
= want_to(ques_buf
, 'n', 'x', NO_HELP
, WT_NORM
);
5595 dprint((2, "deleting folder \"%s\" in context \"%s\"\n",
5596 folder
? folder
: "?",
5597 context
->context
? context
->context
: "?"));
5599 if((sub_stream
= mail_cmd_stream(context
, &unsub_opened
)) != NULL
){
5600 (void) context_apply(tmp_20k_buf
, context
, folder
, SIZEOF_20KBUF
);
5601 if(!mail_unsubscribe(sub_stream
, tmp_20k_buf
)){
5602 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
5603 _("Error unsubscribing from \"%s\""),folder
);
5605 pine_mail_close(sub_stream
);
5609 pine_mail_close(sub_stream
);
5613 * Fix up the displayed list
5615 folder_delete(index
, FOLDERS(context
));
5619 fp
= folder_entry(index
, FOLDERS(context
));
5621 cmd_cancelled("Can't find folder to Delete!");
5625 if(!((context
->use
& CNTXT_INCMNG
) && fp
->name
5626 && check_for_move_mbox(fp
->name
, NULL
, 0, &target
))){
5630 folder
= FLDR_NAME(fp
);
5631 dprint((4, "=== delete_folder(%s) ===\n",
5632 folder
? folder
: "?"));
5634 ew
= config_containing_inc_fldr(fp
);
5635 if(ps_global
->restricted
)
5640 prc
= ps_global
->prc
;
5643 prc
= ps_global
->post_prc
;
5649 readonly
= prc
? prc
->readonly
: 1;
5652 if(prc
&& prc
->quit_to_edit
&& (context
->use
& CNTXT_INCMNG
)){
5653 quit_to_edit_msg(prc
);
5657 if(context
== ps_global
->context_list
5658 && !(context
->dir
&& context
->dir
->ref
)
5659 && strucmp(folder
, ps_global
->inbox_name
) == 0){
5660 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
5661 _("Can't delete special folder \"%s\"."),
5662 ps_global
->inbox_name
);
5665 else if(readonly
&& (context
->use
& CNTXT_INCMNG
)){
5666 q_status_message(SM_ORDER
,3,5,
5667 _("Deletion cancelled: folder not in editable config file"));
5671 && (strm
=context_already_open_stream(context
,fp
->name
,AOS_NONE
)))
5674 && (strm
=context_already_open_stream(NULL
,target
,AOS_NONE
)))){
5675 if(strm
== ps_global
->mail_stream
)
5678 else if(fp
->isdir
|| fp
->isdual
){ /* NO DELETE if directory isn't EMPTY */
5679 FDIR_S
*fdirp
= next_folder_dir(context
,folder
,TRUE
,possible_streamp
);
5683 else if(fp
->hasnochildren
)
5686 ret
= folder_total(fdirp
->folders
) > 0;
5687 free_fdir(&fdirp
, 1);
5691 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
5692 _("Can't delete non-empty directory \"%s\"%s."),
5693 folder
, (fp
->isfolder
&& fp
->isdual
) ? " (or folder of same name)" : "");
5698 * Folder by the same name exist? If so, server's probably going
5699 * to delete it as well. Punt?
5702 && (ret
= want_to(DIR_FOLD_PMT
,'n','x',NO_HELP
,WT_NORM
)) != 'y'){
5703 q_status_message(SM_ORDER
,0,3, (ret
== 'x') ? _("Delete cancelled")
5704 : _("No folder deleted"));
5709 if(context
->use
& CNTXT_INCMNG
){
5710 static ESCKEY_S delf_opts
[] = {
5711 {'n', 'n', "N", N_("Nickname only")},
5712 {'b', 'b', "B", N_("Both Folder and Nickname")},
5715 #define DELF_PROMPT _("DELETE only Nickname or Both nickname and folder? ")
5717 switch(radio_buttons(DELF_PROMPT
, -FOOTER_ROWS(ps_global
),
5718 delf_opts
,'n','x',NO_HELP
,RB_NORM
)){
5724 cmd_cancelled("Delete");
5732 unsigned char *fname
= folder_name_decoded((unsigned char *)folder
);
5733 snprintf(ques_buf
, sizeof(ques_buf
), "DELETE \"%s\"%s", fname
? (char *) fname
: folder
,
5734 close_opened
? " (the currently open folder)" :
5735 (fp
->isdir
&& !(fp
->isdual
|| fp
->isfolder
5736 || (folder_index(folder
, context
, FI_FOLDER
) >= 0)))
5737 ? " (a directory)" : "");
5738 if(fname
) fs_give((void **)&fname
);
5739 ques_buf
[sizeof(ques_buf
)-1] = '\0';
5741 if((ret
= want_to(ques_buf
, 'n', 'x', NO_HELP
, WT_NORM
)) != 'y'){
5742 q_status_message(SM_ORDER
,0,3, (ret
== 'x') ? _("Delete cancelled")
5743 : _("Nothing deleted"));
5749 dprint((2,"deleting \"%s\" (%s) in context \"%s\"\n",
5750 fp
->name
? fp
->name
: "?",
5751 fp
->nickname
? fp
->nickname
: "",
5752 context
->context
? context
->context
: "?"));
5755 * Close it, NULL the pointer, and let do_broach_folder fixup
5758 pine_mail_actually_close(strm
);
5760 if(ps_global
&& ps_global
->ttyo
){
5761 blank_keymenu(ps_global
->ttyo
->screen_rows
- 2, 0);
5762 ps_global
->mangled_footer
= 1;
5765 ps_global
->mangled_header
= 1;
5766 do_broach_folder(ps_global
->inbox_name
,
5767 ps_global
->context_list
, NULL
, DB_INBOXWOCNTXT
);
5772 * Use fp->name since "folder" may be a nickname...
5774 if(possible_streamp
&& *possible_streamp
5775 && context_same_stream(context
, fp
->name
, *possible_streamp
))
5776 del_stream
= *possible_streamp
;
5780 if(!context_delete(context
, del_stream
, fnamep
)){
5782 * BUG: what if sent-mail or saved-messages????
5784 q_status_message1(SM_ORDER
,3,3,"Delete of \"%s\" Failed!", folder
);
5789 snprintf(buf
, sizeof(buf
), "%s\"%s\" deleted.",
5790 !blast_folder
? "Nickname " :
5791 fp
->isdual
? "Folder/Directory " :
5792 (fp
->isdir
&& fp
->isfolder
) ? "Folder " :
5793 fp
->isdir
? "Directory " :
5796 buf
[sizeof(buf
)-1] = '\0';
5798 q_status_message(SM_ORDER
, 0, 3, buf
);
5800 if(context
->use
& CNTXT_INCMNG
){
5801 char **new_list
, **lp
, ***alval
;
5804 alval
= ALVAL(&ps_global
->vars
[V_INCOMING_FOLDERS
], ew
);
5805 for(i
= 0; (*alval
)[i
]; i
++)
5809 * Make it one too big in case we don't find the match for
5810 * some unknown reason.
5812 new_list
= (char **) fs_get((i
+ 1) * sizeof(char *));
5815 * Copy while figuring out which one to skip.
5817 for(lp
= new_list
, i
= 0; (*alval
)[i
]; i
++){
5818 expand_variables(tmp_20k_buf
, SIZEOF_20KBUF
, (*alval
)[i
], 0);
5819 if(fp
->varhash
!= line_hash(tmp_20k_buf
))
5820 *lp
++ = cpystr((*alval
)[i
]);
5825 set_variable_list(V_INCOMING_FOLDERS
, new_list
, TRUE
, ew
);
5826 free_list_array(&new_list
);
5830 * Fix up the displayed list.
5832 folder_delete(index
, FOLDERS(context
));
5835 * Take a guess at what should get hilited next.
5837 if(index
< (ret
= folder_total(FOLDERS(context
)))
5838 || ((index
= ret
- 1) >= 0)){
5839 if((fp
= folder_entry(index
, FOLDERS(context
)))
5840 && strlen(FLDR_NAME(fp
)) < len
- 1)
5841 strncpy(next_folder
, FLDR_NAME(fp
), len
-1);
5842 next_folder
[len
-1] = '\0';
5845 if(!(context
->use
& CNTXT_INCMNG
)){
5847 * Then cause the list to get rebuild 'cause we may've blasted
5848 * some folder that's also a directory or vice versa...
5850 free_folder_list(context
);
5857 /*----------------------------------------------------------------------
5858 Print the list of folders on paper
5860 Args: list -- The current list of folders
5861 lens -- The list of lengths of the current folders
5862 display -- The current folder display structure
5864 Result: list printed on paper
5866 If the display list was created for 80 columns it is used, otherwise
5867 a new list is created for 80 columns
5871 print_folders(FPROC_S
*fp
)
5873 if(open_printer(_("folder list")) == 0){
5874 (void) folder_list_text(ps_global
, fp
, print_char
, NULL
, 80);
5882 scan_get_pattern(char *kind
, char *pat
, int len
)
5888 snprintf(prompt
, sizeof(prompt
), _("String in folder %s to match : "), kind
);
5889 prompt
[sizeof(prompt
)-1] = '\0';
5892 flags
= OE_APPEND_CURRENT
| OE_DISALLOW_HELP
;
5893 switch(optionally_enter(pat
, -FOOTER_ROWS(ps_global
), 0, len
,
5894 prompt
, NULL
, NO_HELP
, &flags
)){
5897 if(ps_global
->redrawer
)
5898 (*ps_global
->redrawer
)();
5907 cmd_cancelled("Select");
5917 folder_select_text(struct pine
*ps
, CONTEXT_S
*context
, int selected
)
5919 char pattern
[MAILTMPLEN
], type
= '\0';
5920 static ESCKEY_S scan_opts
[] = {
5921 {'n', 'n', "N", N_("Name Select")},
5922 {'c', 'c', "C", N_("Content Select")},
5926 if(context
->use
& CNTXT_INCMNG
){
5927 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
5928 _("Select \"Text\" not supported in Incoming Folders"));
5932 switch(radio_buttons(SEL_TEXT_PMT
, -FOOTER_ROWS(ps_global
),
5933 scan_opts
, 'n', 'x', NO_HELP
, RB_NORM
)){
5934 case 'n' : /* Name search */
5935 if(scan_get_pattern("NAME", pattern
, sizeof(pattern
)))
5940 case 'c' : /* content search */
5941 if(scan_get_pattern("CONTENTS", pattern
, sizeof(pattern
)))
5953 char tmp
[MAILTMPLEN
];
5956 memset(&args
, 0, sizeof(SCANARG_S
));
5957 args
.pattern
= pattern
;
5959 args
.context
= context
;
5962 args
.stream
= sp_stream_get(context_apply(tmp
, context
,
5963 "xxx", sizeof(tmp
)),
5966 args
.stream
= pine_mail_open(NULL
, tmp
,
5967 OP_SILENT
|OP_HALFOPEN
|SP_USEPOOL
|SP_TEMPUSE
,
5969 args
.newstream
= (args
.stream
!= NULL
);
5973 rv
= foreach_folder(context
, selected
,
5974 foreach_do_scan
, (void *) &args
);
5977 pine_mail_close(args
.stream
);
5983 cmd_cancelled("Select");
5989 foreach_do_scan(FOLDER_S
*f
, void *d
)
5991 SCANARG_S
*sa
= (SCANARG_S
*) d
;
5993 return((sa
->type
== 'n' && srchstr(FLDR_NAME(f
), sa
->pattern
))
5995 && scan_scan_folder(sa
->stream
, sa
->context
, f
, sa
->pattern
)));
6000 scan_scan_folder(MAILSTREAM
*stream
, CONTEXT_S
*context
, FOLDER_S
*f
, char *pattern
)
6005 char *folder
, *ref
= NULL
, tmp
[MAILTMPLEN
];
6008 snprintf(tmp
, sizeof(tmp
), "Scanning \"%s\"", FLDR_NAME(f
));
6009 tmp
[sizeof(tmp
)-1] = '\0';
6010 we_cancel
= busy_cue(tmp
, NULL
, 1);
6012 mm_list_info
= &ldata
; /* tie down global reference */
6013 memset(&ldata
, 0, sizeof(MM_LIST_S
));
6014 ldata
.filter
= mail_list_response
;
6015 memset(ldata
.data
= &response
, 0, sizeof(LISTRES_S
));
6018 * If no preset reference string, must be at top of context
6020 if(context
&& context_isambig(folder
) && !(ref
= context
->dir
->ref
)){
6023 if((p
= strstr(context
->context
, "%s")) != NULL
){
6025 snprintf(tmp
, sizeof(tmp
), "%.*s", (int) MIN(p
- context
->context
, sizeof(tmp
)-1),
6027 tmp
[sizeof(tmp
)-1] = '\0';
6031 snprintf(tmp
, sizeof(tmp
), context
->context
, folder
);
6032 tmp
[sizeof(tmp
)-1] = '\0';
6038 ref
= context
->context
;
6041 mail_scan(stream
, ref
, folder
, pattern
);
6043 if(context
&& context
->dir
&& response
.delim
)
6044 context
->dir
->delim
= response
.delim
;
6047 cancel_busy_cue(-1);
6049 return(((response
.isfile
) ? FEX_ISFILE
: 0)
6050 | ((response
.isdir
) ? FEX_ISDIR
: 0));
6055 folder_select_props(struct pine
*ps
, CONTEXT_S
*context
, int selected
)
6058 long flags
= 0L, count
;
6059 static ESCKEY_S prop_opts
[] = {
6060 {'u', 'u', "U", N_("Unseen msgs")},
6061 {'n', 'n', "N", N_("New msgs")},
6062 {'c', 'c', "C", N_("msg Count")},
6066 if(context
->use
& CNTXT_INCMNG
){
6067 q_status_message(SM_ORDER
| SM_DING
, 3, 3,
6068 _("Select \"Properties\" not supported in Incoming Folders"));
6072 switch(radio_buttons(SEL_PROP_PMT
, -FOOTER_ROWS(ps_global
),
6073 prop_opts
, 'n', 'x', h_folder_prop
, RB_NORM
)){
6074 case 'c' : /* message count */
6075 if(folder_select_count(&count
, &cmp
))
6076 flags
= SA_MESSAGES
;
6080 case 'n' : /* folders with new */
6084 case 'u' : /* folders with unseen */
6095 char tmp
[MAILTMPLEN
];
6098 memset(&args
, 0, sizeof(STATARG_S
));
6100 args
.context
= context
;
6104 args
.stream
= sp_stream_get(context_apply(tmp
, context
,
6105 "xxx", sizeof(tmp
)),
6108 args
.stream
= pine_mail_open(NULL
, tmp
,
6109 OP_SILENT
|OP_HALFOPEN
|SP_USEPOOL
|SP_TEMPUSE
,
6111 args
.newstream
= (args
.stream
!= NULL
);
6114 rv
= foreach_folder(context
, selected
,
6115 foreach_do_stat
, (void *) &args
);
6118 pine_mail_close(args
.stream
);
6124 cmd_cancelled("Select");
6130 folder_select_count(long int *count
, int *cmp
)
6133 char number
[32], prompt
[128];
6134 static char *tense
[] = {"EQUAL TO", "LESS THAN", "GREATER THAN"};
6135 static ESCKEY_S sel_num_opt
[] = {
6136 {ctrl('W'), 14, "^W", N_("Toggle Comparison")},
6142 flags
= OE_APPEND_CURRENT
| OE_DISALLOW_HELP
;
6143 snprintf(number
, sizeof(number
), "%ld", *count
);
6144 number
[sizeof(number
)-1] = '\0';
6145 snprintf(prompt
, sizeof(prompt
), "Select folders with messages %s : ", tense
[*cmp
]);
6146 prompt
[sizeof(prompt
)-1] = '\0';
6147 r
= optionally_enter(number
, -FOOTER_ROWS(ps_global
), 0, sizeof(number
),
6148 prompt
, sel_num_opt
, NO_HELP
, &flags
);
6153 else if((*count
= atol(number
)) < 0L)
6154 q_status_message(SM_ORDER
, 3, 3,
6155 "Can't have NEGATIVE message count!");
6157 return(1); /* success */
6160 case 4 : /* redraw */
6163 case 14 : /* toggle comparison */
6168 case -1 : /* cancel */
6176 return(0); /* return failure */
6181 foreach_do_stat(FOLDER_S
*f
, void *d
)
6183 STATARG_S
*sa
= (STATARG_S
*) d
;
6186 if(ps_global
->context_current
== sa
->context
6187 && !strcmp(ps_global
->cur_folder
, FLDR_NAME(f
))){
6191 case 0 : /* equals */
6192 if(ps_global
->mail_stream
->nmsgs
== sa
->nmsgs
)
6197 case 1 : /* less than */
6198 if(ps_global
->mail_stream
->nmsgs
< sa
->nmsgs
)
6204 if(ps_global
->mail_stream
->nmsgs
> sa
->nmsgs
)
6216 if(count_flagged(ps_global
->mail_stream
, F_RECENT
))
6222 if(count_flagged(ps_global
->mail_stream
, F_UNSEEN
))
6233 char msg_buf
[MAX_BM
+1];
6234 extern MAILSTATUS mm_status_result
;
6236 snprintf(msg_buf
, sizeof(msg_buf
), "Checking %s for %s", FLDR_NAME(f
),
6237 (sa
->flags
== SA_UNSEEN
)
6239 : (sa
->flags
== SA_MESSAGES
) ? "message count"
6240 : "recent messages");
6241 msg_buf
[sizeof(msg_buf
)-1] = '\0';
6242 we_cancel
= busy_cue(msg_buf
, NULL
, 0);
6244 if(!context_status(sa
->context
, sa
->stream
, f
->name
, sa
->flags
))
6245 mm_status_result
.flags
= 0L;
6250 if(sa
->flags
& mm_status_result
.flags
)
6254 case 0 : /* equals */
6255 if(mm_status_result
.messages
== sa
->nmsgs
)
6260 case 1 : /* less than */
6261 if(mm_status_result
.messages
< sa
->nmsgs
)
6267 if(mm_status_result
.messages
> sa
->nmsgs
)
6279 if(mm_status_result
.recent
)
6285 if(mm_status_result
.unseen
)
6300 foreach_folder(CONTEXT_S
*context
, int selected
, int (*test
) (FOLDER_S
*, void *), void *args
)
6303 int we_turned_on
= 0;
6306 we_turned_on
= intr_handling_on();
6308 for(i
= 0, n
= folder_total(FOLDERS(context
)); i
< n
; i
++){
6309 if(ps_global
->intr_pending
){
6311 folder_entry(i
, FOLDERS(context
))->scanned
= 0;
6313 cmd_cancelled("Select");
6318 fp
= folder_entry(i
, FOLDERS(context
));
6320 if((!selected
|| fp
->selected
) && fp
->isfolder
&& (*test
)(fp
, args
))
6325 intr_handling_off();
6331 /*----------------------------------------------------------------------
6332 Return the path delimiter for the given folder on the given server
6334 Args: folder -- folder type for delimiter
6338 folder_delimiter(char *folder
)
6340 int rv
, we_cancel
= 0;
6342 we_cancel
= busy_cue(NULL
, NULL
, 1);
6344 rv
= get_folder_delimiter(folder
);
6347 cancel_busy_cue(-1);
6354 * next_folder - given a current folder in a context, return the next in
6355 * the list, or NULL if no more or there's a problem.
6357 * Args streamp -- If set, try to re-use this stream for checking.
6358 * next -- Put return value here, return points to this
6359 * nextlen -- Length of next
6360 * current -- Current folder, so we know where to start looking
6362 * find_recent -- Returns the number of recent here. The presence of
6363 * this arg also indicates that we should do the calls
6364 * to figure out whether there is a next interesting folder
6366 * did_cancel -- Tell caller if user canceled. Only used if find_recent
6367 * is also set. Also, user will only be given the
6368 * opportunity to cancel if this is set. If it isn't
6369 * set, we just plow ahead when there is an error or
6370 * when the folder does not exist.
6373 next_folder(MAILSTREAM
**streamp
, char *next
, size_t nextlen
, char *current
, CONTEXT_S
*cntxt
, long int *find_recent
, int *did_cancel
)
6375 int index
, recent
= 0, failed_status
= 0, try_fast
;
6378 char tmp
[MAILTMPLEN
];
6381 /* note: find_folders may assign "stream" */
6382 build_folder_list(streamp
, cntxt
, NULL
, NULL
,
6383 NEWS_TEST(cntxt
) ? BFL_LSUB
: BFL_NONE
);
6385 try_fast
= (F_ON(F_ENABLE_FAST_RECENT
, ps_global
) &&
6386 F_OFF(F_TAB_USES_UNSEEN
, ps_global
));
6390 for(index
= folder_index(current
, cntxt
, FI_FOLDER
) + 1;
6392 && index
< folder_total(FOLDERS(cntxt
))
6393 && (f
= folder_entry(index
, FOLDERS(cntxt
)))
6397 MAILSTREAM
*stream
= NULL
;
6398 int rv
, we_cancel
= 0, match
;
6399 char msg_buf
[MAX_BM
+1];
6401 /* must be a folder and it can't be the current one */
6402 if(ps_global
->context_current
== ps_global
->context_list
6403 && !strcmp(ps_global
->cur_folder
, FLDR_NAME(f
)))
6407 * If we already have the folder open, short circuit all this
6411 if((stream
= sp_stream_get(context_apply(tmp
, cntxt
, f
->name
,
6414 || (!IS_REMOTE(tmp
) && (stream
= already_open_stream(tmp
, AOS_NONE
)) != NULL
)){
6415 (void) pine_mail_ping(stream
);
6417 if(F_ON(F_TAB_USES_UNSEEN
, ps_global
)){
6419 * Just fall through and let the status call below handle
6420 * the already open stream. If we were doing this the
6421 * same as the else case, we would figure out how many
6422 * unseen are in this open stream by doing a search.
6423 * Instead of repeating that code that is already in
6424 * pine_mail_status_full, fall through and note the
6425 * special case by lighting the match variable.
6430 *find_recent
= sp_recent_since_visited(stream
);
6440 snprintf(msg_buf
, sizeof(msg_buf
), "Checking %s for %s messages",
6441 FLDR_NAME(f
), F_ON(F_TAB_USES_UNSEEN
, ps_global
) ? "unseen" : "recent");
6442 msg_buf
[sizeof(msg_buf
)-1] = '\0';
6443 we_cancel
= busy_cue(msg_buf
, NULL
, 0);
6445 /* First, get a stream for the test */
6446 if(!stream
&& streamp
&& *streamp
){
6447 if(context_same_stream(cntxt
, f
->name
, *streamp
)){
6451 pine_mail_close(*streamp
);
6457 stream
= sp_stream_get(context_apply(tmp
, cntxt
, f
->name
,
6463 * If interestingness is indeterminate or we're
6464 * told to explicitly, look harder...
6468 * We could make this more efficient in the cases where we're
6469 * opening a new stream or using streamp by having folder_exists
6470 * cache the stream. The change would require a folder_exists()
6471 * that caches streams, but most of the time folder_exists just
6472 * uses the inbox stream or ps->mail_stream.
6474 * Another thing to consider is that maybe there should be an
6475 * option to try to LIST a folder before doing a STATUS (or SELECT).
6476 * This isn't done by default for the case where a folder is
6477 * SELECTable but not LISTable, but on some servers doing an
6478 * RLIST first tells the server that we support mailbox referrals.
6481 || !((rv
= folder_exists(cntxt
,f
->name
))
6482 & (FEX_ISMARKED
| FEX_UNMARKED
))){
6483 extern MAILSTATUS mm_status_result
;
6485 if(try_fast
&& (rv
== 0 || rv
& FEX_ERROR
)){
6487 mm_status_result
.flags
= 0L;
6491 if(!context_status_full(cntxt
, match
? NULL
: stream
,
6493 F_ON(F_TAB_USES_UNSEEN
, ps_global
)
6494 ? SA_UNSEEN
: SA_RECENT
,
6498 mm_status_result
.flags
= 0L;
6502 /* so we can re-use the stream */
6503 if(!context_status_streamp_full(cntxt
, streamp
, f
->name
,
6504 F_ON(F_TAB_USES_UNSEEN
, ps_global
)
6505 ? SA_UNSEEN
: SA_RECENT
,
6509 mm_status_result
.flags
= 0L;
6514 if(F_ON(F_TAB_USES_UNSEEN
, ps_global
)){
6515 rv
= ((mm_status_result
.flags
& SA_UNSEEN
)
6516 && (*find_recent
= mm_status_result
.unseen
))
6520 rv
= ((mm_status_result
.flags
& SA_RECENT
)
6521 && (*find_recent
= mm_status_result
.recent
))
6525 /* we don't know how many in this case */
6527 *find_recent
= 0L; /* consistency, boy! */
6533 if(failed_status
&& did_cancel
){
6534 char buf1
[6*MAX_SCREEN_COLS
+1];
6537 snprintf(prompt
, sizeof(prompt
), _("Check of folder %s failed. Continue "), FLDR_NAME(f
));
6538 if(utf8_width(prompt
) > MAXPROMPT
){
6539 snprintf(prompt
, sizeof(prompt
), _("Check of %s failed. Continue "), FLDR_NAME(f
));
6540 if((wid1
=utf8_width(prompt
)) > MAXPROMPT
){
6541 if((wid2
=utf8_width(FLDR_NAME(f
))) > wid1
-MAXPROMPT
)
6542 snprintf(prompt
, sizeof(prompt
), _("Check of %s failed. Continue "), strsquish(buf1
, sizeof(buf1
), FLDR_NAME(f
), wid2
-(wid1
-MAXPROMPT
)));
6544 snprintf(prompt
, sizeof(prompt
), _("Check failed. Continue "));
6548 if(want_to(prompt
, 'y', 0, NO_HELP
, WT_NORM
) == 'n'){
6553 /* have to reset this lower-level cancel marker */
6554 ps_global
->user_says_cancel
= 0;
6559 if(rv
& FEX_ISMARKED
){
6565 if(f
&& (!find_recent
|| recent
)){
6566 strncpy(next
, FLDR_NAME(f
), nextlen
);
6567 next
[nextlen
-1] = '\0';
6569 else if(nextlen
> 0)
6572 /* BUG: how can this be made smarter so we cache the list? */
6573 free_folder_list(cntxt
);
6574 return((*next
) ? next
: NULL
);
6578 /*----------------------------------------------------------------------
6579 Shuffle order of incoming folders
6582 shuffle_incoming_folders(CONTEXT_S
*context
, int index
)
6584 int tot
, i
, deefault
, rv
, inheriting
= 0;
6585 int new_index
, index_within_var
, new_index_within_var
;
6593 PINERC_S
*prc
= NULL
;
6595 dprint((4, "shuffle_incoming_folders\n"));
6597 if(!(context
->use
& CNTXT_INCMNG
) ||
6598 (tot
= folder_total(FOLDERS(context
))) < 2 ||
6599 index
< 0 || index
>= tot
)
6603 q_status_message(SM_ORDER
,0,3, _("Cannot shuffle INBOX"));
6607 fp
= folder_entry(index
, FOLDERS(context
));
6608 ew
= config_containing_inc_fldr(fp
);
6610 if(ps_global
->restricted
)
6615 prc
= ps_global
->prc
;
6618 prc
= ps_global
->post_prc
;
6624 readonly
= prc
? prc
->readonly
: 1;
6627 if(prc
&& prc
->quit_to_edit
){
6628 quit_to_edit_msg(prc
);
6633 q_status_message(SM_ORDER
,3,5,
6634 _("Shuffle cancelled: config file not editable"));
6638 alval
= ALVAL(&ps_global
->vars
[V_INCOMING_FOLDERS
], ew
);
6640 if(!(alval
&& *alval
))
6647 opts
[i
++].label
= N_("Back");
6652 opts
[i
++].label
= N_("Forward");
6657 /* find where this entry is in the particular config list */
6658 index_within_var
= -1;
6659 for(i
= 0; (*alval
)[i
]; i
++){
6660 expand_variables(tmp_20k_buf
, SIZEOF_20KBUF
, (*alval
)[i
], 0);
6661 if(i
== 0 && !strcmp(tmp_20k_buf
, INHERIT
))
6663 else if(fp
->varhash
== line_hash(tmp_20k_buf
)){
6664 index_within_var
= i
;
6669 if(index_within_var
== -1){ /* didn't find it */
6670 q_status_message(SM_ORDER
,3,5,
6671 _("Shuffle cancelled: unexpected trouble shuffling"));
6675 if(index_within_var
== 0 || (inheriting
&& index_within_var
== 1)){
6676 opts
[0].ch
= -2; /* no back */
6680 if(!(*alval
)[i
+1]) /* no forward */
6683 if(opts
[0].ch
== -2 && opts
[1].ch
== -2){
6684 q_status_message(SM_ORDER
, 0, 4,
6685 _("Cannot shuffle from one config file to another."));
6689 snprintf(tmp
, sizeof(tmp
), "Shuffle \"%s\" %s%s%s ? ",
6690 FLDR_NAME(folder_entry(index
, FOLDERS(context
))),
6691 (opts
[0].ch
!= -2) ? "BACK" : "",
6692 (opts
[0].ch
!= -2 && opts
[1].ch
!= -2) ? " or " : "",
6693 (opts
[1].ch
!= -2) ? "FORWARD" : "");
6694 tmp
[sizeof(tmp
)-1] = '\0';
6695 help
= (opts
[0].ch
== -2) ? h_incoming_shuf_down
6696 : (opts
[1].ch
== -2) ? h_incoming_shuf_up
6699 rv
= radio_buttons(tmp
, -FOOTER_ROWS(ps_global
), opts
, deefault
, 'x',
6703 new_index_within_var
= index_within_var
;
6707 cmd_cancelled("Shuffle");
6711 new_index_within_var
--;
6716 new_index_within_var
++;
6721 if(swap_incoming_folders(index
, new_index
, FOLDERS(context
))){
6724 /* swap them in the config variable, too */
6725 stmp
= (*alval
)[index_within_var
];
6726 (*alval
)[index_within_var
] = (*alval
)[new_index_within_var
];
6727 (*alval
)[new_index_within_var
] = stmp
;
6729 set_current_val(&ps_global
->vars
[V_INCOMING_FOLDERS
], TRUE
, FALSE
);
6730 write_pinerc(ps_global
, ew
, WRP_NONE
);
6740 swap_incoming_folders(int index1
, int index2
, FLIST
*flist
)
6747 if(index1
== index2
)
6750 if(index1
< 0 || index1
>= flist
->used
){
6751 dprint((1, "Error in swap_incoming_folders: index1=%d, used=%d\n", index1
, flist
->used
));
6755 if(index2
< 0 || index2
>= flist
->used
){
6756 dprint((1, "Error in swap_incoming_folders: index2=%d, used=%d\n", index2
, flist
->used
));
6760 ftmp
= flist
->folders
[index1
];
6761 flist
->folders
[index1
] = flist
->folders
[index2
];
6762 flist
->folders
[index2
] = ftmp
;
6768 /*----------------------------------------------------------------------
6769 Find an entry in the folder list by matching names
6772 search_folder_list(void *list
, char *name
)
6777 for(i
= 0; i
< folder_total(list
); i
++) {
6778 n
= folder_entry(i
, list
)->name
;
6779 if(strucmp(name
, n
) == 0)
6780 return(1); /* Found it */
6786 static CONTEXT_S
*post_cntxt
= NULL
;
6788 /*----------------------------------------------------------------------
6789 Browse list of newsgroups available for posting
6791 Called from composer when ^T is typed in newsgroups field
6795 Returns: pointer to selected newsgroup, or NULL.
6796 Selector call in composer expects this to be alloc'd here.
6800 news_group_selector(char **error_mess
)
6807 /* Coming back from composer */
6808 fix_windsize(ps_global
);
6811 post_folder
= fs_get((size_t)MAILTMPLEN
);
6813 /*--- build the post_cntxt -----*/
6814 em
= get_post_list(ps_global
->VAR_NNTP_SERVER
);
6816 if(error_mess
!= NULL
)
6817 *error_mess
= cpystr(em
);
6819 cancel_busy_cue(-1);
6823 /*----- Call the browser -------*/
6825 if((rc
= folders_for_post(ps_global
, &tc
, post_folder
)) != 0)
6828 cancel_busy_cue(-1);
6833 return(post_folder
);
6837 /*----------------------------------------------------------------------
6838 Get the list of news groups that are possible for posting
6840 Args: post_host -- host name for posting
6842 Returns NULL if list is retrieved, pointer to error message if failed
6844 This is kept in a standards "CONTEXT" for a acouple of reasons. First
6845 it makes it very easy to use the folder browser to display the
6846 newsgroup for selection on ^T from the composer. Second it will allow
6847 the same mechanism to be used for all folder lists on memory tight
6848 systems like DOS. The list is kept for the life of the session because
6849 fetching it is a expensive.
6853 get_post_list(char **post_host
)
6855 char *post_context_string
;
6857 if(!post_host
|| !post_host
[0]) {
6858 /* BUG should assume inews and get this from active file */
6859 return(_("Can't post messages, NNTP server needs to be configured"));
6866 we_cancel
= busy_cue(_("Getting full list of groups for posting"), NULL
, 1);
6868 l
= strlen(post_host
[0]) + 20;
6869 post_context_string
= (char *) fs_get((l
+1) * sizeof(char));
6870 snprintf(post_context_string
, l
+1, "{%s/nntp}#news.[]", post_host
[0]);
6871 post_context_string
[l
] = '\0';
6873 post_cntxt
= new_context(post_context_string
, NULL
);
6874 post_cntxt
->use
|= CNTXT_FINDALL
;
6875 post_cntxt
->dir
->status
|= CNTXT_NOFIND
;
6876 post_cntxt
->next
= NULL
;
6878 build_folder_list(NULL
, post_cntxt
, NULL
, NULL
,
6879 NEWS_TEST(post_cntxt
) ? BFL_LSUB
: BFL_NONE
);
6881 cancel_busy_cue(-1);
6888 fcc_tab_complete (char *prefix
, char **answer
, int tabtab
, unsigned flags
)
6890 char tmp
[MAILTMPLEN
+1];
6894 if(prefix
== NULL
|| *prefix
== '\0')
6897 for(mc
= ps_global
->context_list
; mc
!= NULL
; mc
= mc
->next
)
6898 if(mc
->use
& CNTXT_SAVEDFLT
)
6901 if(mc
== NULL
) return 0;
6903 strncpy(tmp
, prefix
, sizeof(tmp
));
6904 tmp
[sizeof(tmp
)-1] = '\0';
6906 if(!folder_complete(mc
, tmp
, sizeof(tmp
), &n
)){
6909 display_folder_list(&mc
, tmp
, 1,folders_for_goto
);
6915 *answer
= cpystr(tmp
);
6916 return n
== 0 ? 0 : n
== 1 ? 2 : 1;
6923 folder_list_popup(sparms
, in_handle
)
6927 MPopup fldr_popup
[20];
6929 memset(fldr_popup
, 0, 20 * sizeof(MPopup
));
6930 fldr_popup
[0].type
= tTail
;
6933 HANDLE_S
*h
= get_handle(sparms
->text
.handles
, in_handle
);
6934 FOLDER_S
*fp
= (h
) ? folder_entry(h
->h
.f
.index
,
6935 FOLDERS(h
->h
.f
.context
))
6938 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_CHOICE
)) >= 0){
6939 fldr_popup
[n
].type
= tQueue
;
6940 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
6941 fldr_popup
[n
].label
.style
= lNormal
;
6942 fldr_popup
[n
++].label
.string
= (fp
&& fp
->isdir
)
6947 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_SELCUR
)) >= 0
6948 && bitnset(i
, sparms
->keys
.bitmap
)){
6949 fldr_popup
[n
].type
= tQueue
;
6950 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
6951 fldr_popup
[n
].label
.style
= lNormal
;
6952 fldr_popup
[n
++].label
.string
= (fp
&& fp
->isdir
)
6953 ? "&Select Directory"
6957 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_DELETE
)) >= 0
6958 && bitnset(i
, sparms
->keys
.bitmap
)){
6959 fldr_popup
[n
].type
= tQueue
;
6960 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
6961 fldr_popup
[n
].label
.style
= lNormal
;
6962 fldr_popup
[n
++].label
.string
= "Delete Folder";
6965 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_EXPORT
)) >= 0
6966 && bitnset(i
, sparms
->keys
.bitmap
)){
6967 fldr_popup
[n
].type
= tQueue
;
6968 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
6969 fldr_popup
[n
].label
.style
= lNormal
;
6970 fldr_popup
[n
++].label
.string
= "Export Folder";
6973 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_CHK_RECENT
)) >= 0
6974 && bitnset(i
, sparms
->keys
.bitmap
)){
6975 fldr_popup
[n
].type
= tQueue
;
6976 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
6977 fldr_popup
[n
].label
.style
= lNormal
;
6978 fldr_popup
[n
++].label
.string
= "Check New Messages";
6982 fldr_popup
[n
++].type
= tSeparator
;
6984 folder_popup_config(((FPROC_S
*)sparms
->proc
.data
.p
)->fs
,
6985 sparms
->keys
.menu
, &fldr_popup
[n
]);
6988 folder_popup_config(((FPROC_S
*)sparms
->proc
.data
.p
)->fs
,
6989 sparms
->keys
.menu
, fldr_popup
);
6991 if(fldr_popup
[0].type
!= tTail
)
6992 mswin_popup(fldr_popup
);
6999 folder_list_select_popup(sparms
, in_handle
)
7003 MPopup fldr_popup
[20];
7005 memset(fldr_popup
, 0, 20 * sizeof(MPopup
));
7006 fldr_popup
[0].type
= tTail
;
7009 HANDLE_S
*h
= get_handle(sparms
->text
.handles
, in_handle
);
7010 FOLDER_S
*fp
= (h
) ? folder_entry(h
->h
.f
.index
,FOLDERS(h
->h
.f
.context
))
7013 if((i
= menu_binding_index(sparms
->keys
.menu
, MC_CHOICE
)) >= 0){
7014 fldr_popup
[n
].type
= tQueue
;
7015 fldr_popup
[n
].data
.val
= sparms
->keys
.menu
->keys
[i
].bind
.ch
[0];
7016 fldr_popup
[n
].label
.style
= lNormal
;
7017 fldr_popup
[n
++].label
.string
= (fp
&& fp
->isdir
)
7021 fldr_popup
[n
++].type
= tSeparator
;
7024 folder_popup_config(((FPROC_S
*)sparms
->proc
.data
.p
)->fs
,
7025 sparms
->keys
.menu
, &fldr_popup
[n
]);
7028 folder_popup_config(((FPROC_S
*)sparms
->proc
.data
.p
)->fs
,
7029 sparms
->keys
.menu
, fldr_popup
);
7031 if(fldr_popup
[0].type
!= tTail
)
7032 mswin_popup(fldr_popup
);
7039 * Just a little something to simplify assignments
7041 #define FLDRPOPUP(p, c, s) { \
7042 (p)->type = tQueue; \
7043 (p)->data.val = c; \
7044 (p)->label.style = lNormal; \
7045 (p)->label.string = s; \
7049 /*----------------------------------------------------------------------
7050 Popup Menu configurator
7054 folder_popup_config(fs
, km
, popup
)
7056 struct key_menu
*km
;
7061 if((i
= menu_binding_index(km
, MC_PARENT
)) >= 0){
7062 FLDRPOPUP(popup
, km
->keys
[i
].bind
.ch
[0], "Parent Directory");
7066 if(fs
->km
== &folder_km
){
7067 if((fs
->context
->next
|| fs
->context
->prev
) && !fs
->combined_view
){
7068 FLDRPOPUP(popup
, '<', "Collection List");
7072 else if((i
= menu_binding_index(km
, MC_COLLECTIONS
)) >= 0){
7073 FLDRPOPUP(popup
, km
->keys
[i
].bind
.ch
[0], "Collection List");
7077 if((i
= menu_binding_index(km
, MC_INDEX
)) >= 0){
7078 FLDRPOPUP(popup
, km
->keys
[i
].bind
.ch
[0], "Current Folder Index");
7082 if((i
= menu_binding_index(km
, MC_MAIN
)) >= 0){
7083 FLDRPOPUP(popup
, km
->keys
[i
].bind
.ch
[0], "Main Menu");
7087 popup
->type
= tTail
; /* tie off the array */
7089 #endif /* _WINDOWS */