1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: mailindx.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2016 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
29 #include "../pith/flag.h"
30 #include "../pith/newmail.h"
31 #include "../pith/thread.h"
32 #include "../pith/conf.h"
33 #include "../pith/msgno.h"
34 #include "../pith/icache.h"
35 #include "../pith/state.h"
36 #include "../pith/bitmap.h"
37 #include "../pith/news.h"
38 #include "../pith/strlst.h"
39 #include "../pith/sequence.h"
40 #include "../pith/sort.h"
41 #include "../pith/hist.h"
42 #include "../pith/busy.h"
43 #include "../pith/signal.h"
46 struct save_thrdinfo
{
47 ICE_S
*(*format_index_line
)(INDEXDATA_S
*);
48 void (*setup_header_widths
)(MAILSTREAM
*);
49 unsigned viewing_a_thread
:1;
53 static OtherMenu what_keymenu
= FirstMenu
;
55 struct index_state
*current_index_state
= NULL
;
61 void index_index_screen(struct pine
*);
62 void thread_index_screen(struct pine
*);
63 int update_index(struct pine
*, struct index_state
*);
64 int index_scroll_up(long);
65 int index_scroll_down(long);
66 int index_scroll_to_pos(long);
67 long top_ent_calc(MAILSTREAM
*, MSGNO_S
*, long, long);
68 void reset_index_border(void);
69 void redraw_index_body(void);
70 int paint_index_line(ICE_S
*, int, long, IndexColType
, IndexColType
, IndexColType
,
71 struct entry_state
*, int, int);
72 void pine_imap_envelope(MAILSTREAM
*, unsigned long, ENVELOPE
*);
73 void index_search(struct pine
*, MAILSTREAM
*, int, MSGNO_S
*);
75 int index_scroll_callback(int,long);
76 int index_gettext_callback(char *, size_t, void **, long *, int *);
77 void index_popup(IndexType style
, MAILSTREAM
*, MSGNO_S
*, int);
78 char *pcpine_help_index(char *);
79 char *pcpine_help_index_simple(char *);
84 /*----------------------------------------------------------------------
89 do_index_border(CONTEXT_S
*cntxt
, char *folder
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
,
90 IndexType style
, int *which_keys
, int flags
)
92 struct key_menu
*km
= (style
== ThreadIndex
)
94 : (ps_global
->mail_stream
!= stream
)
95 ? &simple_index_keymenu
98 if(flags
& INDX_CLEAR
)
101 if(flags
& INDX_HEADER
)
102 set_titlebar((style
== ThreadIndex
)
103 /* TRANSLATORS: these are some screen titles */
105 : (stream
== ps_global
->mail_stream
)
106 ? (style
== MsgIndex
|| style
== MultiMsgIndex
)
108 : _("ZOOMED MESSAGE INDEX")
109 : (!strcmp(folder
, INTERRUPTED_MAIL
))
110 ? _("COMPOSE: SELECT INTERRUPTED")
111 : (ps_global
->VAR_FORM_FOLDER
112 && !strcmp(ps_global
->VAR_FORM_FOLDER
, folder
))
113 ? _("COMPOSE: SELECT FORM LETTER")
114 : _("COMPOSE: SELECT POSTPONED"),
115 stream
, cntxt
, folder
, msgmap
, 1,
116 (style
== ThreadIndex
) ? ThrdIndex
118 && sp_viewing_a_thread(stream
))
123 if(flags
& INDX_FOOTER
) {
129 if(km
== &index_keymenu
){
130 if(THREADING() && sp_viewing_a_thread(stream
)){
131 menu_init_binding(km
, '<', MC_THRDINDX
, "<",
132 N_("ThrdIndex"), BACK_KEY
);
133 menu_add_binding(km
, ',', MC_THRDINDX
);
136 menu_init_binding(km
, '<', MC_FOLDERS
, "<",
137 N_("FldrList"), BACK_KEY
);
138 menu_add_binding(km
, ',', MC_FOLDERS
);
140 if(F_OFF(F_ENABLE_PIPE
,ps_global
))
141 clrbitn(VIEW_PIPE_KEY
, bitmap
); /* always clear for DOS */
142 if(F_OFF(F_ENABLE_FULL_HDR
,ps_global
))
143 clrbitn(VIEW_FULL_HEADERS_KEY
, bitmap
);
144 if(F_OFF(F_ENABLE_BOUNCE
,ps_global
))
145 clrbitn(BOUNCE_KEY
, bitmap
);
146 if(F_OFF(F_ENABLE_FLAG
,ps_global
))
147 clrbitn(FLAG_KEY
, bitmap
);
148 if(F_OFF(F_ENABLE_AGG_OPS
,ps_global
)){
149 clrbitn(SELECT_KEY
, bitmap
);
150 clrbitn(APPLY_KEY
, bitmap
);
151 clrbitn(SELCUR_KEY
, bitmap
);
152 if(style
!= ZoomIndex
)
153 clrbitn(ZOOM_KEY
, bitmap
);
157 if(style
== MultiMsgIndex
){
158 clrbitn(PREVM_KEY
, bitmap
);
159 clrbitn(NEXTM_KEY
, bitmap
);
163 if(km
== &index_keymenu
|| km
== &thread_keymenu
){
165 km
->keys
[EXCLUDE_KEY
].label
= N_("eXclude");
166 KS_OSDATASET(&km
->keys
[EXCLUDE_KEY
], KS_NONE
);
169 clrbitn(UNEXCLUDE_KEY
, bitmap
);
170 km
->keys
[EXCLUDE_KEY
].label
= N_("eXpunge");
171 KS_OSDATASET(&km
->keys
[EXCLUDE_KEY
], KS_EXPUNGE
);
175 if(km
!= &simple_index_keymenu
&& !THRD_COLLAPSE_ENABLE())
176 clrbitn(COLLAPSE_KEY
, bitmap
);
178 menu_clear_binding(km
, KEY_LEFT
);
179 menu_clear_binding(km
, KEY_RIGHT
);
180 if(F_ON(F_ARROW_NAV
, ps_global
)){
181 if((cmd
= menu_clear_binding(km
, '<')) != MC_UNKNOWN
){
182 menu_add_binding(km
, '<', cmd
);
183 menu_add_binding(km
, KEY_LEFT
, cmd
);
186 if((cmd
= menu_clear_binding(km
, '>')) != MC_UNKNOWN
){
187 menu_add_binding(km
, '>', cmd
);
188 menu_add_binding(km
, KEY_RIGHT
, cmd
);
192 if(menu_binding_index(km
, MC_JUMP
) >= 0){
193 for(cmd
= 0; cmd
< 10; cmd
++)
194 if(F_ON(F_ENABLE_JUMP
, ps_global
))
195 (void) menu_add_binding(km
, '0' + cmd
, MC_JUMP
);
197 (void) menu_clear_binding(km
, '0' + cmd
);
200 draw_keymenu(km
, bitmap
, ps_global
->ttyo
->screen_cols
,
201 1-FOOTER_ROWS(ps_global
), 0, what_keymenu
);
202 what_keymenu
= SameMenu
;
204 *which_keys
= km
->which
; /* pass back to caller */
212 /*----------------------------------------------------------------------
213 Main loop executing commands for the mail index screen
215 Args: state -- the pine_state structure for next/prev screen pointers
216 and to pass to the index manager...
220 mail_index_screen(struct pine
*state
)
222 if(!state
->mail_stream
) {
223 q_status_message(SM_ORDER
, 0, 3, _("No folder is currently open"));
224 state
->prev_screen
= mail_index_screen
;
225 state
->next_screen
= main_menu_screen
;
229 state
->prev_screen
= mail_index_screen
;
230 state
->next_screen
= SCREEN_FUN_NULL
;
233 && sp_viewing_a_thread(state
->mail_stream
)
234 && state
->view_skipped_index
235 && unview_thread(state
, state
->mail_stream
, state
->msgmap
)){
236 state
->next_screen
= mail_index_screen
;
237 state
->view_skipped_index
= 0;
238 state
->mangled_screen
= 1;
241 adjust_cur_to_visible(state
->mail_stream
, state
->msgmap
);
244 thread_index_screen(state
);
246 index_index_screen(state
);
251 index_index_screen(struct pine
*state
)
253 dprint((1, "\n\n ---- MAIL INDEX ----\n"));
255 setup_for_index_index_screen();
257 index_lister(state
, state
->context_current
, state
->cur_folder
,
258 state
->mail_stream
, state
->msgmap
);
263 thread_index_screen(struct pine
*state
)
265 dprint((1, "\n\n ---- THREAD INDEX ----\n"));
267 setup_for_thread_index_screen();
269 index_lister(state
, state
->context_current
, state
->cur_folder
,
270 state
->mail_stream
, state
->msgmap
);
275 stop_threading_temporarily(void)
277 struct save_thrdinfo
*ti
;
279 ps_global
->turn_off_threading_temporarily
= 1;
281 ti
= (struct save_thrdinfo
*) fs_get(sizeof(*ti
));
282 ti
->format_index_line
= format_index_line
;
283 ti
->setup_header_widths
= setup_header_widths
;
284 ti
->viewing_a_thread
= sp_viewing_a_thread(ps_global
->mail_stream
);
286 setup_for_index_index_screen();
293 restore_threading(void **p
)
295 struct save_thrdinfo
*ti
;
297 ps_global
->turn_off_threading_temporarily
= 0;
300 ti
= (struct save_thrdinfo
*) (*p
);
301 format_index_line
= ti
->format_index_line
;
302 setup_header_widths
= ti
->setup_header_widths
;
303 sp_set_viewing_a_thread(ps_global
->mail_stream
, ti
->viewing_a_thread
);
310 /*----------------------------------------------------------------------
311 Main loop executing commands for the mail index screen
313 Args: state -- pine_state structure for display flags and such
314 msgmap -- c-client/pine message number mapping struct
318 index_lister(struct pine
*state
, CONTEXT_S
*cntxt
, char *folder
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
)
321 int cmd
, which_keys
, force
,
322 cur_row
, cur_col
, km_popped
, paint_status
;
323 static int old_day
= -1;
324 long i
, j
, k
, old_max_msgno
;
325 long lflagged
, old_lflagged
= 0L;
327 IndexType style
, old_style
= MsgIndex
;
328 struct index_state id
;
329 struct key_menu
*km
= NULL
;
332 dprint((1, "\n\n ---- INDEX MANAGER ----\n"));
334 ch
= 'x'; /* For displaying msg 1st time thru */
337 state
->mangled_screen
= 1;
338 what_keymenu
= FirstMenu
;
339 old_max_msgno
= mn_get_total(msgmap
);
340 memset((void *)&id
, 0, sizeof(struct index_state
));
341 current_index_state
= &id
;
343 if(msgmap
->top
!= 0L)
344 id
.msg_at_top
= msgmap
->top
;
347 set_need_format_setup(stream
);
350 ps_global
->user_says_cancel
= 0;
356 if(!state
->mangled_body
358 && id
.lines_per_page
> 1){
359 id
.entry_state
[id
.lines_per_page
-2].id
= 0;
360 id
.entry_state
[id
.lines_per_page
-1].id
= 0;
363 state
->mangled_body
= 1;
367 /*------- Check for new mail -------*/
368 new_mail(force
, NM_TIMING(ch
), NM_STATUS_MSG
);
369 force
= 0; /* may not need to next time around */
372 * If the width of the message number field in the display changes
373 * we need to flush the cache and redraw. When the cache is cleared
374 * the widths are recalculated, taking into account the max msgno.
377 if(format_includes_msgno(stream
) &&
378 ((old_max_msgno
< 1000L && mn_get_total(msgmap
) >= 1000L)
379 || (old_max_msgno
< 10000L && mn_get_total(msgmap
) >= 10000L)
380 || (old_max_msgno
< 100000L && mn_get_total(msgmap
) >= 100000L))){
381 clear_index_cache(stream
, IC_CLEAR_WIDTHS_DONE
);
382 state
->mangled_body
= 1;
385 old_max_msgno
= mn_get_total(msgmap
);
388 * If the display includes the SMARTDATE ("Today", "Yesterday", ...)
389 * then when the day changes the date column will change. All of the
390 * Today's will become Yesterday's at midnight. So we have to
391 * clear the cache at midnight.
393 if(format_includes_smartdate(stream
)){
398 parse_date(db
, &nnow
);
399 if(old_day
!= -1 && nnow
.day
!= old_day
){
400 clear_index_cache(stream
, 0);
401 state
->mangled_body
= 1;
408 state
->mangled_header
= 1;
410 if(state
->mangled_screen
){
411 state
->mangled_header
= 1;
412 state
->mangled_body
= 1;
413 state
->mangled_footer
= 1;
414 state
->mangled_screen
= 0;
418 * events may have occured that require us to shift from
423 : (any_lflagged(msgmap
, MN_HIDE
))
425 : (mn_total_cur(msgmap
) > 1L) ? MultiMsgIndex
: MsgIndex
;
426 lflagged
= any_lflagged(msgmap
, MN_HIDE
);
427 if(style
!= old_style
|| lflagged
< old_lflagged
){
428 state
->mangled_header
= 1;
429 state
->mangled_footer
= 1;
431 old_lflagged
= lflagged
;
432 if(!(style
== ThreadIndex
|| old_style
== ThreadIndex
))
436 /*------------ Update the title bar -----------*/
437 if(state
->mangled_header
) {
438 km
= do_index_border(cntxt
, folder
, stream
, msgmap
,
439 style
, NULL
, INDX_HEADER
);
440 state
->mangled_header
= 0;
443 else if(mn_get_total(msgmap
) > 0) {
444 update_titlebar_message();
446 * If flags aren't available to update the status,
447 * defer it until after all the fetches associated
448 * with building index lines are done (no extra rtts!)...
450 paint_status
= !update_titlebar_status();
453 current_index_state
= &id
;
455 /*------------ draw the index body ---------------*/
456 cur_row
= update_index(state
, &id
);
457 if(F_OFF(F_SHOW_CURSOR
, state
)){
458 cur_row
= state
->ttyo
->screen_rows
- FOOTER_ROWS(state
);
461 else if(id
.status_col
>= 0)
462 cur_col
= MIN(id
.status_col
, state
->ttyo
->screen_cols
-1);
464 ps_global
->redrawer
= redraw_index_body
;
467 (void) update_titlebar_status();
469 /*------------ draw the footer/key menus ---------------*/
470 if(state
->mangled_footer
) {
471 if(!state
->painted_footer_on_startup
){
473 FOOTER_ROWS(state
) = 3;
477 km
= do_index_border(cntxt
, folder
, stream
, msgmap
, style
,
478 &which_keys
, INDX_FOOTER
);
480 FOOTER_ROWS(state
) = 1;
481 mark_keymenu_dirty();
485 state
->mangled_footer
= 0;
488 state
->painted_body_on_startup
= 0;
489 state
->painted_footer_on_startup
= 0;
491 /*-- Display any queued message (eg, new mail, command result --*/
493 FOOTER_ROWS(state
) = 3;
494 mark_status_unknown();
499 FOOTER_ROWS(state
) = 1;
500 mark_status_unknown();
503 if(F_ON(F_SHOW_CURSOR
, state
) && cur_row
< 0){
504 cur_row
= state
->ttyo
->screen_rows
- FOOTER_ROWS(state
);
507 cur_row
= MIN(MAX(cur_row
, 0), state
->ttyo
->screen_rows
-1);
508 MoveCursor(cur_row
, cur_col
);
510 /* Let read_command do the fflush(stdout) */
512 /*---------- Read command and validate it ----------------*/
514 mouse_in_content(KEY_MOUSE
, -1, -1, 0x5, 0);
515 register_mfunc(mouse_in_content
, HEADER_ROWS(ps_global
), 0,
516 state
->ttyo
->screen_rows
-(FOOTER_ROWS(ps_global
)+1),
517 state
->ttyo
->screen_cols
);
520 mswin_setscrollcallback (index_scroll_callback
);
521 mswin_sethelptextcallback((stream
== state
->mail_stream
)
523 : pcpine_help_index_simple
);
524 mswin_setviewinwindcallback(view_in_new_window
);
526 ch
= READ_COMMAND(&utf8str
);
528 clear_mfunc(mouse_in_content
);
531 mswin_setscrollcallback(NULL
);
532 mswin_sethelptextcallback(NULL
);
533 mswin_setviewinwindcallback(NULL
);
536 cmd
= menu_command(ch
, km
);
552 /*----------- Execute the command ------------------*/
555 /*---------- Roll keymenu ----------*/
557 if(F_OFF(F_USE_FK
, ps_global
))
560 what_keymenu
= NextMenu
;
561 state
->mangled_footer
= 1;
565 /*---------- Scroll line up ----------*/
567 (void) process_cmd(state
, stream
, msgmap
, MC_PREVITEM
,
569 || style
== MultiMsgIndex
570 || style
== ZoomIndex
)
572 : (style
== ThreadIndex
)
576 if(mn_get_cur(msgmap
) < (id
.msg_at_top
+ HS_MARGIN(state
)))
582 /*---------- Scroll line down ----------*/
585 * Special Page framing handling here. If we
586 * did something that should scroll-by-a-line, frame
587 * the page by hand here rather than leave it to the
588 * page-by-page framing in update_index()...
590 (void) process_cmd(state
, stream
, msgmap
, MC_NEXTITEM
,
592 || style
== MultiMsgIndex
593 || style
== ZoomIndex
)
595 : (style
== ThreadIndex
)
599 for(j
= 0L, k
= i
= id
.msg_at_top
; ; i
++){
600 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
602 if(j
++ >= id
.lines_per_page
)
606 if(i
>= mn_get_total(msgmap
)){
607 k
= 0L; /* don't scroll */
612 if(k
&& (mn_get_cur(msgmap
) + HS_MARGIN(state
)) >= k
)
613 index_scroll_down(1L);
618 /*---------- Scroll page up ----------*/
621 for(k
= i
= id
.msg_at_top
; ; i
--){
622 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
624 if(++j
>= id
.lines_per_page
){
625 if((id
.msg_at_top
= i
) == 1L)
626 q_status_message(SM_ORDER
, 0, 1, _("First Index page"));
633 if((!THREADING() && mn_get_cur(msgmap
) == 1L)
635 && mn_get_cur(msgmap
) == first_sorted_flagged(F_NONE
,
639 q_status_message(SM_ORDER
, 0, 1,
640 _("Already at start of Index"));
646 if(mn_get_total(msgmap
) > 0L && mn_total_cur(msgmap
) == 1L)
647 mn_set_cur(msgmap
, k
);
652 /*---------- Scroll page forward ----------*/
655 for(k
= i
= id
.msg_at_top
; ; i
++){
656 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
658 if(++j
>= id
.lines_per_page
){
659 if(i
+id
.lines_per_page
> mn_get_total(msgmap
))
660 q_status_message(SM_ORDER
, 0, 1, _("Last Index page"));
667 if(i
>= mn_get_total(msgmap
)){
668 if(mn_get_cur(msgmap
) == k
)
669 q_status_message(SM_ORDER
,0,1,_("Already at end of Index"));
675 if(mn_get_total(msgmap
) > 0L && mn_total_cur(msgmap
) == 1L)
676 mn_set_cur(msgmap
, k
);
681 /*---------- Scroll to first page ----------*/
683 if((mn_get_total(msgmap
) > 0L)
684 && (mn_total_cur(msgmap
) <= 1L)){
685 long cur_msg
= mn_get_cur(msgmap
), selected
;
687 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
690 mn_dec_cur(stream
, msgmap
, MH_NONE
);
691 cur_msg
= mn_get_cur(msgmap
);
693 while(selected
!= cur_msg
);
696 cur_msg
= (mn_get_total(msgmap
) > 0L) ? 1L : 0L;
697 mn_set_cur(msgmap
, cur_msg
);
698 q_status_message(SM_ORDER
, 0, 3, _("First Index Page"));
702 /*---------- Scroll to last page ----------*/
704 if((mn_get_total(msgmap
) > 0L)
705 && (mn_total_cur(msgmap
) <= 1L)){
706 long cur_msg
= mn_get_cur(msgmap
), selected
;
708 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
711 mn_inc_cur(stream
, msgmap
, MH_NONE
);
712 cur_msg
= mn_get_cur(msgmap
);
714 while(selected
!= cur_msg
);
717 cur_msg
= mn_get_total(msgmap
);
718 mn_set_cur(msgmap
, cur_msg
);
719 q_status_message(SM_ORDER
, 0, 3, _("Last Index Page"));
723 /*---------- Search (where is command) ----------*/
725 index_search(state
, stream
, -FOOTER_ROWS(ps_global
), msgmap
);
726 state
->mangled_footer
= 1;
730 /*-------------- jump command -------------*/
731 /* NOTE: preempt the process_cmd() version because
732 * we need to get at the number..
735 j
= jump_to(msgmap
, -FOOTER_ROWS(ps_global
), ch
, NULL
,
736 (style
== ThreadIndex
) ? ThrdIndx
: MsgIndx
);
738 if(style
== ThreadIndex
){
741 thrd
= find_thread_by_number(stream
, msgmap
, j
, NULL
);
743 if(thrd
&& thrd
->rawno
)
744 mn_set_cur(msgmap
, mn_raw2m(msgmap
, thrd
->rawno
));
747 /* jump to message */
748 if(mn_total_cur(msgmap
) > 1L){
749 mn_reset_cur(msgmap
, j
);
752 mn_set_cur(msgmap
, j
);
759 state
->mangled_footer
= 1;
763 case MC_VIEW_ENTRY
: /* only happens in thread index */
766 * If the feature F_THRD_AUTO_VIEW is turned on and there
767 * is only one message in the thread, then we skip the index
768 * view of the thread and go straight to the message view.
771 if(THRD_AUTO_VIEW() && style
== ThreadIndex
){
774 thrd
= fetch_thread(stream
,
775 mn_m2raw(msgmap
, mn_get_cur(msgmap
)));
777 && (count_lflags_in_thread(stream
, thrd
,
778 msgmap
, MN_NONE
) == 1)){
779 if(view_thread(state
, stream
, msgmap
, 1)){
780 state
->view_skipped_index
= 1;
787 if(view_thread(state
, stream
, msgmap
, 1)){
788 ps_global
->next_screen
= mail_index_screen
;
789 ps_global
->redrawer
= NULL
;
790 current_index_state
= NULL
;
792 fs_give((void **)&(id
.entry_state
));
801 msgmap
->top
= msgmap
->top_after_thrd
;
802 if(unview_thread(state
, stream
, msgmap
)){
803 state
->next_screen
= mail_index_screen
;
804 state
->view_skipped_index
= 0;
805 state
->mangled_screen
= 1;
806 ps_global
->redrawer
= NULL
;
807 current_index_state
= NULL
;
809 fs_give((void **)&(id
.entry_state
));
823 mouse_get_last (NULL
, &mp
);
826 for(i
= id
.msg_at_top
;
827 mp
.row
>= 0 && i
<= mn_get_total(msgmap
);
829 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
834 if(mn_get_total(msgmap
) && mp
.row
< 0){
837 if(mn_total_cur(msgmap
) == 1L)
838 mn_set_cur(msgmap
, new_cur
);
840 if(mp
.flags
& M_KEY_CONTROL
){
841 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
842 (void) select_by_current(state
, msgmap
, MsgIndx
);
845 else if(!(mp
.flags
& M_KEY_SHIFT
)){
848 && mp
.col
== id
.plus_col
849 && style
!= ThreadIndex
){
850 collapse_or_expand(state
, stream
, msgmap
,
853 else if (mp
.doubleclick
){
854 if(mp
.button
== M_BUTTON_LEFT
){
855 if(stream
== state
->mail_stream
){
866 ps_global
->redrawer
= NULL
;
867 current_index_state
= NULL
;
869 fs_give((void **)&(id
.entry_state
));
878 case M_BUTTON_MIDDLE
:
881 case M_BUTTON_RIGHT
:
883 if (!mp
.doubleclick
){
884 if(mn_total_cur(msgmap
) == 1L)
885 mn_set_cur(msgmap
, new_cur
);
887 cur_row
= update_index(state
, &id
);
889 index_popup(style
, stream
, msgmap
, TRUE
);
900 case M_BUTTON_MIDDLE
:
903 case M_BUTTON_RIGHT
:
905 index_popup(style
, stream
, msgmap
, FALSE
);
915 /*---------- Resize ----------*/
918 * If we were smarter we could do the
919 * IC_CLEAR_WIDTHS_DONE trick here. The problem is
920 * that entire columns of the format can go away or
921 * appear because the width gets smaller or larger,
922 * so in that case we need to re-do. If we could tell
923 * when that happened or not we could set the flag
926 clear_index_cache(stream
, 0);
927 reset_index_border();
933 /*---------- Redraw ----------*/
935 force
= 1; /* check for new mail! */
936 reset_index_border();
940 /*---------- No op command ----------*/
942 break; /* no op check for new mail */
945 /*--------- keystroke not bound to command --------*/
951 if(cmd
== MC_UNKNOWN
&& (ch
== 'i' || ch
== 'I'))
952 q_status_message(SM_ORDER
, 0, 1, "Already in Index");
954 bogus_command(ch
, F_ON(F_USE_FK
,state
) ? "F1" : "?");
960 thread_command(state
, stream
, msgmap
, ch
, -FOOTER_ROWS(state
));
976 PINETHRD_S
*thrd
= NULL
;
979 rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
981 thrd
= fetch_thread(stream
, rawno
);
983 collapsed
= thrd
&& thrd
->next
984 && get_lflag(stream
, NULL
, rawno
, MN_COLL
);
988 thread_command(state
, stream
, msgmap
,
989 ch
, -FOOTER_ROWS(state
));
990 /* increment current */
991 if(cmd
== MC_DELETE
){
992 advance_cur_after_delete(state
, stream
, msgmap
,
994 || style
== MultiMsgIndex
995 || style
== ZoomIndex
)
997 : (style
== ThreadIndex
)
1001 else if((cmd
== MC_SELCUR
1002 && (state
->ugly_consider_advancing_bit
1003 || F_OFF(F_UNSELECT_WONT_ADVANCE
, state
)))
1004 || (state
->ugly_consider_advancing_bit
1006 && F_ON(F_SAVE_ADVANCES
, state
))){
1007 mn_inc_cur(stream
, msgmap
, MH_NONE
);
1011 goto do_the_default
;
1018 bogus_utf8_command(utf8str
, NULL
);
1022 /*---------- First HELP command with menu hidden ----------*/
1024 if(FOOTER_ROWS(state
) == 1 && km_popped
== 0){
1026 mark_status_unknown();
1027 mark_keymenu_dirty();
1028 state
->mangled_footer
= 1;
1031 /* else fall thru to normal default */
1034 /*---------- Default -- all other command ----------*/
1037 if(stream
== state
->mail_stream
){
1038 msgmap
->top
= id
.msg_at_top
;
1039 process_cmd(state
, stream
, msgmap
, cmd
,
1041 || style
== MultiMsgIndex
1042 || style
== ZoomIndex
)
1044 : (style
== ThreadIndex
)
1048 if(state
->next_screen
!= SCREEN_FUN_NULL
){
1049 ps_global
->redrawer
= NULL
;
1050 current_index_state
= NULL
;
1052 fs_give((void **)&(id
.entry_state
));
1057 if(stream
!= state
->mail_stream
){
1059 * Must have had an failed open. repair our
1062 id
.stream
= stream
= state
->mail_stream
;
1063 id
.msgmap
= msgmap
= state
->msgmap
;
1066 current_index_state
= &id
;
1068 if(cmd
== MC_ZOOM
&& THRD_INDX())
1072 else{ /* special processing */
1075 helper(h_simple_index
,
1076 (!strcmp(folder
, INTERRUPTED_MAIL
))
1077 ? _("HELP FOR SELECTING INTERRUPTED MSG")
1078 : _("HELP FOR SELECTING POSTPONED MSG"),
1080 state
->mangled_screen
= 1;
1083 case MC_DELETE
: /* delete */
1084 dprint((3, "Special delete: msg %s\n",
1085 long2string(mn_get_cur(msgmap
))));
1091 raw
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
1092 if(raw
> 0L && stream
1093 && raw
<= stream
->nmsgs
1094 && (mc
= mail_elt(stream
, raw
))
1096 if((t
= mn_get_cur(msgmap
)) > 0L)
1097 clear_index_cache_ent(stream
, t
, 0);
1099 mail_setflag(stream
,long2string(raw
),"\\DELETED");
1100 update_titlebar_status();
1104 q_status_message1(SM_ORDER
, 0, 1,
1105 del
? _("Message %s deleted") : _("Message %s already deleted"),
1106 long2string(mn_get_cur(msgmap
)));
1111 case MC_UNDELETE
: /* UNdelete */
1112 dprint((3, "Special UNdelete: msg %s\n",
1113 long2string(mn_get_cur(msgmap
))));
1119 raw
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
1120 if(raw
> 0L && stream
1121 && raw
<= stream
->nmsgs
1122 && (mc
= mail_elt(stream
, raw
))
1124 if((t
= mn_get_cur(msgmap
)) > 0L)
1125 clear_index_cache_ent(stream
, t
, 0);
1127 mail_clearflag(stream
, long2string(raw
),
1129 update_titlebar_status();
1133 q_status_message1(SM_ORDER
, 0, 1,
1134 del
? _("Message %s UNdeleted") : _("Message %s NOT deleted"),
1135 long2string(mn_get_cur(msgmap
)));
1140 case MC_EXIT
: /* exit */
1141 ps_global
->redrawer
= NULL
;
1142 current_index_state
= NULL
;
1144 fs_give((void **)&(id
.entry_state
));
1148 case MC_SELECT
: /* select */
1149 ps_global
->redrawer
= NULL
;
1150 current_index_state
= NULL
;
1152 fs_give((void **)&(id
.entry_state
));
1156 case MC_PREVITEM
: /* previous */
1157 mn_dec_cur(stream
, msgmap
, MH_NONE
);
1160 case MC_NEXTITEM
: /* next */
1161 mn_inc_cur(stream
, msgmap
, MH_NONE
);
1165 bogus_command(ch
, NULL
);
1169 } /* The big switch */
1170 } /* the BIG while loop! */
1175 /*----------------------------------------------------------------------
1176 Manage index body painting
1178 Args: state - pine struct containing selected message data
1179 index_state - struct describing what's currently displayed
1181 Returns: screen row number of first highlighted message
1183 The idea is pretty simple. Maintain an array of index line id's that
1184 are displayed and their hilited state. Decide what's to be displayed
1185 and update the screen appropriately. All index screen painting
1186 is done here. Pretty simple, huh?
1189 update_index(struct pine
*state
, struct index_state
*screen
)
1191 int i
, retval
= -1, row
, already_fetched
= 0;
1193 PINETHRD_S
*thrd
= NULL
;
1196 dprint((7, "--update_index--\n"));
1202 mswin_beginupdate();
1205 /*---- reset the works if necessary ----*/
1206 if(state
->mangled_body
){
1208 if(screen
->entry_state
){
1209 fs_give((void **)&(screen
->entry_state
));
1210 screen
->lines_per_page
= 0;
1214 state
->mangled_body
= 0;
1216 /*---- make sure we have a place to write state ----*/
1217 if(screen
->lines_per_page
1218 != MAX(0, state
->ttyo
->screen_rows
- FOOTER_ROWS(state
)
1219 - HEADER_ROWS(state
))){
1220 i
= screen
->lines_per_page
;
1221 screen
->lines_per_page
1222 = MAX(0, state
->ttyo
->screen_rows
- FOOTER_ROWS(state
)
1223 - HEADER_ROWS(state
));
1225 size_t len
= screen
->lines_per_page
* sizeof(struct entry_state
);
1226 screen
->entry_state
= (struct entry_state
*) fs_get(len
);
1229 fs_resize((void **)&(screen
->entry_state
),
1230 (size_t)screen
->lines_per_page
);
1232 for(; i
< screen
->lines_per_page
; i
++) /* init new entries */
1233 memset(&screen
->entry_state
[i
], 0, sizeof(struct entry_state
));
1236 /*---- figure out the first message on the display ----*/
1237 if(screen
->msg_at_top
< 1L
1238 || msgline_hidden(screen
->stream
, screen
->msgmap
, screen
->msg_at_top
,0)){
1239 screen
->msg_at_top
= top_ent_calc(screen
->stream
, screen
->msgmap
,
1241 screen
->lines_per_page
);
1243 else if(mn_get_cur(screen
->msgmap
) < screen
->msg_at_top
){
1246 /* scroll back a page at a time until current is displayed */
1247 while(mn_get_cur(screen
->msgmap
) < screen
->msg_at_top
){
1248 for(i
= screen
->lines_per_page
, j
= screen
->msg_at_top
-1L, k
= 0L;
1251 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, j
, 0)){
1256 if(i
== screen
->lines_per_page
)
1257 break; /* can't scroll back ? */
1259 screen
->msg_at_top
= k
;
1262 else if(mn_get_cur(screen
->msgmap
) >= screen
->msg_at_top
1263 + screen
->lines_per_page
){
1267 for(i
= screen
->lines_per_page
, j
= k
= screen
->msg_at_top
;
1268 j
<= mn_get_total(screen
->msgmap
) && i
> 0L;
1270 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, j
, 0)){
1273 if(mn_get_cur(screen
->msgmap
) <= k
)
1277 if(mn_get_cur(screen
->msgmap
) <= k
)
1280 /* set msg_at_top to next displayed message */
1281 for(i
= k
+ 1L; i
<= mn_get_total(screen
->msgmap
); i
++)
1282 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, i
, 0)){
1287 screen
->msg_at_top
= k
;
1294 * Set scroll range and position. Note that message numbers start at 1
1295 * while scroll position starts at 0.
1298 if(THREADING() && sp_viewing_a_thread(screen
->stream
)
1299 && mn_get_total(screen
->msgmap
) > 1L){
1300 long x
= 0L, range
= 0L, lowest_numbered_msg
;
1303 * We know that all visible messages in the thread are marked
1306 thrd
= fetch_thread(screen
->stream
,
1307 mn_m2raw(screen
->msgmap
,
1308 mn_get_cur(screen
->msgmap
)));
1309 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
1310 thrd
= fetch_thread(screen
->stream
, thrd
->top
);
1313 if(mn_get_revsort(screen
->msgmap
)){
1314 n
= mn_raw2m(screen
->msgmap
, thrd
->rawno
);
1315 while(n
> 1L && get_lflag(screen
->stream
, screen
->msgmap
,
1319 lowest_numbered_msg
= n
;
1322 lowest_numbered_msg
= mn_raw2m(screen
->msgmap
, thrd
->rawno
);
1326 n
= lowest_numbered_msg
;
1327 for(; n
<= mn_get_total(screen
->msgmap
); n
++){
1329 if(!get_lflag(screen
->stream
, screen
->msgmap
, n
, MN_CHID2
))
1332 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0)){
1334 if(n
< screen
->msg_at_top
)
1340 scroll_setrange(screen
->lines_per_page
, range
-1L);
1343 else if(THRD_INDX()){
1344 if(any_lflagged(screen
->msgmap
, MN_HIDE
)){
1347 range
= screen
->msgmap
->visible_threads
- 1L;
1348 scroll_setrange(screen
->lines_per_page
, range
);
1349 if(range
>= screen
->lines_per_page
){ /* else not needed */
1350 PINETHRD_S
*topthrd
;
1354 /* find top of currently displayed top line */
1355 topthrd
= fetch_thread(screen
->stream
,
1356 mn_m2raw(screen
->msgmap
,
1357 screen
->msg_at_top
));
1358 if(topthrd
&& topthrd
->top
!= topthrd
->rawno
)
1359 topthrd
= fetch_thread(screen
->stream
, topthrd
->top
);
1363 * Split into two halves to speed up finding scroll pos.
1364 * It's tricky because the thread list always goes from
1365 * past to future but the thrdno's will be reversed if
1366 * the sort is reversed and of course the order on the
1367 * screen will be reversed.
1369 if((!mn_get_revsort(screen
->msgmap
)
1370 && topthrd
->thrdno
<= screen
->msgmap
->max_thrdno
/2)
1372 (mn_get_revsort(screen
->msgmap
)
1373 && topthrd
->thrdno
> screen
->msgmap
->max_thrdno
/2)){
1375 /* start with head of thread list */
1376 if(topthrd
&& topthrd
->head
)
1377 thrd
= fetch_thread(screen
->stream
, topthrd
->head
);
1387 * Start with tail thread and work back.
1389 if(mn_get_revsort(screen
->msgmap
))
1390 tailrawno
= mn_m2raw(screen
->msgmap
, 1L);
1392 tailrawno
= mn_m2raw(screen
->msgmap
,
1393 mn_get_total(screen
->msgmap
));
1395 thrd
= fetch_thread(screen
->stream
, tailrawno
);
1396 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
1397 thrd
= fetch_thread(screen
->stream
, thrd
->top
);
1403 * x is the scroll position. We try to use the fewest
1404 * number of steps to find it, so we start with either
1405 * the beginning or the end.
1407 if(topthrd
->thrdno
<= screen
->msgmap
->max_thrdno
/2){
1416 while(thrd
&& thrd
!= topthrd
){
1417 if(!msgline_hidden(screen
->stream
, screen
->msgmap
,
1418 mn_raw2m(screen
->msgmap
,thrd
->rawno
),
1422 if(thrddir
> 0 && thrd
->nextthd
)
1423 thrd
= fetch_thread(screen
->stream
, thrd
->nextthd
);
1424 else if(thrddir
< 0 && thrd
->prevthd
)
1425 thrd
= fetch_thread(screen
->stream
, thrd
->prevthd
);
1436 * This works for forward or reverse sort because the thrdno's
1437 * will have been reversed.
1439 thrd
= fetch_thread(screen
->stream
,
1440 mn_m2raw(screen
->msgmap
, screen
->msg_at_top
));
1442 scroll_setrange(screen
->lines_per_page
,
1443 screen
->msgmap
->max_thrdno
- 1L);
1444 scroll_setpos(thrd
->thrdno
- 1L);
1448 else if(n
= any_lflagged(screen
->msgmap
, MN_HIDE
| MN_CHID
)){
1451 range
= mn_get_total(screen
->msgmap
) - n
- 1L;
1452 scroll_setrange(screen
->lines_per_page
, range
);
1454 if(range
>= screen
->lines_per_page
){ /* else not needed */
1455 if(screen
->msg_at_top
< mn_get_total(screen
->msgmap
) / 2){
1456 for(n
= 1, x
= 0; n
!= screen
->msg_at_top
; n
++)
1457 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1461 for(n
= mn_get_total(screen
->msgmap
), x
= range
;
1462 n
!= screen
->msg_at_top
; n
--)
1463 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1471 scroll_setrange(screen
->lines_per_page
,
1472 mn_get_total(screen
->msgmap
) - 1L);
1473 scroll_setpos(screen
->msg_at_top
- 1L);
1478 * Set up c-client call back to tell us about IMAP envelope arrivals
1479 * Can't do it (easily) if single lines on the screen need information
1480 * about more than a single message before they can be drawn.
1482 if(F_OFF(F_QUELL_IMAP_ENV_CB
, ps_global
) && !THRD_INDX()
1483 && !(THREADING() && (sp_viewing_a_thread(screen
->stream
)
1484 || ps_global
->thread_disp_style
== THREAD_MUTTLIKE
1485 || any_lflagged(screen
->msgmap
, MN_COLL
))))
1486 mail_parameters(NULL
, SET_IMAPENVELOPE
, (void *) pine_imap_envelope
);
1489 visible
= screen
->msgmap
->visible_threads
;
1490 else if(THREADING() && sp_viewing_a_thread(screen
->stream
)){
1492 * We know that all visible messages in the thread are marked
1495 for(visible
= 0L, n
= screen
->msg_at_top
;
1496 visible
< (int) screen
->lines_per_page
1497 && n
<= mn_get_total(screen
->msgmap
); n
++){
1499 if(!get_lflag(screen
->stream
, screen
->msgmap
, n
, MN_CHID2
))
1502 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1507 visible
= mn_get_total(screen
->msgmap
)
1508 - any_lflagged(screen
->msgmap
, MN_HIDE
|MN_CHID
);
1510 /*---- march thru display lines, painting whatever is needed ----*/
1511 for(i
= 0, n
= screen
->msg_at_top
; i
< (int) screen
->lines_per_page
; i
++){
1512 if(visible
== 0L || n
< 1 || n
> mn_get_total(screen
->msgmap
)){
1513 if(screen
->entry_state
[i
].id
!= LINE_HASH_N
){
1514 screen
->entry_state
[i
].hilite
= 0;
1515 screen
->entry_state
[i
].bolded
= 0;
1516 screen
->entry_state
[i
].msgno
= 0L;
1517 screen
->entry_state
[i
].id
= LINE_HASH_N
;
1518 ClearLine(HEADER_ROWS(state
) + i
);
1525 * This changes status_col as a side effect so it has to be
1526 * executed before next line.
1528 ice
= build_header_line(state
, screen
->stream
, screen
->msgmap
,
1529 n
, &already_fetched
);
1534 unsigned long rawno
;
1536 rawno
= mn_m2raw(screen
->msgmap
, n
);
1538 thrd
= fetch_thread(screen
->stream
, rawno
);
1541 row
= paint_index_line(ice
, i
,
1542 (THRD_INDX() && thrd
) ? thrd
->thrdno
: n
,
1543 screen
->status_fld
, screen
->plus_fld
,
1544 screen
->arrow_fld
, &screen
->entry_state
[i
],
1545 mn_is_cur(screen
->msgmap
, n
),
1547 ? (count_lflags_in_thread(screen
->stream
,
1551 : get_lflag(screen
->stream
, screen
->msgmap
,
1554 if(row
&& retval
< 0)
1558 /*--- increment n ---*/
1559 while((visible
== -1L || visible
> 0L)
1560 && ++n
<= mn_get_total(screen
->msgmap
)
1561 && msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1566 cancel_busy_cue(-1);
1568 mail_parameters(NULL
, SET_IMAPENVELOPE
, (void *) NULL
);
1574 dprint((7, "--update_index done\n"));
1580 /*----------------------------------------------------------------------
1581 Create a string summarizing the message header for index on screen
1583 Args: stream -- mail stream to fetch envelope info from
1584 msgmap -- message number to pine sort mapping
1585 msgno -- Message number to create line for
1587 Result: returns a malloced string
1588 saves string in a cache for next call for same header
1591 build_header_line(struct pine
*state
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
, long int msgno
, int *already_fetched
)
1593 return(build_header_work(state
, stream
, msgmap
, msgno
,
1594 current_index_state
->msg_at_top
,
1595 current_index_state
->lines_per_page
,
1600 /*----------------------------------------------------------------------
1601 Paint the given index line
1604 Args: ice -- index cache entry
1605 line -- index line number on screen, starting at 0 for first
1606 visible line, 1, 2, ...
1607 msgno -- for painting the message number field
1608 sfld -- field type of the status field, which is
1609 where we'll put the X for selected if necessary
1610 pfld -- field type where the thread indicator symbol goes
1611 afld -- field type of column which corresponds to the
1612 index-format ARROW token
1613 entry -- cache used to help us decide whether or not we need to
1614 redraw the index line or if we can just leave it alone because
1615 we know it is already correct
1616 cur -- is this the current message?
1617 sel -- is this message in the selected set?
1619 Returns: screen row number if this is current message, else 0
1622 paint_index_line(ICE_S
*argice
, int line
, long int msgno
, IndexColType sfld
,
1623 IndexColType pfld
, IndexColType afld
, struct entry_state
*entry
,
1626 COLOR_PAIR
*lastc
= NULL
, *base_color
= NULL
;
1628 IFIELD_S
*ifield
, *previfield
= NULL
;
1630 int save_schar1
= -1, save_schar2
= -1, save_pchar
= -1, i
;
1631 int draw_whole_line
= 0, draw_partial_line
= 0;
1632 int n
= MAX_SCREEN_COLS
*6;
1633 char draw
[MAX_SCREEN_COLS
*6+1], *p
;
1635 ice
= (THRD_INDX() && argice
) ? argice
->tice
: argice
;
1637 /* This better not happen! */
1639 q_status_message3(SM_ORDER
| SM_DING
, 5, 5,
1640 "NULL ice in paint_index_line: %s, msgno=%s line=%s",
1641 THRD_INDX() ? "THRD_INDX" : "reg index",
1642 comatose(msgno
), comatose(line
));
1643 dprint((1, "NULL ice in paint_index_line: %s, msgno=%ld line=%d\n",
1644 THRD_INDX() ? "THRD_INDX" : "reg index",
1649 if(entry
->msgno
!= msgno
|| ice
->id
== 0 || entry
->id
!= ice
->id
){
1652 draw_whole_line
= 1;
1654 else if((cur
!= entry
->hilite
) || (sel
!= entry
->bolded
)
1655 || (ice
->plus
!= entry
->plus
)){
1656 draw_partial_line
= 1;
1659 if(draw_whole_line
|| draw_partial_line
){
1661 if(F_ON(F_FORCE_LOW_SPEED
,ps_global
) || ps_global
->low_speed
){
1663 memset(draw
, 0, sizeof(draw
));
1666 for(ifield
= ice
->ifield
; ifield
&& p
-draw
< n
; ifield
= ifield
->next
){
1668 /* space between fields */
1669 if(ifield
!= ice
->ifield
&& !(previfield
&& previfield
->ctype
== iText
))
1672 /* message number string is generated on the fly */
1673 if(ifield
->ctype
== iMessNo
){
1674 ielem
= ifield
->ielem
;
1675 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1676 snprintf(ielem
->data
, ielem
->datalen
+1, "%*.ld", ifield
->width
, msgno
);
1677 ielem
->data
[ifield
->width
] = '\0';
1678 ielem
->data
[ielem
->datalen
] = '\0';
1682 if(ifield
->ctype
== sfld
){
1683 ielem
= ifield
->ielem
;
1684 if(ielem
&& ielem
->datalen
> 0){
1685 if(draw_partial_line
)
1686 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1688 if(ielem
->datalen
== 1){
1689 save_schar1
= ielem
->data
[0];
1690 ielem
->data
[0] = (sel
) ? 'X' : (cur
&& save_schar1
== ' ') ? '-' : save_schar1
;
1691 if(draw_partial_line
)
1692 Writechar(ielem
->data
[0], 0);
1694 if(ielem
->next
&& ielem
->next
->datalen
){
1695 save_schar2
= ielem
->next
->data
[0];
1697 ielem
->next
->data
[0] = '>';
1699 if(draw_partial_line
)
1700 Writechar(ielem
->next
->data
[0], 0);
1703 else if(ielem
->datalen
> 1){
1704 save_schar1
= ielem
->data
[0];
1705 ielem
->data
[0] = (sel
) ? 'X' : (cur
&& save_schar1
== ' ') ? '-' : save_schar1
;
1706 if(draw_partial_line
)
1707 Writechar(ielem
->data
[0], 0);
1709 save_schar2
= ielem
->data
[1];
1711 ielem
->data
[1] = '>';
1712 if(draw_partial_line
)
1713 Writechar(ielem
->data
[1], 0);
1718 else if(ifield
->ctype
== afld
){
1720 if(draw_partial_line
){
1721 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1722 for(i
= 0; i
< ifield
->width
-1; i
++)
1723 Writechar(cur
? '-' : ' ', 0);
1725 Writechar(cur
? '>' : ' ', 0);
1728 ielem
= ifield
->ielem
;
1729 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1730 for(i
= 0; i
< ifield
->width
-1; i
++)
1731 ielem
->data
[i
] = cur
? '-' : ' ';
1733 ielem
->data
[i
] = cur
? '>' : ' ';
1736 else if(ifield
->ctype
== pfld
){
1737 ielem
= ifield
->ielem
;
1738 if(ielem
&& ielem
->datalen
> 0){
1739 save_pchar
= ielem
->data
[0];
1740 ielem
->data
[0] = ice
->plus
;
1742 if(draw_partial_line
){
1743 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1744 Writechar(ielem
->data
[0], 0);
1750 for(ielem
= ifield
->ielem
;
1751 ielem
&& ielem
->print_format
&& p
-draw
< n
;
1752 ielem
= ielem
->next
){
1757 bytes_added
= utf8_pad_to_width(p
, src
,
1758 ((n
+1)-(p
-draw
)) * sizeof(char),
1759 ielem
->wid
, ifield
->leftadj
);
1765 if(ifield
->ctype
== sfld
){
1766 ielem
= ifield
->ielem
;
1767 if(ielem
&& ielem
->datalen
> 0){
1768 if(ielem
->datalen
== 1){
1769 ielem
->data
[0] = save_schar1
;
1770 if(ielem
->next
&& ielem
->next
->datalen
)
1771 ielem
->next
->data
[0] = save_schar2
;
1773 else if(ielem
->datalen
> 1){
1774 ielem
->data
[0] = save_schar1
;
1775 ielem
->data
[1] = save_schar2
;
1779 else if(ifield
->ctype
== afld
){
1780 ielem
= ifield
->ielem
;
1781 if(ielem
&& ielem
->datalen
>= ifield
->width
)
1782 for(i
= 0; i
< ifield
->width
; i
++)
1783 ielem
->data
[i
] = ' ';
1785 else if(ifield
->ctype
== pfld
){
1786 ielem
= ifield
->ielem
;
1787 if(ielem
&& ielem
->datalen
> 0)
1788 ielem
->data
[0] = save_pchar
;
1791 previfield
= ifield
;
1797 PutLine0(HEADER_ROWS(ps_global
) + line
, 0, draw
);
1800 int uc
, ac
, do_arrow
;
1802 int inverse_hack
= 0, need_inverse_hack
= 0;
1805 /* so we can restore current color at the end */
1806 if((uc
=pico_usingcolor()) != 0)
1807 lastc
= pico_get_cur_color();
1810 * There are two possible "arrow" cursors. One is the one that
1811 * you get when you are at a slow speed or you turn that slow
1812 * speed one on. It is drawn as part of the status column.
1813 * That one is the one associated with the variable "ac".
1814 * It is always the base_color or the inverse of the base_color.
1816 * The other "arrow" cursor is the one you get by including the
1817 * ARROW token in the index-format. It may be configured to
1820 * The arrow cursors have two special properties that make
1821 * them different from other sections or fields.
1822 * First, the arrow cursors only show up on the current line.
1823 * Second, the arrow cursors are drawn with generated data, not
1824 * data that is present in the passed in data.
1827 /* ac is for the old integrated arrow cursor */
1828 ac
= F_ON(F_FORCE_ARROW
,ps_global
);
1830 /* do_arrow is for the ARROW token in index-format */
1831 do_arrow
= (afld
!= iNothing
);
1833 MoveCursor(HEADER_ROWS(ps_global
) + line
, 0);
1835 /* find the base color for the whole line */
1836 if(cur
&& !ac
&& !do_arrow
){
1838 * This stanza handles the current line marking in the
1839 * regular, non-arrow-cursor case.
1843 * If the current line has a linecolor, apply the
1844 * appropriate reverse transformation to show it is current.
1846 if(uc
&& ice
->linecolor
&& ice
->linecolor
->fg
[0]
1847 && ice
->linecolor
->bg
[0] && pico_is_good_colorpair(ice
->linecolor
)){
1848 base_color
= apply_rev_color(ice
->linecolor
,
1849 ps_global
->index_color_style
);
1851 (void)pico_set_colorp(base_color
, PSC_NONE
);
1858 if((rev
= pico_get_rev_color()) != NULL
){
1859 base_color
= new_color_pair(rev
->fg
, rev
->bg
);
1860 (void)pico_set_colorp(base_color
, PSC_NONE
);
1867 else if(uc
&& ice
->linecolor
&& ice
->linecolor
->fg
[0]
1868 && ice
->linecolor
->bg
[0]
1869 && pico_is_good_colorpair(ice
->linecolor
)){
1870 (void)pico_set_colorp(ice
->linecolor
, PSC_NONE
);
1871 base_color
= ice
->linecolor
;
1876 memset(draw
, 0, sizeof(draw
));
1879 doing_bold
= (sel
&& F_ON(F_SELECTED_SHOWN_BOLD
, ps_global
) && StartBold());
1881 /* draw each field */
1882 for(ifield
= ice
->ifield
; ifield
&& p
-draw
< n
; ifield
= ifield
->next
){
1887 * Fix up the data for some special cases.
1890 /* message number string is generated on the fly */
1891 if(ifield
->ctype
== iMessNo
){
1892 ielem
= ifield
->ielem
;
1893 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1894 snprintf(ielem
->data
, ielem
->datalen
+1, "%*.ld", ifield
->width
, msgno
);
1895 ielem
->data
[ifield
->width
] = '\0';
1896 ielem
->data
[ielem
->datalen
] = '\0';
1900 if(ifield
->ctype
== sfld
){
1901 ielem
= ifield
->ielem
;
1902 if(ielem
&& ielem
->datalen
> 0){
1903 if(ielem
->datalen
== 1){
1904 save_schar1
= ielem
->data
[0];
1905 if(sel
&& !doing_bold
){
1906 ielem
->data
[0] = 'X';
1909 else if(ac
&& cur
&& ielem
->data
[0] == ' ')
1910 ielem
->data
[0] = '-';
1912 if(ielem
->next
&& ielem
->next
->datalen
){
1913 save_schar2
= ielem
->next
->data
[0];
1914 if(ac
&& cur
&& ielem
->next
->data
[0] != '\0')
1915 ielem
->next
->data
[0] = '>';
1918 else if(ielem
->datalen
> 1){
1919 if(sel
&& !doing_bold
){
1920 ielem
->data
[0] = 'X';
1923 else if(ac
&& cur
&& ielem
->data
[0] == ' ')
1924 ielem
->data
[0] = '-';
1926 save_schar2
= ielem
->data
[1];
1927 if(ac
&& cur
&& ielem
->data
[1] != '\0')
1928 ielem
->data
[1] = '>';
1932 else if(ifield
->ctype
== afld
&& do_arrow
&& cur
){
1934 ielem
= ifield
->ielem
;
1935 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1936 for(i
= 0; i
< ifield
->width
-1; i
++)
1937 ielem
->data
[i
] = cur
? '-' : ' ';
1939 ielem
->data
[i
] = '>';
1942 else if(ifield
->ctype
== pfld
){
1943 ielem
= ifield
->ielem
;
1944 if(ielem
&& ielem
->datalen
> 0){
1945 save_pchar
= ielem
->data
[0];
1946 ielem
->data
[0] = ice
->plus
;
1950 /* space between fields */
1951 if(ifield
!= ice
->ifield
&& !(previfield
&& previfield
->ctype
== iText
)){
1955 Write_to_screen(" ");
1960 for(ielem
= ifield
->ielem
; ielem
; ielem
= ielem
->next
){
1964 utf8_pad_to_width(draw
, src
, (n
+1) * sizeof(char),
1965 ielem
->wid
, ifield
->leftadj
);
1969 * Switch to color for ielem.
1970 * But don't switch if we drew an X in this column,
1971 * because that overwrites the colored thing, and don't
1972 * switch if this is the ARROW field and this is not
1973 * the current message. ARROW field is only colored for
1974 * the current message.
1975 * And don't switch if current line and type eTypeCol.
1977 if(ielem
->color
&& pico_is_good_colorpair(ielem
->color
)
1978 && !(do_arrow
&& ifield
->ctype
== afld
&& !cur
)
1979 && (!drew_X
|| ielem
!= ifield
->ielem
)
1980 && !(cur
&& ielem
->type
== eTypeCol
)){
1981 need_inverse_hack
= 0;
1982 (void) pico_set_colorp(ielem
->color
, PSC_NORM
);
1985 need_inverse_hack
= 1;
1987 if(need_inverse_hack
&& inverse_hack
)
1990 Write_to_screen(draw
);
1991 if(need_inverse_hack
&& inverse_hack
)
1994 (void) pico_set_colorp(base_color
, PSC_NORM
);
1998 * Restore the data for the special cases.
2001 if(ifield
->ctype
== sfld
){
2002 ielem
= ifield
->ielem
;
2003 if(ielem
&& ielem
->datalen
> 0){
2004 if(ielem
->datalen
== 1){
2005 ielem
->data
[0] = save_schar1
;
2006 if(ielem
->next
&& ielem
->next
->datalen
)
2007 ielem
->next
->data
[0] = save_schar2
;
2009 else if(ielem
->datalen
> 1){
2010 ielem
->data
[0] = save_schar1
;
2011 ielem
->data
[1] = save_schar2
;
2015 else if(ifield
->ctype
== afld
){
2016 ielem
= ifield
->ielem
;
2017 if(ielem
&& ielem
->datalen
>= ifield
->width
)
2018 for(i
= 0; i
< ifield
->width
; i
++)
2019 ielem
->data
[i
] = ' ';
2021 else if(ifield
->ctype
== pfld
){
2022 ielem
= ifield
->ielem
;
2023 if(ielem
&& ielem
->datalen
> 0)
2024 ielem
->data
[0] = save_pchar
;
2027 previfield
= ifield
;
2033 if(base_color
&& base_color
!= lastc
&& base_color
!= ice
->linecolor
)
2034 free_color_pair(&base_color
);
2037 (void)pico_set_colorp(lastc
, PSC_NORM
);
2038 free_color_pair(&lastc
);
2043 entry
->hilite
= cur
;
2044 entry
->bolded
= sel
;
2045 entry
->msgno
= msgno
;
2046 entry
->plus
= ice
->plus
;
2047 entry
->id
= ice
->id
;
2049 if(!ice
->color_lookup_done
&& pico_usingcolor())
2052 return(cur
? (line
+ HEADER_ROWS(ps_global
)) : 0);
2056 * setup_index_state - hooked onto pith_opt_save_index_state to setup
2057 * current_index_state after setup_{index,thread}_header_widths
2060 setup_index_state(int threaded
)
2062 if(current_index_state
){
2064 current_index_state
->status_col
= 0;
2065 current_index_state
->status_fld
= iStatus
;
2066 current_index_state
->plus_fld
= iNothing
;
2067 current_index_state
->arrow_fld
= iNothing
;
2069 INDEX_COL_S
*cdesc
, *prevcdesc
= NULL
;
2070 IndexColType sfld
, altfld
, plusfld
, arrowfld
;
2071 int width
, fld
, col
, pluscol
, scol
, altcol
;
2078 /* figure out which field is status field */
2079 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2080 cdesc
->ctype
!= iNothing
;
2082 width
= cdesc
->width
;
2086 /* space between columns */
2087 if(col
> 0 && !(prevcdesc
&& prevcdesc
->ctype
== iText
))
2090 if(cdesc
->ctype
== iStatus
){
2092 sfld
= cdesc
->ctype
;
2096 if(cdesc
->ctype
== iFStatus
|| cdesc
->ctype
== iIStatus
){
2098 sfld
= cdesc
->ctype
;
2102 if(cdesc
->ctype
== iMessNo
){
2104 altfld
= cdesc
->ctype
;
2112 if(sfld
== iNothing
){
2123 current_index_state
->status_col
= scol
;
2124 current_index_state
->status_fld
= sfld
;
2130 /* figure out which column to use for threading '+' */
2132 && ps_global
->thread_disp_style
!= THREAD_NONE
2133 && ps_global
->VAR_THREAD_MORE_CHAR
[0]
2134 && ps_global
->VAR_THREAD_EXP_CHAR
[0])
2135 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2136 cdesc
->ctype
!= iNothing
;
2138 width
= cdesc
->width
;
2142 /* space between columns */
2143 if(col
> 0 && !(prevcdesc
&& prevcdesc
->ctype
== iText
))
2146 if((cdesc
->ctype
== iSubject
2147 || cdesc
->ctype
== iSubjectText
2148 || cdesc
->ctype
== iSubjKey
2149 || cdesc
->ctype
== iSubjKeyText
2150 || cdesc
->ctype
== iSubjKeyInit
2151 || cdesc
->ctype
== iSubjKeyInitText
)
2152 && (ps_global
->thread_disp_style
== THREAD_STRUCT
2153 || ps_global
->thread_disp_style
== THREAD_MUTTLIKE
2154 || ps_global
->thread_disp_style
== THREAD_INDENT_SUBJ1
2155 || ps_global
->thread_disp_style
== THREAD_INDENT_SUBJ2
)){
2156 plusfld
= cdesc
->ctype
;
2161 if((cdesc
->ctype
== iFrom
2162 || cdesc
->ctype
== iFromToNotNews
2163 || cdesc
->ctype
== iFromTo
2164 || cdesc
->ctype
== iAddress
2165 || cdesc
->ctype
== iMailbox
)
2166 && (ps_global
->thread_disp_style
== THREAD_INDENT_FROM1
2167 || ps_global
->thread_disp_style
== THREAD_INDENT_FROM2
2168 || ps_global
->thread_disp_style
== THREAD_STRUCT_FROM
)){
2169 plusfld
= cdesc
->ctype
;
2179 current_index_state
->plus_fld
= plusfld
;
2180 current_index_state
->plus_col
= pluscol
;
2182 arrowfld
= iNothing
;
2183 /* figure out which field is arrow field, if any */
2184 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2185 cdesc
->ctype
!= iNothing
;
2187 width
= cdesc
->width
;
2191 if(cdesc
->ctype
== iArrow
){
2192 arrowfld
= cdesc
->ctype
;
2199 current_index_state
->arrow_fld
= arrowfld
;
2206 * insert_condensed_thread_cue - used on pith hook to add decoration to
2207 * subject or from text to show condensed thread info
2210 condensed_thread_cue(PINETHRD_S
*thd
, ICE_S
*ice
,
2211 char **fieldstr
, size_t *strsize
, int width
, int collapsed
)
2213 if(current_index_state
->plus_fld
!= iNothing
&& !THRD_INDX() && fieldstr
&& *fieldstr
){
2216 * There is an unwarranted assumption here that VAR_THREAD_MORE_CHAR[0]
2217 * and VAR_THREAD_EXP_CHAR[0] are ascii.
2218 * Could do something similar to the conversions done with keyword
2219 * initials in key_str.
2222 ice
->plus
= collapsed
? ps_global
->VAR_THREAD_MORE_CHAR
[0]
2223 : (thd
&& thd
->next
)
2224 ? ps_global
->VAR_THREAD_EXP_CHAR
[0] : ' ';
2226 if(strsize
&& *strsize
> 0 && width
!= 0){
2227 *(*fieldstr
)++ = ' ';
2233 if(strsize
&& *strsize
> 0 && width
!= 0){
2234 *(*fieldstr
)++ = ' ';
2246 truncate_subj_and_from_strings(void)
2253 * paint_index_hline - paint index line given what we got
2256 paint_index_hline(MAILSTREAM
*stream
, long int msgno
, ICE_S
*ice
)
2261 * Trust only what we get back that isn't bogus since
2262 * we were prevented from doing any fetches and such...
2264 if((ps_global
->redrawer
== redraw_index_body
2265 || ps_global
->prev_screen
== mail_index_screen
)
2266 && current_index_state
2267 && current_index_state
->stream
== stream
2268 && !ps_global
->msgmap
->hilited
){
2272 * This test isn't right if there are hidden lines. The line will
2273 * fail the test because it seems like it is past the end of the
2274 * screen but since the hidden lines don't take up space the line
2275 * might actually be on the screen. Don't know that it is worth
2276 * it to fix this, though, since you may have to file through
2277 * many hidden lines before finding the visible ones. I'm not sure
2278 * if the logic inside the if is correct when we do pass the
2279 * top-level test. Leave it for now. Hubert - 2002-06-28
2281 if((line
= (int)(msgno
- current_index_state
->msg_at_top
)) >= 0
2282 && line
< current_index_state
->lines_per_page
){
2283 if(any_lflagged(ps_global
->msgmap
, MN_HIDE
| MN_CHID
)){
2285 long zoomhide
, collapsehide
;
2287 zoomhide
= any_lflagged(ps_global
->msgmap
, MN_HIDE
);
2288 collapsehide
= any_lflagged(ps_global
->msgmap
, MN_CHID
);
2291 * Line is visible if it is selected and not hidden due to
2292 * thread collapse, or if there is no zooming happening and
2293 * it is not hidden due to thread collapse.
2295 for(line
= 0, n
= current_index_state
->msg_at_top
;
2299 && get_lflag(stream
, current_index_state
->msgmap
,
2302 || !get_lflag(stream
, current_index_state
->msgmap
, n
,
2306 && !get_lflag(stream
, current_index_state
->msgmap
,
2313 unsigned long rawno
;
2315 rawno
= mn_m2raw(current_index_state
->msgmap
, msgno
);
2317 thrd
= fetch_thread(stream
, rawno
);
2320 paint_index_line(ice
, line
,
2321 (THRD_INDX() && thrd
) ? thrd
->thrdno
: msgno
,
2322 current_index_state
->status_fld
,
2323 current_index_state
->plus_fld
,
2324 current_index_state
->arrow_fld
,
2325 ¤t_index_state
->entry_state
[line
],
2326 mn_is_cur(current_index_state
->msgmap
, msgno
),
2328 ? (count_lflags_in_thread(stream
, thrd
,
2329 current_index_state
->msgmap
,
2331 : get_lflag(stream
, current_index_state
->msgmap
,
2342 * pine_imap_env -- C-client's telling us an envelope just arrived
2343 * from the server. Use it if we can...
2346 pine_imap_envelope(MAILSTREAM
*stream
, long unsigned int rawno
, ENVELOPE
*env
)
2350 dprint((7, "imap_env(%ld)\n", rawno
));
2351 if(stream
&& !sp_mail_box_changed(stream
)
2352 && stream
== ps_global
->mail_stream
2353 && rawno
> 0L && rawno
<= stream
->nmsgs
2354 && (mc
= mail_elt(stream
,rawno
))
2357 && !get_lflag(stream
, NULL
, rawno
, MN_HIDE
| MN_CHID
| MN_EXLD
)){
2361 memset(&idata
, 0, sizeof(INDEXDATA_S
));
2363 idata
.size
= mc
->rfc822_size
;
2364 idata
.rawno
= rawno
;
2365 idata
.msgno
= mn_raw2m(sp_msgmap(stream
), rawno
);
2366 idata
.stream
= stream
;
2368 index_data_env(&idata
, env
);
2371 * Look for resent-to already in MAILCACHE data
2373 if(mc
->private.msg
.header
.text
.data
){
2376 static char *linelist
[] = {"resent-to" , NULL
};
2378 if(mail_match_lines(lines
= new_strlst(linelist
),
2379 mc
->private.msg
.lines
, 0L)){
2380 idata
.valid_resent_to
= 1;
2381 memset(&szt
, 0, sizeof(SIZEDTEXT
));
2382 textcpy(&szt
, &mc
->private.msg
.header
.text
);
2383 mail_filter((char *) szt
.data
, szt
.size
, lines
, 0L);
2384 idata
.resent_to_us
= parsed_resent_to_us((char *) szt
.data
);
2386 fs_give((void **) &szt
.data
);
2389 free_strlst(&lines
);
2392 ice
= (*format_index_line
)(&idata
);
2396 paint_index_hline(stream
, idata
.msgno
, ice
);
2401 /*----------------------------------------------------------------------
2402 Scroll to specified postion.
2405 Args: pos - position to scroll to.
2407 Returns: TRUE - did the scroll operation.
2408 FALSE - was not able to do the scroll operation.
2411 index_scroll_to_pos (long int pos
)
2413 static short bad_timing
= 0;
2420 * Put the requested line at the top of the screen...
2424 * Starting at msg 'pos' find next visible message.
2426 for(i
=pos
; i
<= mn_get_total(current_index_state
->msgmap
); i
++) {
2427 if(!msgline_hidden(current_index_state
->stream
,
2428 current_index_state
->msgmap
, i
, 0)){
2429 current_index_state
->msg_at_top
= i
;
2435 * If single selection, move selected message to be on the screen.
2437 if (mn_total_cur(current_index_state
->msgmap
) == 1L) {
2438 if (current_index_state
->msg_at_top
>
2439 mn_get_cur (current_index_state
->msgmap
)) {
2440 /* Selection was above screen, move to top of screen. */
2441 mn_set_cur(current_index_state
->msgmap
,current_index_state
->msg_at_top
);
2444 /* Scan through the screen. If selection found, leave where is.
2445 * Otherwise, move to end of screen */
2446 for( i
= current_index_state
->msg_at_top
,
2447 j
= current_index_state
->lines_per_page
;
2448 i
!= mn_get_cur(current_index_state
->msgmap
) &&
2449 i
<= mn_get_total(current_index_state
->msgmap
) &&
2452 if(!msgline_hidden(current_index_state
->stream
,
2453 current_index_state
->msgmap
, i
, 0)){
2459 /* Move to end of screen. */
2460 mn_set_cur(current_index_state
->msgmap
, k
);
2470 /*----------------------------------------------------------------------
2471 Adjust the index display state down a line
2473 Args: scroll_count -- number of lines to scroll
2475 Returns: TRUE - did the scroll operation.
2476 FALSE - was not able to do the scroll operation.
2479 index_scroll_down(long int scroll_count
)
2481 static short bad_timing
= 0;
2492 total
= mn_get_total (current_index_state
->msgmap
);
2493 for(k
= i
= current_index_state
->msg_at_top
; ; i
++){
2495 /* Only examine non-hidden messages. */
2496 if(!msgline_hidden(current_index_state
->stream
,
2497 current_index_state
->msgmap
, i
, 0)){
2498 /* Remember this message */
2500 /* Increment count of lines. */
2501 if (++j
>= scroll_count
) {
2502 /* Counted enough lines, stop. */
2503 current_index_state
->msg_at_top
= k
;
2508 /* If at last message, stop. */
2510 current_index_state
->msg_at_top
= k
;
2516 * If not multiple selection, see if selected message visable. if not
2517 * set it to last visable message.
2519 if(mn_total_cur(current_index_state
->msgmap
) == 1L) {
2521 cur
= mn_get_cur (current_index_state
->msgmap
);
2522 for (i
= current_index_state
->msg_at_top
; i
<= total
; ++i
) {
2523 if(!msgline_hidden(current_index_state
->stream
,
2524 current_index_state
->msgmap
, i
, 0)){
2525 if (++j
>= current_index_state
->lines_per_page
) {
2533 mn_set_cur(current_index_state
->msgmap
,
2534 current_index_state
->msg_at_top
);
2543 /*----------------------------------------------------------------------
2544 Adjust the index display state up a line
2546 Args: scroll_count -- number of lines to scroll
2548 Returns: TRUE - did the scroll operation.
2549 FALSE - was not able to do the scroll operation.
2553 index_scroll_up(long int scroll_count
)
2555 static short bad_timing
= 0;
2565 for(k
= i
= current_index_state
->msg_at_top
; ; i
--){
2567 /* Only examine non-hidden messages. */
2568 if(!msgline_hidden(current_index_state
->stream
,
2569 current_index_state
->msgmap
, i
, 0)){
2570 /* Remember this message */
2572 /* Increment count of lines. */
2573 if (++j
>= scroll_count
) {
2574 /* Counted enough lines, stop. */
2575 current_index_state
->msg_at_top
= k
;
2580 /* If at first message, stop */
2582 current_index_state
->msg_at_top
= k
;
2589 * If not multiple selection, see if selected message visable. if not
2590 * set it to last visable message.
2592 if(mn_total_cur(current_index_state
->msgmap
) == 1L) {
2594 cur
= mn_get_cur (current_index_state
->msgmap
);
2595 for ( i
= current_index_state
->msg_at_top
;
2596 i
<= mn_get_total(current_index_state
->msgmap
);
2598 if(!msgline_hidden(current_index_state
->stream
,
2599 current_index_state
->msgmap
, i
, 0)){
2600 if (++j
>= current_index_state
->lines_per_page
) {
2609 mn_set_cur(current_index_state
->msgmap
, k
);
2619 /*----------------------------------------------------------------------
2620 Calculate the message number that should be at the top of the display
2622 Args: current - the current message number
2623 lines_per_page - the number of lines for the body of the index only
2625 Returns: -1 if the current message is -1
2626 the message entry for the first message at the top of the screen.
2628 When paging in the index it is always on even page boundies, and the
2629 current message is always on the page thus the top of the page is
2630 completely determined by the current message and the number of lines
2634 top_ent_calc(MAILSTREAM
*stream
, MSGNO_S
*msgs
, long int at_top
, long int lines_per_page
)
2636 long current
, hidden
, lastn
;
2637 long n
, m
= 0L, t
= 1L;
2639 current
= (mn_total_cur(msgs
) <= 1L) ? mn_get_cur(msgs
) : at_top
;
2644 if(lines_per_page
== 0L)
2647 if(THRD_INDX_ENABLED()){
2649 PINETHRD_S
*thrd
= NULL
;
2651 rawno
= mn_m2raw(msgs
, mn_get_cur(msgs
));
2653 thrd
= fetch_thread(stream
, rawno
);
2657 if(any_lflagged(msgs
, MN_HIDE
)){
2658 PINETHRD_S
*is_current_thrd
;
2660 is_current_thrd
= thrd
;
2661 if(is_current_thrd
){
2662 if(mn_get_revsort(msgs
)){
2663 /* start with top of tail of thread list */
2664 thrd
= fetch_thread(stream
, mn_m2raw(msgs
, 1L));
2665 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
2666 thrd
= fetch_thread(stream
, thrd
->top
);
2669 /* start with head of thread list */
2670 thrd
= fetch_head_thread(stream
);
2676 n
= mn_raw2m(msgs
, thrd
->rawno
);
2679 if(!msgline_hidden(stream
, msgs
, n
, 0)
2680 && (++m
% lines_per_page
) == 1L)
2683 if(thrd
== is_current_thrd
)
2686 if(mn_get_revsort(msgs
) && thrd
->prevthd
)
2687 thrd
= fetch_thread(stream
, thrd
->prevthd
);
2688 else if(!mn_get_revsort(msgs
) && thrd
->nextthd
)
2689 thrd
= fetch_thread(stream
, thrd
->nextthd
);
2694 n
= mn_raw2m(msgs
, thrd
->rawno
);
2701 m
= lines_per_page
* ((n
- 1L)/ lines_per_page
) + 1L;
2704 * We want to find the m'th thread and the
2705 * message number that goes with that. We just have
2706 * to back up from where we are to get there.
2707 * If we have a reverse sort backing up is going
2708 * forward through the thread.
2710 while(thrd
&& m
< thrd
->thrdno
){
2712 if(mn_get_revsort(msgs
) && thrd
->nextthd
)
2713 thrd
= fetch_thread(stream
, thrd
->nextthd
);
2714 else if(!mn_get_revsort(msgs
) && thrd
->prevthd
)
2715 thrd
= fetch_thread(stream
, thrd
->prevthd
);
2723 t
= mn_raw2m(msgs
, n
);
2727 else{ /* viewing a thread */
2729 lastn
= mn_get_total(msgs
);
2732 /* get top of thread */
2733 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
2734 thrd
= fetch_thread(stream
, thrd
->top
);
2737 if(mn_get_revsort(msgs
))
2738 lastn
= mn_raw2m(msgs
, thrd
->rawno
);
2740 t
= mn_raw2m(msgs
, thrd
->rawno
);
2745 /* n is the end of this thread */
2747 n
= mn_raw2m(msgs
, thrd
->rawno
);
2749 thrd
= fetch_thread(stream
, thrd
->branch
);
2751 thrd
= fetch_thread(stream
, thrd
->next
);
2757 if(mn_get_revsort(msgs
))
2763 for(m
= 0L, n
= t
; n
<= MIN(current
, lastn
); n
++)
2764 if(!msgline_hidden(stream
, msgs
, n
, 0)
2765 && (++m
% lines_per_page
) == 1L)
2771 else if((hidden
= any_lflagged(msgs
, MN_HIDE
| MN_CHID
)) != 0){
2773 if(current
< mn_get_total(msgs
) / 2){
2776 for(n
= 1L; n
<= MIN(current
, mn_get_total(msgs
)); n
++)
2777 if(!msgline_hidden(stream
, msgs
, n
, 0)
2778 && (++m
% lines_per_page
) == 1L)
2783 m
= mn_get_total(msgs
)-hidden
+1L;
2784 for(n
= mn_get_total(msgs
); n
>= 1L && t
> current
; n
--)
2785 if(!msgline_hidden(stream
, msgs
, n
, 0)
2786 && (--m
% lines_per_page
) == 1L)
2796 return(lines_per_page
* ((current
- 1L)/ lines_per_page
) + 1L);
2800 /*----------------------------------------------------------------------
2801 Clear various bits that make up a healthy display
2805 reset_index_border(void)
2807 mark_status_dirty();
2808 mark_keymenu_dirty();
2809 mark_titlebar_dirty();
2810 ps_global
->mangled_screen
= 1; /* signal FULL repaint */
2814 /*----------------------------------------------------------------------
2815 This redraws the body of the index screen, taking into
2816 account any change in the size of the screen. All the state needed to
2817 repaint is in the static variables so this can be called from
2821 redraw_index_body(void)
2825 if((agg
= (mn_total_cur(current_index_state
->msgmap
) > 1L)) != 0)
2826 restore_selected(current_index_state
->msgmap
);
2828 ps_global
->mangled_body
= 1;
2830 (void) update_index(ps_global
, current_index_state
);
2832 pseudo_selected(current_index_state
->stream
, current_index_state
->msgmap
);
2836 /*----------------------------------------------------------------------
2837 Give hint about Other command being optional. Some people get the idea
2838 that it is required to use the commands on the 2nd and 3rd keymenus.
2842 Result: message may be printed to status line
2845 warn_other_cmds(void)
2847 static int other_cmds
= 0;
2850 if(((ps_global
->first_time_user
|| ps_global
->show_new_version
) &&
2851 other_cmds
% 3 == 0 && other_cmds
< 10) || other_cmds
% 20 == 0)
2852 q_status_message(SM_ASYNC
, 0, 9,
2853 _("Remember the \"O\" command is always optional"));
2858 thread_command(struct pine
*state
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
,
2859 UCS preloadkeystroke
, int q_line
)
2861 PINETHRD_S
*thrd
= NULL
;
2862 unsigned long rawno
, save_branch
;
2864 int flags
= AC_FROM_THREAD
;
2866 if(!(stream
&& msgmap
))
2869 rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
2871 thrd
= fetch_thread(stream
, rawno
);
2876 save_branch
= thrd
->branch
;
2877 thrd
->branch
= 0L; /* branch is a sibling, not part of thread */
2879 if(!preloadkeystroke
){
2881 if(get_lflag(stream
, NULL
, rawno
, MN_COLL
) && thrd
->next
)
2887 if(count_lflags_in_thread(stream
, thrd
, msgmap
, MN_SLCT
)
2888 == count_lflags_in_thread(stream
, thrd
, msgmap
, MN_NONE
))
2892 we_cancel
= busy_cue(NULL
, NULL
, 1);
2894 /* save the SLCT flags in STMP for restoring at the bottom */
2895 copy_lflags(stream
, msgmap
, MN_SLCT
, MN_STMP
);
2897 /* clear the values from the SLCT flags */
2898 set_lflags(stream
, msgmap
, MN_SLCT
, 0);
2900 /* set SLCT for thrd on down */
2901 set_flags_for_thread(stream
, msgmap
, MN_SLCT
, thrd
, 1);
2902 thrd
->branch
= save_branch
;
2907 (void ) apply_command(state
, stream
, msgmap
, preloadkeystroke
, flags
,
2910 /* restore the original flags */
2911 copy_lflags(stream
, msgmap
, MN_STMP
, MN_SLCT
);
2913 if(any_lflagged(msgmap
, MN_HIDE
) > 0L){
2914 /* if nothing left selected, unhide all */
2915 if(any_lflagged(msgmap
, MN_SLCT
) == 0L){
2916 (void) unzoom_index(ps_global
, stream
, msgmap
);
2917 dprint((4, "\n\n ---- Exiting ZOOM mode ----\n"));
2918 q_status_message(SM_ORDER
,0,2, _("Index Zoom Mode is now off"));
2921 /* if current is hidden, adjust */
2922 adjust_cur_to_visible(stream
, msgmap
);
2927 /*----------------------------------------------------------------------
2928 Search the message headers as displayed in index
2930 Args: command_line -- The screen line to prompt on
2931 msg -- The current message number to start searching at
2932 max_msg -- The largest message number in the current folder
2934 The headers are searched exactly as they are displayed on the screen. The
2935 search will wrap around to the beginning if not string is not found right
2939 index_search(struct pine
*state
, MAILSTREAM
*stream
, int command_line
, MSGNO_S
*msgmap
)
2941 int rc
, select_all
= 0, flags
, prefetch
, we_turned_on
= 0;
2942 long i
, sorted_msg
, selected
= 0L;
2943 char prompt
[MAX_SEARCH
+50], new_string
[MAX_SEARCH
+1];
2944 char buf
[MAX_SCREEN_COLS
+1], *p
;
2946 char search_string
[MAX_SEARCH
+1];
2948 static HISTORY_S
*history
= NULL
;
2949 static ESCKEY_S header_search_key
[] = { {0, 0, NULL
, NULL
},
2950 {ctrl('Y'), 10, "^Y", N_("First Msg")},
2951 {ctrl('V'), 11, "^V", N_("Last Msg")},
2952 {KEY_UP
, 30, "", ""},
2953 {KEY_DOWN
, 31, "", ""},
2954 {-1, 0, NULL
, NULL
} };
2955 #define KU_IS (3) /* index of KEY_UP */
2956 #define PREFETCH_THIS_MANY_LINES (50)
2958 init_hist(&history
, HISTSIZE
);
2959 search_string
[0] = '\0';
2960 if((p
= get_prev_hist(history
, "", 0, NULL
)) != NULL
){
2961 strncpy(search_string
, p
, sizeof(search_string
));
2962 search_string
[sizeof(search_string
)-1] = '\0';
2965 dprint((4, "\n - search headers - \n"));
2967 if(!any_messages(msgmap
, NULL
, "to search")){
2970 else if(mn_total_cur(msgmap
) > 1L){
2971 q_status_message1(SM_ORDER
, 0, 2, "%s msgs selected; Can't search",
2972 comatose(mn_total_cur(msgmap
)));
2976 sorted_msg
= mn_get_cur(msgmap
);
2979 new_string
[0] = '\0';
2982 snprintf(prompt
, sizeof(prompt
), _("Word to search for [%s] : "), search_string
);
2984 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
2985 header_search_key
[0].ch
= ctrl('X');
2986 header_search_key
[0].rval
= 12;
2987 header_search_key
[0].name
= "^X";
2988 header_search_key
[0].label
= N_("Select Matches");
2991 header_search_key
[0].ch
= header_search_key
[0].rval
= 0;
2992 header_search_key
[0].name
= header_search_key
[0].label
= NULL
;
2996 * 2 is really 1 because there will be one real entry and
2997 * one entry of "" because of the get_prev_hist above.
2999 if(items_in_hist(history
) > 2){
3000 header_search_key
[KU_IS
].name
= HISTORY_UP_KEYNAME
;
3001 header_search_key
[KU_IS
].label
= HISTORY_KEYLABEL
;
3002 header_search_key
[KU_IS
+1].name
= HISTORY_DOWN_KEYNAME
;
3003 header_search_key
[KU_IS
+1].label
= HISTORY_KEYLABEL
;
3006 header_search_key
[KU_IS
].name
= "";
3007 header_search_key
[KU_IS
].label
= "";
3008 header_search_key
[KU_IS
+1].name
= "";
3009 header_search_key
[KU_IS
+1].label
= "";
3012 flags
= OE_APPEND_CURRENT
| OE_KEEP_TRAILING_SPACE
;
3014 rc
= optionally_enter(new_string
, command_line
, 0, sizeof(new_string
),
3015 prompt
, header_search_key
, help
, &flags
);
3018 help
= (help
!= NO_HELP
) ? NO_HELP
:
3019 F_ON(F_ENABLE_AGG_OPS
, ps_global
) ? h_os_index_whereis_agg
3020 : h_os_index_whereis
;
3024 q_status_message(SM_ORDER
, 0, 3, _("Searched to First Message."));
3025 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
3027 selected
= sorted_msg
;
3028 mn_dec_cur(stream
, msgmap
, MH_NONE
);
3029 sorted_msg
= mn_get_cur(msgmap
);
3031 while(selected
!= sorted_msg
);
3034 sorted_msg
= (mn_get_total(msgmap
) > 0L) ? 1L : 0L;
3036 mn_set_cur(msgmap
, sorted_msg
);
3040 q_status_message(SM_ORDER
, 0, 3, _("Searched to Last Message."));
3041 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
3043 selected
= sorted_msg
;
3044 mn_inc_cur(stream
, msgmap
, MH_NONE
);
3045 sorted_msg
= mn_get_cur(msgmap
);
3047 while(selected
!= sorted_msg
);
3050 sorted_msg
= mn_get_total(msgmap
);
3052 mn_set_cur(msgmap
, sorted_msg
);
3060 if((p
= get_prev_hist(history
, new_string
, 0, NULL
)) != NULL
){
3061 strncpy(new_string
, p
, sizeof(new_string
));
3062 new_string
[sizeof(new_string
)-1] = '\0';
3070 if((p
= get_next_hist(history
, new_string
, 0, NULL
)) != NULL
){
3071 strncpy(new_string
, p
, sizeof(new_string
));
3072 new_string
[sizeof(new_string
)-1] = '\0';
3080 if(rc
!= 4){ /* 4 is redraw */
3081 save_hist(history
, new_string
, 0, NULL
);
3086 if(rc
== 1 || (new_string
[0] == '\0' && search_string
[0] == '\0')) {
3087 cmd_cancelled(_("Search"));
3091 if(new_string
[0] == '\0'){
3092 strncpy(new_string
, search_string
, sizeof(new_string
));
3093 new_string
[sizeof(new_string
)-1] = '\0';
3096 strncpy(search_string
, new_string
, sizeof(search_string
));
3097 search_string
[sizeof(search_string
)-1] = '\0';
3099 we_turned_on
= intr_handling_on();
3102 for(i
= sorted_msg
+ ((select_all
)?0:1);
3103 i
<= mn_get_total(msgmap
) && !ps_global
->intr_pending
;
3105 if(msgline_hidden(stream
, msgmap
, i
, 0))
3109 prefetch
= PREFETCH_THIS_MANY_LINES
;
3111 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, prefetch
--, NULL
);
3113 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3115 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3119 set_lflag(stream
, msgmap
, i
, MN_SLCT
, 1);
3126 if(i
> mn_get_total(msgmap
)){
3127 for(i
= 1; i
< sorted_msg
&& !ps_global
->intr_pending
; i
++){
3128 if(msgline_hidden(stream
, msgmap
, i
, 0))
3132 prefetch
= PREFETCH_THIS_MANY_LINES
;
3134 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, prefetch
--, NULL
);
3136 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3138 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3142 set_lflag(stream
, msgmap
, i
, MN_SLCT
, 1);
3149 /* search current line */
3150 if(!select_all
&& !selected
){
3152 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
3154 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, 1, NULL
);
3156 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3158 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3165 if(ps_global
->intr_pending
){
3166 q_status_message1(SM_ORDER
, 0, 3, _("Search cancelled.%s"),
3167 select_all
? _(" Selected set may be incomplete."):"");
3169 else if(select_all
){
3171 && any_lflagged(msgmap
, MN_SLCT
) > 0L
3172 && !any_lflagged(msgmap
, MN_HIDE
)
3173 && F_ON(F_AUTO_ZOOM
, state
))
3174 (void) zoom_index(state
, stream
, msgmap
, MN_SLCT
);
3176 q_status_message1(SM_ORDER
, 0, 3, _("%s messages found matching word"),
3177 long2string(selected
));
3180 q_status_message1(SM_ORDER
, 0, 3, _("Word found%s"),
3181 (i
< sorted_msg
) ? _(". Search wrapped to beginning") :
3182 (i
== sorted_msg
) ? _(". Current line contains only match") : "");
3183 mn_set_cur(msgmap
, i
);
3186 q_status_message(SM_ORDER
, 0, 3, _("Word not found"));
3189 intr_handling_off();
3194 * Original idea from Stephen Casner <casner@acm.org>.
3196 * Apply the appropriate reverse color transformation to the given
3197 * color pair and return a new color pair. The caller should free the
3202 apply_rev_color(COLOR_PAIR
*cp
, int style
)
3204 COLOR_PAIR
*rc
= pico_get_rev_color();
3207 if(style
== IND_COL_REV
){
3208 /* just use Reverse color regardless */
3209 return(new_color_pair(rc
->fg
, rc
->bg
));
3211 else if(style
== IND_COL_FG
){
3213 * If changing to Rev fg is readable and different
3214 * from what it already is, do it.
3216 if(strcmp(rc
->fg
, cp
->bg
) && strcmp(rc
->fg
, cp
->fg
))
3217 return(new_color_pair(rc
->fg
, cp
->bg
));
3219 else if(style
== IND_COL_BG
){
3221 * If changing to Rev bg is readable and different
3222 * from what it already is, do it.
3224 if(strcmp(rc
->bg
, cp
->fg
) && strcmp(rc
->bg
, cp
->bg
))
3225 return(new_color_pair(cp
->fg
, rc
->bg
));
3227 else if(style
== IND_COL_FG_NOAMBIG
){
3229 * If changing to Rev fg is readable, different
3230 * from what it already is, and not the same as
3231 * the Rev color, do it.
3233 if(strcmp(rc
->fg
, cp
->bg
) && strcmp(rc
->fg
, cp
->fg
) &&
3234 strcmp(rc
->bg
, cp
->bg
))
3235 return(new_color_pair(rc
->fg
, cp
->bg
));
3237 else if(style
== IND_COL_BG_NOAMBIG
){
3239 * If changing to Rev bg is readable, different
3240 * from what it already is, and not the same as
3241 * the Rev color, do it.
3243 if(strcmp(rc
->bg
, cp
->fg
) && strcmp(rc
->bg
, cp
->bg
) &&
3244 strcmp(rc
->fg
, cp
->fg
))
3245 return(new_color_pair(cp
->fg
, rc
->bg
));
3249 /* come here for IND_COL_FLIP and for the cases which fail the tests */
3250 return(new_color_pair(cp
->bg
, cp
->fg
)); /* flip the colors */
3257 /*----------------------------------------------------------------------
3258 Callback to get the text of the current message. Used to display
3259 a message in an alternate window.
3261 Args: cmd - what type of scroll operation.
3262 text - filled with pointer to text.
3264 style - Returns style of text. Can be:
3265 GETTEXT_TEXT - Is a pointer to text with CRLF deliminated
3267 GETTEXT_LINES - Is a pointer to NULL terminated array of
3268 char *. Each entry points to a line of
3271 this implementation always returns GETTEXT_TEXT.
3273 Returns: TRUE - did the scroll operation.
3274 FALSE - was not able to do the scroll operation.
3277 index_scroll_callback (cmd
, scroll_pos
)
3284 case MSWIN_KEY_SCROLLUPLINE
:
3285 paint
= index_scroll_up (scroll_pos
);
3288 case MSWIN_KEY_SCROLLDOWNLINE
:
3289 paint
= index_scroll_down (scroll_pos
);
3292 case MSWIN_KEY_SCROLLUPPAGE
:
3293 paint
= index_scroll_up (current_index_state
->lines_per_page
);
3296 case MSWIN_KEY_SCROLLDOWNPAGE
:
3297 paint
= index_scroll_down (current_index_state
->lines_per_page
);
3300 case MSWIN_KEY_SCROLLTO
:
3301 /* Normalize msgno in zoomed case */
3302 if(any_lflagged(ps_global
->msgmap
, MN_HIDE
| MN_CHID
)){
3306 x
< scroll_pos
&& n
< mn_get_total(ps_global
->msgmap
);
3308 if(!msgline_hidden(ps_global
->mail_stream
, ps_global
->msgmap
,
3312 scroll_pos
= n
- 1; /* list-position --> message number */
3315 paint
= index_scroll_to_pos (scroll_pos
+ 1);
3320 mswin_beginupdate();
3321 update_titlebar_message();
3322 update_titlebar_status();
3323 redraw_index_body();
3331 /*----------------------------------------------------------------------
3332 MSWin scroll callback to get the text of the current message
3334 Args: title - title for new window
3339 Returns: TRUE - got the requested text
3340 FALSE - was not able to get the requested text
3343 index_gettext_callback(title
, titlelen
, text
, l
, style
)
3356 if(mn_get_total(ps_global
->msgmap
) > 0L
3357 && (so
= so_get(CharStar
, NULL
, WRITE_ACCESS
))){
3358 gf_set_so_writec(&pc
, so
);
3360 if((env
= pine_mail_fetchstructure(ps_global
->mail_stream
,
3361 mn_m2raw(ps_global
->msgmap
,
3362 mn_get_cur(ps_global
->msgmap
)),
3364 && format_message(mn_m2raw(ps_global
->msgmap
,
3365 mn_get_cur(ps_global
->msgmap
)),
3366 env
, body
, NULL
, FM_NEW_MESS
, pc
)){
3367 snprintf(title
, titlelen
, "Folder %s -- Message %ld of %ld",
3368 strsquish(tmp_20k_buf
+ 500, SIZEOF_20KBUF
-500, ps_global
->cur_folder
, 50),
3369 mn_get_cur(ps_global
->msgmap
),
3370 mn_get_total(ps_global
->msgmap
));
3371 title
[titlelen
-1] = '\0';
3372 *text
= so_text(so
);
3373 *l
= strlen((char *)so_text(so
));
3374 *style
= GETTEXT_TEXT
;
3376 /* free alloc'd so, but preserve the text passed back to caller */
3377 so
->txt
= (void *) NULL
;
3381 gf_clear_so_writec(so
);
3393 index_sort_callback(set
, order
)
3400 sort_folder(ps_global
->mail_stream
, ps_global
->msgmap
,
3402 (order
& 0x00000100) != 0, SRT_VRB
);
3403 mswin_beginupdate();
3404 update_titlebar_message();
3405 update_titlebar_status();
3406 redraw_index_body();
3408 flush_status_messages(1);
3411 i
= (int) mn_get_sort(ps_global
->msgmap
);
3412 if(mn_get_revsort(ps_global
->msgmap
))
3424 index_popup(IndexType style
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
, int full
)
3427 int view_in_new_wind_index
= -1;
3430 MPopup view_index_popup
[32];
3431 struct key_menu
*km
= (style
== ThreadIndex
)
3433 : (ps_global
->mail_stream
!= stream
)
3434 ? &simple_index_keymenu
3438 * Loosely follow the logic in do_index_border to figure
3439 * out which commands to show.
3443 if(km
!= &simple_index_keymenu
){
3444 view_index_popup
[n
].type
= tQueue
;
3445 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3446 ? "&View Thread" : "&View";
3447 view_index_popup
[n
].label
.style
= lNormal
;
3448 view_index_popup
[n
++].data
.val
= 'V';
3451 if(km
== &index_keymenu
){
3452 view_in_new_wind_index
= n
;
3453 view_index_popup
[n
].type
= tIndex
;
3454 view_index_popup
[n
].label
.style
= lNormal
;
3455 view_index_popup
[n
++].label
.string
= "View in New Window";
3458 if(km
!= &simple_index_keymenu
)
3459 view_index_popup
[n
++].type
= tSeparator
;
3461 if(km
== &thread_keymenu
){
3462 view_index_popup
[n
].type
= tQueue
;
3463 view_index_popup
[n
].label
.string
= "&Delete Thread";
3464 view_index_popup
[n
].label
.style
= lNormal
;
3465 view_index_popup
[n
++].data
.val
= 'D';
3467 view_index_popup
[n
].type
= tQueue
;
3468 view_index_popup
[n
].label
.string
= "&UnDelete Thread";
3469 view_index_popup
[n
].label
.style
= lNormal
;
3470 view_index_popup
[n
++].data
.val
= 'U';
3473 /* Make "delete/undelete" item sensitive */
3474 mc
= ((rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
))) > 0L
3475 && stream
&& rawno
<= stream
->nmsgs
)
3476 ? mail_elt(stream
, rawno
) : NULL
;
3477 view_index_popup
[n
].type
= tQueue
;
3478 view_index_popup
[n
].label
.style
= lNormal
;
3479 if(mc
&& mc
->deleted
){
3480 view_index_popup
[n
].label
.string
= "&Undelete";
3481 view_index_popup
[n
++].data
.val
= 'U';
3484 view_index_popup
[n
].label
.string
= "&Delete";
3485 view_index_popup
[n
++].data
.val
= 'D';
3489 if(km
== &index_keymenu
&& F_ON(F_ENABLE_FLAG
, ps_global
)){
3490 view_index_popup
[n
].type
= tSubMenu
;
3491 view_index_popup
[n
].label
.string
= "Flag";
3492 view_index_popup
[n
++].data
.submenu
= flag_submenu(mc
);
3495 if(km
== &simple_index_keymenu
){
3496 view_index_popup
[n
].type
= tQueue
;
3497 view_index_popup
[n
].label
.style
= lNormal
;
3498 view_index_popup
[n
].label
.string
= "&Select";
3499 view_index_popup
[n
++].data
.val
= 'S';
3502 view_index_popup
[n
].type
= tQueue
;
3503 view_index_popup
[n
].label
.style
= lNormal
;
3504 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3505 ? "&Save Thread" : "&Save";
3506 view_index_popup
[n
++].data
.val
= 'S';
3508 view_index_popup
[n
].type
= tQueue
;
3509 view_index_popup
[n
].label
.style
= lNormal
;
3510 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3511 ? "&Export Thread" : "&Export";
3512 view_index_popup
[n
++].data
.val
= 'E';
3514 view_index_popup
[n
].type
= tQueue
;
3515 view_index_popup
[n
].label
.style
= lNormal
;
3516 view_index_popup
[n
].label
.string
= "Print";
3517 view_index_popup
[n
++].data
.val
= '%';
3519 view_index_popup
[n
].type
= tQueue
;
3520 view_index_popup
[n
].label
.style
= lNormal
;
3521 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3522 ? "&Reply To Thread" : "&Reply";
3523 view_index_popup
[n
++].data
.val
= 'R';
3525 view_index_popup
[n
].type
= tQueue
;
3526 view_index_popup
[n
].label
.style
= lNormal
;
3527 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3528 ? "&Forward Thread" : "&Forward";
3529 view_index_popup
[n
++].data
.val
= 'F';
3531 if(F_ON(F_ENABLE_BOUNCE
, ps_global
)){
3532 view_index_popup
[n
].type
= tQueue
;
3533 view_index_popup
[n
].label
.style
= lNormal
;
3534 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3535 ? "&Bounce Thread" : "&Bounce";
3536 view_index_popup
[n
++].data
.val
= 'B';
3539 view_index_popup
[n
].type
= tQueue
;
3540 view_index_popup
[n
].label
.style
= lNormal
;
3541 view_index_popup
[n
].label
.string
= "&Take Addresses";
3542 view_index_popup
[n
++].data
.val
= 'T';
3544 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
3545 view_index_popup
[n
].type
= tQueue
;
3546 view_index_popup
[n
].label
.style
= lNormal
;
3547 view_index_popup
[n
].label
.string
= "[Un]Select Current";
3548 view_index_popup
[n
++].data
.val
= ':';
3552 view_index_popup
[n
].type
= tQueue
;
3553 view_index_popup
[n
].label
.style
= lNormal
;
3554 view_index_popup
[n
].label
.string
= "&WhereIs";
3555 view_index_popup
[n
++].data
.val
= 'W';
3557 view_index_popup
[n
++].type
= tSeparator
;
3560 if(km
== &simple_index_keymenu
){
3561 view_index_popup
[n
].type
= tQueue
;
3562 view_index_popup
[n
].label
.style
= lNormal
;
3563 view_index_popup
[n
].label
.string
= "&Exit Select";
3564 view_index_popup
[n
++].data
.val
= 'E';
3566 else if(km
== &index_keymenu
&& THREADING() && sp_viewing_a_thread(stream
)){
3567 view_index_popup
[n
].type
= tQueue
;
3568 view_index_popup
[n
].label
.style
= lNormal
;
3569 view_index_popup
[n
].label
.string
= "Thread Index";
3570 view_index_popup
[n
++].data
.val
= '<';
3573 view_index_popup
[n
].type
= tQueue
;
3574 view_index_popup
[n
].label
.style
= lNormal
;
3575 view_index_popup
[n
].label
.string
= "Folder &List";
3576 view_index_popup
[n
++].data
.val
= '<';
3579 view_index_popup
[n
].type
= tQueue
;
3580 view_index_popup
[n
].label
.style
= lNormal
;
3581 view_index_popup
[n
].label
.string
= "&Main Menu";
3582 view_index_popup
[n
++].data
.val
= 'M';
3584 view_index_popup
[n
].type
= tTail
;
3586 if(mswin_popup(view_index_popup
) == view_in_new_wind_index
3587 && view_in_new_wind_index
>= 0)
3588 view_in_new_window();
3593 pcpine_help_index(title
)
3597 * Title is size 256 in pico. Put in args.
3600 strncpy(title
, "Alpine MESSAGE INDEX Help", 256);
3602 return(pcpine_help(h_mail_index
));
3606 pcpine_help_index_simple(title
)
3610 * Title is size 256 in pico. Put in args.
3613 strncpy(title
, "Alpine SELECT MESSAGE Help", 256);
3615 return(pcpine_help(h_simple_index
));
3619 #include "../pico/osdep/mswin_tw.h"
3623 view_in_new_window(void)
3625 char title
[GETTEXT_TITLELEN
+1];
3629 MSWIN_TEXTWINDOW
*mswin_tw
= NULL
;
3631 /* Launch text in alt window. */
3632 if(index_gettext_callback(title
, sizeof (title
), &text
, &len
, &format
)){
3633 if(format
== GETTEXT_TEXT
)
3634 mswin_tw
= mswin_displaytext(title
, text
, (size_t) len
, NULL
,
3635 NULL
, MSWIN_DT_USEALTWINDOW
);
3636 else if(format
== GETTEXT_LINES
)
3637 mswin_tw
= mswin_displaytext(title
, NULL
, 0, text
,
3638 NULL
, MSWIN_DT_USEALTWINDOW
);
3640 if(mswin_tw
!= NULL
)
3641 mswin_set_readonly(mswin_tw
, FALSE
);
3645 #endif /* _WINDOWS */