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 2013-2018 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
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 if(any_lflagged(msgmap
, MN_SLCT
)){
802 PINETHRD_S
*thrd
, *topthrd
;
803 for(i
= 1L; i
> 0L && i
<= mn_get_total(msgmap
);){
804 thrd
= fetch_thread(stream
, i
);
805 if(thrd
&& thrd
->top
)
806 topthrd
= fetch_thread(stream
, thrd
->top
);
808 set_thread_lflags(stream
, topthrd
, msgmap
, MN_CHID
, 1);
809 set_thread_lflags(stream
, topthrd
, msgmap
, MN_CHID2
, 0);
810 set_lflag(stream
, msgmap
, mn_raw2m(msgmap
, topthrd
->rawno
), MN_CHID
, 0);
811 set_lflag(stream
, msgmap
, mn_raw2m(msgmap
, topthrd
->rawno
), MN_COLL
, 1);
816 msgmap
->top
= msgmap
->top_after_thrd
;
817 if(unview_thread(state
, stream
, msgmap
)){
818 state
->next_screen
= mail_index_screen
;
819 state
->view_skipped_index
= 0;
820 state
->mangled_screen
= 1;
821 ps_global
->redrawer
= NULL
;
822 current_index_state
= NULL
;
824 fs_give((void **)&(id
.entry_state
));
838 mouse_get_last (NULL
, &mp
);
841 for(i
= id
.msg_at_top
;
842 mp
.row
>= 0 && i
<= mn_get_total(msgmap
);
844 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
849 if(mn_get_total(msgmap
) && mp
.row
< 0){
852 if(mn_total_cur(msgmap
) == 1L)
853 mn_set_cur(msgmap
, new_cur
);
855 if(mp
.flags
& M_KEY_CONTROL
){
856 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
857 (void) select_by_current(state
, msgmap
, MsgIndx
);
860 else if(!(mp
.flags
& M_KEY_SHIFT
)){
863 && mp
.col
== id
.plus_col
864 && style
!= ThreadIndex
){
865 collapse_or_expand(state
, stream
, msgmap
,
868 else if (mp
.doubleclick
){
869 if(mp
.button
== M_BUTTON_LEFT
){
870 if(stream
== state
->mail_stream
){
881 ps_global
->redrawer
= NULL
;
882 current_index_state
= NULL
;
884 fs_give((void **)&(id
.entry_state
));
893 case M_BUTTON_MIDDLE
:
896 case M_BUTTON_RIGHT
:
898 if (!mp
.doubleclick
){
899 if(mn_total_cur(msgmap
) == 1L)
900 mn_set_cur(msgmap
, new_cur
);
902 cur_row
= update_index(state
, &id
);
904 index_popup(style
, stream
, msgmap
, TRUE
);
915 case M_BUTTON_MIDDLE
:
918 case M_BUTTON_RIGHT
:
920 index_popup(style
, stream
, msgmap
, FALSE
);
930 /*---------- Resize ----------*/
933 * If we were smarter we could do the
934 * IC_CLEAR_WIDTHS_DONE trick here. The problem is
935 * that entire columns of the format can go away or
936 * appear because the width gets smaller or larger,
937 * so in that case we need to re-do. If we could tell
938 * when that happened or not we could set the flag
941 clear_index_cache(stream
, 0);
942 reset_index_border();
948 /*---------- Redraw ----------*/
950 force
= 1; /* check for new mail! */
951 reset_index_border();
955 /*---------- No op command ----------*/
957 break; /* no op check for new mail */
960 /*--------- keystroke not bound to command --------*/
966 if(cmd
== MC_UNKNOWN
&& (ch
== 'i' || ch
== 'I'))
967 q_status_message(SM_ORDER
, 0, 1, "Already in Index");
969 bogus_command(ch
, F_ON(F_USE_FK
,state
) ? "F1" : "?");
975 thread_command(state
, stream
, msgmap
, ch
, -FOOTER_ROWS(state
));
991 PINETHRD_S
*thrd
= NULL
;
994 rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
996 thrd
= fetch_thread(stream
, rawno
);
998 collapsed
= thrd
&& thrd
->next
999 && get_lflag(stream
, NULL
, rawno
, MN_COLL
);
1003 thread_command(state
, stream
, msgmap
,
1004 ch
, -FOOTER_ROWS(state
));
1005 /* increment current */
1006 if(cmd
== MC_DELETE
){
1007 advance_cur_after_delete(state
, stream
, msgmap
,
1009 || style
== MultiMsgIndex
1010 || style
== ZoomIndex
)
1012 : (style
== ThreadIndex
)
1016 else if((cmd
== MC_SELCUR
1017 && (state
->ugly_consider_advancing_bit
1018 || F_OFF(F_UNSELECT_WONT_ADVANCE
, state
)))
1019 || (state
->ugly_consider_advancing_bit
1021 && F_ON(F_SAVE_ADVANCES
, state
))){
1022 mn_inc_cur(stream
, msgmap
, MH_NONE
);
1026 goto do_the_default
;
1033 bogus_utf8_command(utf8str
, NULL
);
1037 /*---------- First HELP command with menu hidden ----------*/
1039 if(FOOTER_ROWS(state
) == 1 && km_popped
== 0){
1041 mark_status_unknown();
1042 mark_keymenu_dirty();
1043 state
->mangled_footer
= 1;
1046 /* else fall thru to normal default */
1049 /*---------- Default -- all other command ----------*/
1052 if(stream
== state
->mail_stream
){
1053 msgmap
->top
= id
.msg_at_top
;
1054 process_cmd(state
, stream
, msgmap
, cmd
,
1056 || style
== MultiMsgIndex
1057 || style
== ZoomIndex
)
1059 : (style
== ThreadIndex
)
1063 if(state
->next_screen
!= SCREEN_FUN_NULL
){
1064 ps_global
->redrawer
= NULL
;
1065 current_index_state
= NULL
;
1067 fs_give((void **)&(id
.entry_state
));
1072 if(stream
!= state
->mail_stream
){
1074 * Must have had an failed open. repair our
1077 id
.stream
= stream
= state
->mail_stream
;
1078 id
.msgmap
= msgmap
= state
->msgmap
;
1081 current_index_state
= &id
;
1083 if(cmd
== MC_ZOOM
&& THRD_INDX())
1087 else{ /* special processing */
1090 helper(h_simple_index
,
1091 (!strcmp(folder
, INTERRUPTED_MAIL
))
1092 ? _("HELP FOR SELECTING INTERRUPTED MSG")
1093 : _("HELP FOR SELECTING POSTPONED MSG"),
1095 state
->mangled_screen
= 1;
1098 case MC_DELETE
: /* delete */
1099 dprint((3, "Special delete: msg %s\n",
1100 long2string(mn_get_cur(msgmap
))));
1106 raw
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
1107 if(raw
> 0L && stream
1108 && raw
<= stream
->nmsgs
1109 && (mc
= mail_elt(stream
, raw
))
1111 if((t
= mn_get_cur(msgmap
)) > 0L)
1112 clear_index_cache_ent(stream
, t
, 0);
1114 mail_setflag(stream
,long2string(raw
),"\\DELETED");
1115 update_titlebar_status();
1119 q_status_message1(SM_ORDER
, 0, 1,
1120 del
? _("Message %s deleted") : _("Message %s already deleted"),
1121 long2string(mn_get_cur(msgmap
)));
1126 case MC_UNDELETE
: /* UNdelete */
1127 dprint((3, "Special UNdelete: msg %s\n",
1128 long2string(mn_get_cur(msgmap
))));
1134 raw
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
1135 if(raw
> 0L && stream
1136 && raw
<= stream
->nmsgs
1137 && (mc
= mail_elt(stream
, raw
))
1139 if((t
= mn_get_cur(msgmap
)) > 0L)
1140 clear_index_cache_ent(stream
, t
, 0);
1142 mail_clearflag(stream
, long2string(raw
),
1144 update_titlebar_status();
1148 q_status_message1(SM_ORDER
, 0, 1,
1149 del
? _("Message %s UNdeleted") : _("Message %s NOT deleted"),
1150 long2string(mn_get_cur(msgmap
)));
1155 case MC_EXIT
: /* exit */
1156 ps_global
->redrawer
= NULL
;
1157 current_index_state
= NULL
;
1159 fs_give((void **)&(id
.entry_state
));
1163 case MC_SELECT
: /* select */
1164 ps_global
->redrawer
= NULL
;
1165 current_index_state
= NULL
;
1167 fs_give((void **)&(id
.entry_state
));
1171 case MC_PREVITEM
: /* previous */
1172 mn_dec_cur(stream
, msgmap
, MH_NONE
);
1175 case MC_NEXTITEM
: /* next */
1176 mn_inc_cur(stream
, msgmap
, MH_NONE
);
1180 bogus_command(ch
, NULL
);
1184 } /* The big switch */
1185 } /* the BIG while loop! */
1190 /*----------------------------------------------------------------------
1191 Manage index body painting
1193 Args: state - pine struct containing selected message data
1194 index_state - struct describing what's currently displayed
1196 Returns: screen row number of first highlighted message
1198 The idea is pretty simple. Maintain an array of index line id's that
1199 are displayed and their hilited state. Decide what's to be displayed
1200 and update the screen appropriately. All index screen painting
1201 is done here. Pretty simple, huh?
1204 update_index(struct pine
*state
, struct index_state
*screen
)
1206 int i
, retval
= -1, row
, already_fetched
= 0;
1208 PINETHRD_S
*thrd
= NULL
;
1211 dprint((7, "--update_index--\n"));
1217 mswin_beginupdate();
1220 /*---- reset the works if necessary ----*/
1221 if(state
->mangled_body
){
1223 if(screen
->entry_state
){
1224 fs_give((void **)&(screen
->entry_state
));
1225 screen
->lines_per_page
= 0;
1229 state
->mangled_body
= 0;
1231 /*---- make sure we have a place to write state ----*/
1232 if(screen
->lines_per_page
1233 != MAX(0, state
->ttyo
->screen_rows
- FOOTER_ROWS(state
)
1234 - HEADER_ROWS(state
))){
1235 i
= screen
->lines_per_page
;
1236 screen
->lines_per_page
1237 = MAX(0, state
->ttyo
->screen_rows
- FOOTER_ROWS(state
)
1238 - HEADER_ROWS(state
));
1240 size_t len
= screen
->lines_per_page
* sizeof(struct entry_state
);
1241 screen
->entry_state
= (struct entry_state
*) fs_get(len
);
1244 fs_resize((void **)&(screen
->entry_state
),
1245 (size_t)screen
->lines_per_page
);
1247 for(; i
< screen
->lines_per_page
; i
++) /* init new entries */
1248 memset(&screen
->entry_state
[i
], 0, sizeof(struct entry_state
));
1251 /*---- figure out the first message on the display ----*/
1252 if(screen
->msg_at_top
< 1L
1253 || msgline_hidden(screen
->stream
, screen
->msgmap
, screen
->msg_at_top
,0)){
1254 screen
->msg_at_top
= top_ent_calc(screen
->stream
, screen
->msgmap
,
1256 screen
->lines_per_page
);
1258 else if(mn_get_cur(screen
->msgmap
) < screen
->msg_at_top
){
1261 /* scroll back a page at a time until current is displayed */
1262 while(mn_get_cur(screen
->msgmap
) < screen
->msg_at_top
){
1263 for(i
= screen
->lines_per_page
, j
= screen
->msg_at_top
-1L, k
= 0L;
1266 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, j
, 0)){
1271 if(i
== screen
->lines_per_page
)
1272 break; /* can't scroll back ? */
1274 screen
->msg_at_top
= k
;
1277 else if(mn_get_cur(screen
->msgmap
) >= screen
->msg_at_top
1278 + screen
->lines_per_page
){
1282 for(i
= screen
->lines_per_page
, j
= k
= screen
->msg_at_top
;
1283 j
<= mn_get_total(screen
->msgmap
) && i
> 0L;
1285 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, j
, 0)){
1288 if(mn_get_cur(screen
->msgmap
) <= k
)
1292 if(mn_get_cur(screen
->msgmap
) <= k
)
1295 /* set msg_at_top to next displayed message */
1296 for(i
= k
+ 1L; i
<= mn_get_total(screen
->msgmap
); i
++)
1297 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, i
, 0)){
1302 screen
->msg_at_top
= k
;
1309 * Set scroll range and position. Note that message numbers start at 1
1310 * while scroll position starts at 0.
1313 if(THREADING() && sp_viewing_a_thread(screen
->stream
)
1314 && mn_get_total(screen
->msgmap
) > 1L){
1315 long x
= 0L, range
= 0L, lowest_numbered_msg
;
1318 * We know that all visible messages in the thread are marked
1321 thrd
= fetch_thread(screen
->stream
,
1322 mn_m2raw(screen
->msgmap
,
1323 mn_get_cur(screen
->msgmap
)));
1324 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
1325 thrd
= fetch_thread(screen
->stream
, thrd
->top
);
1328 if(mn_get_revsort(screen
->msgmap
)){
1329 n
= mn_raw2m(screen
->msgmap
, thrd
->rawno
);
1330 while(n
> 1L && get_lflag(screen
->stream
, screen
->msgmap
,
1334 lowest_numbered_msg
= n
;
1337 lowest_numbered_msg
= mn_raw2m(screen
->msgmap
, thrd
->rawno
);
1341 n
= lowest_numbered_msg
;
1342 for(; n
<= mn_get_total(screen
->msgmap
); n
++){
1344 if(!get_lflag(screen
->stream
, screen
->msgmap
, n
, MN_CHID2
))
1347 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0)){
1349 if(n
< screen
->msg_at_top
)
1355 scroll_setrange(screen
->lines_per_page
, range
-1L);
1358 else if(THRD_INDX()){
1359 if(any_lflagged(screen
->msgmap
, MN_HIDE
)){
1362 range
= screen
->msgmap
->visible_threads
- 1L;
1363 scroll_setrange(screen
->lines_per_page
, range
);
1364 if(range
>= screen
->lines_per_page
){ /* else not needed */
1365 PINETHRD_S
*topthrd
;
1369 /* find top of currently displayed top line */
1370 topthrd
= fetch_thread(screen
->stream
,
1371 mn_m2raw(screen
->msgmap
,
1372 screen
->msg_at_top
));
1373 if(topthrd
&& topthrd
->top
!= topthrd
->rawno
)
1374 topthrd
= fetch_thread(screen
->stream
, topthrd
->top
);
1378 * Split into two halves to speed up finding scroll pos.
1379 * It's tricky because the thread list always goes from
1380 * past to future but the thrdno's will be reversed if
1381 * the sort is reversed and of course the order on the
1382 * screen will be reversed.
1384 if((!mn_get_revsort(screen
->msgmap
)
1385 && topthrd
->thrdno
<= screen
->msgmap
->max_thrdno
/2)
1387 (mn_get_revsort(screen
->msgmap
)
1388 && topthrd
->thrdno
> screen
->msgmap
->max_thrdno
/2)){
1390 /* start with head of thread list */
1391 if(topthrd
&& topthrd
->head
)
1392 thrd
= fetch_thread(screen
->stream
, topthrd
->head
);
1402 * Start with tail thread and work back.
1404 if(mn_get_revsort(screen
->msgmap
))
1405 tailrawno
= mn_m2raw(screen
->msgmap
, 1L);
1407 tailrawno
= mn_m2raw(screen
->msgmap
,
1408 mn_get_total(screen
->msgmap
));
1410 thrd
= fetch_thread(screen
->stream
, tailrawno
);
1411 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
1412 thrd
= fetch_thread(screen
->stream
, thrd
->top
);
1418 * x is the scroll position. We try to use the fewest
1419 * number of steps to find it, so we start with either
1420 * the beginning or the end.
1422 if(topthrd
->thrdno
<= screen
->msgmap
->max_thrdno
/2){
1431 while(thrd
&& thrd
!= topthrd
){
1432 if(!msgline_hidden(screen
->stream
, screen
->msgmap
,
1433 mn_raw2m(screen
->msgmap
,thrd
->rawno
),
1437 if(thrddir
> 0 && thrd
->nextthd
)
1438 thrd
= fetch_thread(screen
->stream
, thrd
->nextthd
);
1439 else if(thrddir
< 0 && thrd
->prevthd
)
1440 thrd
= fetch_thread(screen
->stream
, thrd
->prevthd
);
1451 * This works for forward or reverse sort because the thrdno's
1452 * will have been reversed.
1454 thrd
= fetch_thread(screen
->stream
,
1455 mn_m2raw(screen
->msgmap
, screen
->msg_at_top
));
1457 scroll_setrange(screen
->lines_per_page
,
1458 screen
->msgmap
->max_thrdno
- 1L);
1459 scroll_setpos(thrd
->thrdno
- 1L);
1463 else if(n
= any_lflagged(screen
->msgmap
, MN_HIDE
| MN_CHID
)){
1466 range
= mn_get_total(screen
->msgmap
) - n
- 1L;
1467 scroll_setrange(screen
->lines_per_page
, range
);
1469 if(range
>= screen
->lines_per_page
){ /* else not needed */
1470 if(screen
->msg_at_top
< mn_get_total(screen
->msgmap
) / 2){
1471 for(n
= 1, x
= 0; n
!= screen
->msg_at_top
; n
++)
1472 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1476 for(n
= mn_get_total(screen
->msgmap
), x
= range
;
1477 n
!= screen
->msg_at_top
; n
--)
1478 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1486 scroll_setrange(screen
->lines_per_page
,
1487 mn_get_total(screen
->msgmap
) - 1L);
1488 scroll_setpos(screen
->msg_at_top
- 1L);
1493 * Set up c-client call back to tell us about IMAP envelope arrivals
1494 * Can't do it (easily) if single lines on the screen need information
1495 * about more than a single message before they can be drawn.
1497 if(F_OFF(F_QUELL_IMAP_ENV_CB
, ps_global
) && !THRD_INDX()
1498 && !(THREADING() && (sp_viewing_a_thread(screen
->stream
)
1499 || ps_global
->thread_disp_style
== THREAD_MUTTLIKE
1500 || any_lflagged(screen
->msgmap
, MN_COLL
))))
1501 mail_parameters(NULL
, SET_IMAPENVELOPE
, (void *) pine_imap_envelope
);
1504 visible
= screen
->msgmap
->visible_threads
;
1505 else if(THREADING() && sp_viewing_a_thread(screen
->stream
)){
1507 * We know that all visible messages in the thread are marked
1510 for(visible
= 0L, n
= screen
->msg_at_top
;
1511 visible
< (int) screen
->lines_per_page
1512 && n
<= mn_get_total(screen
->msgmap
); n
++){
1514 if(!get_lflag(screen
->stream
, screen
->msgmap
, n
, MN_CHID2
))
1517 if(!msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1522 visible
= mn_get_total(screen
->msgmap
)
1523 - any_lflagged(screen
->msgmap
, MN_HIDE
|MN_CHID
);
1525 /*---- march thru display lines, painting whatever is needed ----*/
1526 for(i
= 0, n
= screen
->msg_at_top
; i
< (int) screen
->lines_per_page
; i
++){
1527 if(visible
== 0L || n
< 1 || n
> mn_get_total(screen
->msgmap
)){
1528 if(screen
->entry_state
[i
].id
!= LINE_HASH_N
){
1529 screen
->entry_state
[i
].hilite
= 0;
1530 screen
->entry_state
[i
].bolded
= 0;
1531 screen
->entry_state
[i
].msgno
= 0L;
1532 screen
->entry_state
[i
].id
= LINE_HASH_N
;
1533 ClearLine(HEADER_ROWS(state
) + i
);
1540 * This changes status_col as a side effect so it has to be
1541 * executed before next line.
1543 ice
= build_header_line(state
, screen
->stream
, screen
->msgmap
,
1544 n
, &already_fetched
);
1549 unsigned long rawno
;
1551 rawno
= mn_m2raw(screen
->msgmap
, n
);
1553 thrd
= fetch_thread(screen
->stream
, rawno
);
1556 row
= paint_index_line(ice
, i
,
1557 (THRD_INDX() && thrd
) ? thrd
->thrdno
: n
,
1558 screen
->status_fld
, screen
->plus_fld
,
1559 screen
->arrow_fld
, &screen
->entry_state
[i
],
1560 mn_is_cur(screen
->msgmap
, n
),
1562 ? (count_lflags_in_thread(screen
->stream
,
1566 : get_lflag(screen
->stream
, screen
->msgmap
,
1569 if(row
&& retval
< 0)
1573 /*--- increment n ---*/
1574 while((visible
== -1L || visible
> 0L)
1575 && ++n
<= mn_get_total(screen
->msgmap
)
1576 && msgline_hidden(screen
->stream
, screen
->msgmap
, n
, 0))
1581 cancel_busy_cue(-1);
1583 mail_parameters(NULL
, SET_IMAPENVELOPE
, (void *) NULL
);
1589 dprint((7, "--update_index done\n"));
1595 /*----------------------------------------------------------------------
1596 Create a string summarizing the message header for index on screen
1598 Args: stream -- mail stream to fetch envelope info from
1599 msgmap -- message number to pine sort mapping
1600 msgno -- Message number to create line for
1602 Result: returns a malloced string
1603 saves string in a cache for next call for same header
1606 build_header_line(struct pine
*state
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
, long int msgno
, int *already_fetched
)
1608 return(build_header_work(state
, stream
, msgmap
, msgno
,
1609 current_index_state
->msg_at_top
,
1610 current_index_state
->lines_per_page
,
1615 /*----------------------------------------------------------------------
1616 Paint the given index line
1619 Args: ice -- index cache entry
1620 line -- index line number on screen, starting at 0 for first
1621 visible line, 1, 2, ...
1622 msgno -- for painting the message number field
1623 sfld -- field type of the status field, which is
1624 where we'll put the X for selected if necessary
1625 pfld -- field type where the thread indicator symbol goes
1626 afld -- field type of column which corresponds to the
1627 index-format ARROW token
1628 entry -- cache used to help us decide whether or not we need to
1629 redraw the index line or if we can just leave it alone because
1630 we know it is already correct
1631 cur -- is this the current message?
1632 sel -- is this message in the selected set?
1634 Returns: screen row number if this is current message, else 0
1637 paint_index_line(ICE_S
*argice
, int line
, long int msgno
, IndexColType sfld
,
1638 IndexColType pfld
, IndexColType afld
, struct entry_state
*entry
,
1641 COLOR_PAIR
*lastc
= NULL
, *base_color
= NULL
;
1643 IFIELD_S
*ifield
, *previfield
= NULL
;
1645 int save_schar1
= -1, save_schar2
= -1, save_pchar
= -1, i
;
1646 int draw_whole_line
= 0, draw_partial_line
= 0;
1647 int n
= MAX_SCREEN_COLS
*6;
1648 char draw
[MAX_SCREEN_COLS
*6+1], *p
;
1650 ice
= (THRD_INDX() && argice
) ? argice
->tice
: argice
;
1652 /* This better not happen! */
1654 q_status_message3(SM_ORDER
| SM_DING
, 5, 5,
1655 "NULL ice in paint_index_line: %s, msgno=%s line=%s",
1656 THRD_INDX() ? "THRD_INDX" : "reg index",
1657 comatose(msgno
), comatose(line
));
1658 dprint((1, "NULL ice in paint_index_line: %s, msgno=%ld line=%d\n",
1659 THRD_INDX() ? "THRD_INDX" : "reg index",
1664 if(entry
->msgno
!= msgno
|| ice
->id
== 0 || entry
->id
!= ice
->id
){
1667 draw_whole_line
= 1;
1669 else if((cur
!= entry
->hilite
) || (sel
!= entry
->bolded
)
1670 || (ice
->plus
!= entry
->plus
)){
1671 draw_partial_line
= 1;
1674 if(draw_whole_line
|| draw_partial_line
){
1676 if(F_ON(F_FORCE_LOW_SPEED
,ps_global
) || ps_global
->low_speed
){
1678 memset(draw
, 0, sizeof(draw
));
1681 for(ifield
= ice
->ifield
; ifield
&& p
-draw
< n
; ifield
= ifield
->next
){
1683 /* space between fields */
1684 if(ifield
!= ice
->ifield
&& !(previfield
&& previfield
->ctype
== iText
))
1687 /* message number string is generated on the fly */
1688 if(ifield
->ctype
== iMessNo
){
1689 ielem
= ifield
->ielem
;
1690 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1691 snprintf(ielem
->data
, ielem
->datalen
+1, "%*.ld", ifield
->width
, msgno
);
1692 ielem
->data
[ifield
->width
] = '\0';
1693 ielem
->data
[ielem
->datalen
] = '\0';
1697 if(ifield
->ctype
== sfld
){
1698 ielem
= ifield
->ielem
;
1699 if(ielem
&& ielem
->datalen
> 0){
1700 if(draw_partial_line
)
1701 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1703 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 if(ielem
->next
&& ielem
->next
->datalen
){
1710 save_schar2
= ielem
->next
->data
[0];
1712 ielem
->next
->data
[0] = '>';
1714 if(draw_partial_line
)
1715 Writechar(ielem
->next
->data
[0], 0);
1718 else if(ielem
->datalen
> 1){
1719 save_schar1
= ielem
->data
[0];
1720 ielem
->data
[0] = (sel
) ? 'X' : (cur
&& save_schar1
== ' ') ? '-' : save_schar1
;
1721 if(draw_partial_line
)
1722 Writechar(ielem
->data
[0], 0);
1724 save_schar2
= ielem
->data
[1];
1726 ielem
->data
[1] = '>';
1727 if(draw_partial_line
)
1728 Writechar(ielem
->data
[1], 0);
1733 else if(ifield
->ctype
== afld
){
1735 if(draw_partial_line
){
1736 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1737 for(i
= 0; i
< ifield
->width
-1; i
++)
1738 Writechar(cur
? '-' : ' ', 0);
1740 Writechar(cur
? '>' : ' ', 0);
1743 ielem
= ifield
->ielem
;
1744 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1745 for(i
= 0; i
< ifield
->width
-1; i
++)
1746 ielem
->data
[i
] = cur
? '-' : ' ';
1748 ielem
->data
[i
] = cur
? '>' : ' ';
1751 else if(ifield
->ctype
== pfld
){
1752 ielem
= ifield
->ielem
;
1753 if(ielem
&& ielem
->datalen
> 0){
1754 save_pchar
= ielem
->data
[0];
1755 ielem
->data
[0] = ice
->plus
;
1757 if(draw_partial_line
){
1758 MoveCursor(HEADER_ROWS(ps_global
) + line
, utf8_width(draw
));
1759 Writechar(ielem
->data
[0], 0);
1765 for(ielem
= ifield
->ielem
;
1766 ielem
&& ielem
->print_format
&& p
-draw
< n
;
1767 ielem
= ielem
->next
){
1772 bytes_added
= utf8_pad_to_width(p
, src
,
1773 ((n
+1)-(p
-draw
)) * sizeof(char),
1774 ielem
->wid
, ifield
->leftadj
);
1780 if(ifield
->ctype
== sfld
){
1781 ielem
= ifield
->ielem
;
1782 if(ielem
&& ielem
->datalen
> 0){
1783 if(ielem
->datalen
== 1){
1784 ielem
->data
[0] = save_schar1
;
1785 if(ielem
->next
&& ielem
->next
->datalen
)
1786 ielem
->next
->data
[0] = save_schar2
;
1788 else if(ielem
->datalen
> 1){
1789 ielem
->data
[0] = save_schar1
;
1790 ielem
->data
[1] = save_schar2
;
1794 else if(ifield
->ctype
== afld
){
1795 ielem
= ifield
->ielem
;
1796 if(ielem
&& ielem
->datalen
>= ifield
->width
)
1797 for(i
= 0; i
< ifield
->width
; i
++)
1798 ielem
->data
[i
] = ' ';
1800 else if(ifield
->ctype
== pfld
){
1801 ielem
= ifield
->ielem
;
1802 if(ielem
&& ielem
->datalen
> 0)
1803 ielem
->data
[0] = save_pchar
;
1806 previfield
= ifield
;
1812 PutLine0(HEADER_ROWS(ps_global
) + line
, 0, draw
);
1815 int uc
, ac
, do_arrow
;
1817 int inverse_hack
= 0, need_inverse_hack
= 0;
1820 /* so we can restore current color at the end */
1821 if((uc
=pico_usingcolor()) != 0)
1822 lastc
= pico_get_cur_color();
1825 * There are two possible "arrow" cursors. One is the one that
1826 * you get when you are at a slow speed or you turn that slow
1827 * speed one on. It is drawn as part of the status column.
1828 * That one is the one associated with the variable "ac".
1829 * It is always the base_color or the inverse of the base_color.
1831 * The other "arrow" cursor is the one you get by including the
1832 * ARROW token in the index-format. It may be configured to
1835 * The arrow cursors have two special properties that make
1836 * them different from other sections or fields.
1837 * First, the arrow cursors only show up on the current line.
1838 * Second, the arrow cursors are drawn with generated data, not
1839 * data that is present in the passed in data.
1842 /* ac is for the old integrated arrow cursor */
1843 ac
= F_ON(F_FORCE_ARROW
,ps_global
);
1845 /* do_arrow is for the ARROW token in index-format */
1846 do_arrow
= (afld
!= iNothing
);
1848 MoveCursor(HEADER_ROWS(ps_global
) + line
, 0);
1850 /* find the base color for the whole line */
1851 if(cur
&& !ac
&& !do_arrow
){
1853 * This stanza handles the current line marking in the
1854 * regular, non-arrow-cursor case.
1858 * If the current line has a linecolor, apply the
1859 * appropriate reverse transformation to show it is current.
1861 if(uc
&& ice
->linecolor
&& ice
->linecolor
->fg
[0]
1862 && ice
->linecolor
->bg
[0] && pico_is_good_colorpair(ice
->linecolor
)){
1863 base_color
= apply_rev_color(ice
->linecolor
,
1864 ps_global
->index_color_style
);
1866 (void)pico_set_colorp(base_color
, PSC_NONE
);
1873 if((rev
= pico_get_rev_color()) != NULL
){
1874 base_color
= new_color_pair(rev
->fg
, rev
->bg
);
1875 (void)pico_set_colorp(base_color
, PSC_NONE
);
1882 else if(uc
&& ice
->linecolor
&& ice
->linecolor
->fg
[0]
1883 && ice
->linecolor
->bg
[0]
1884 && pico_is_good_colorpair(ice
->linecolor
)){
1885 (void)pico_set_colorp(ice
->linecolor
, PSC_NONE
);
1886 base_color
= ice
->linecolor
;
1891 memset(draw
, 0, sizeof(draw
));
1894 doing_bold
= (sel
&& F_ON(F_SELECTED_SHOWN_BOLD
, ps_global
) && StartBold());
1896 /* draw each field */
1897 for(ifield
= ice
->ifield
; ifield
&& p
-draw
< n
; ifield
= ifield
->next
){
1902 * Fix up the data for some special cases.
1905 /* message number string is generated on the fly */
1906 if(ifield
->ctype
== iMessNo
){
1907 ielem
= ifield
->ielem
;
1908 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1909 snprintf(ielem
->data
, ielem
->datalen
+1, "%*.ld", ifield
->width
, msgno
);
1910 ielem
->data
[ifield
->width
] = '\0';
1911 ielem
->data
[ielem
->datalen
] = '\0';
1915 if(ifield
->ctype
== sfld
){
1916 ielem
= ifield
->ielem
;
1917 if(ielem
&& ielem
->datalen
> 0){
1918 if(ielem
->datalen
== 1){
1919 save_schar1
= ielem
->data
[0];
1920 if(sel
&& !doing_bold
){
1921 ielem
->data
[0] = 'X';
1924 else if(ac
&& cur
&& ielem
->data
[0] == ' ')
1925 ielem
->data
[0] = '-';
1927 if(ielem
->next
&& ielem
->next
->datalen
){
1928 save_schar2
= ielem
->next
->data
[0];
1929 if(ac
&& cur
&& ielem
->next
->data
[0] != '\0')
1930 ielem
->next
->data
[0] = '>';
1933 else if(ielem
->datalen
> 1){
1934 if(sel
&& !doing_bold
){
1935 ielem
->data
[0] = 'X';
1938 else if(ac
&& cur
&& ielem
->data
[0] == ' ')
1939 ielem
->data
[0] = '-';
1941 save_schar2
= ielem
->data
[1];
1942 if(ac
&& cur
&& ielem
->data
[1] != '\0')
1943 ielem
->data
[1] = '>';
1947 else if(ifield
->ctype
== afld
&& do_arrow
&& cur
){
1949 ielem
= ifield
->ielem
;
1950 if(ielem
&& ielem
->datalen
>= ifield
->width
){
1951 for(i
= 0; i
< ifield
->width
-1; i
++)
1952 ielem
->data
[i
] = cur
? '-' : ' ';
1954 ielem
->data
[i
] = '>';
1957 else if(ifield
->ctype
== pfld
){
1958 ielem
= ifield
->ielem
;
1959 if(ielem
&& ielem
->datalen
> 0){
1960 save_pchar
= ielem
->data
[0];
1961 ielem
->data
[0] = ice
->plus
;
1965 /* space between fields */
1966 if(ifield
!= ice
->ifield
&& !(previfield
&& previfield
->ctype
== iText
)){
1970 Write_to_screen(" ");
1975 for(ielem
= ifield
->ielem
; ielem
; ielem
= ielem
->next
){
1979 utf8_pad_to_width(draw
, src
, (n
+1) * sizeof(char),
1980 ielem
->wid
, ifield
->leftadj
);
1984 * Switch to color for ielem.
1985 * But don't switch if we drew an X in this column,
1986 * because that overwrites the colored thing, and don't
1987 * switch if this is the ARROW field and this is not
1988 * the current message. ARROW field is only colored for
1989 * the current message.
1990 * And don't switch if current line and type eTypeCol.
1992 if(ielem
->color
&& pico_is_good_colorpair(ielem
->color
)
1993 && !(do_arrow
&& ifield
->ctype
== afld
&& !cur
)
1994 && (!drew_X
|| ielem
!= ifield
->ielem
)
1995 && !(cur
&& ielem
->type
== eTypeCol
)){
1996 need_inverse_hack
= 0;
1997 (void) pico_set_colorp(ielem
->color
, PSC_NORM
);
2000 need_inverse_hack
= 1;
2002 if(need_inverse_hack
&& inverse_hack
)
2005 Write_to_screen(draw
);
2006 if(need_inverse_hack
&& inverse_hack
)
2009 (void) pico_set_colorp(base_color
, PSC_NORM
);
2013 * Restore the data for the special cases.
2016 if(ifield
->ctype
== sfld
){
2017 ielem
= ifield
->ielem
;
2018 if(ielem
&& ielem
->datalen
> 0){
2019 if(ielem
->datalen
== 1){
2020 ielem
->data
[0] = save_schar1
;
2021 if(ielem
->next
&& ielem
->next
->datalen
)
2022 ielem
->next
->data
[0] = save_schar2
;
2024 else if(ielem
->datalen
> 1){
2025 ielem
->data
[0] = save_schar1
;
2026 ielem
->data
[1] = save_schar2
;
2030 else if(ifield
->ctype
== afld
){
2031 ielem
= ifield
->ielem
;
2032 if(ielem
&& ielem
->datalen
>= ifield
->width
)
2033 for(i
= 0; i
< ifield
->width
; i
++)
2034 ielem
->data
[i
] = ' ';
2036 else if(ifield
->ctype
== pfld
){
2037 ielem
= ifield
->ielem
;
2038 if(ielem
&& ielem
->datalen
> 0)
2039 ielem
->data
[0] = save_pchar
;
2042 previfield
= ifield
;
2048 if(base_color
&& base_color
!= lastc
&& base_color
!= ice
->linecolor
)
2049 free_color_pair(&base_color
);
2052 (void)pico_set_colorp(lastc
, PSC_NORM
);
2053 free_color_pair(&lastc
);
2058 entry
->hilite
= cur
;
2059 entry
->bolded
= sel
;
2060 entry
->msgno
= msgno
;
2061 entry
->plus
= ice
->plus
;
2062 entry
->id
= ice
->id
;
2064 if(!ice
->color_lookup_done
&& pico_usingcolor())
2067 return(cur
? (line
+ HEADER_ROWS(ps_global
)) : 0);
2071 * setup_index_state - hooked onto pith_opt_save_index_state to setup
2072 * current_index_state after setup_{index,thread}_header_widths
2075 setup_index_state(int threaded
)
2077 if(current_index_state
){
2079 current_index_state
->status_col
= 0;
2080 current_index_state
->status_fld
= iStatus
;
2081 current_index_state
->plus_fld
= iNothing
;
2082 current_index_state
->arrow_fld
= iNothing
;
2084 INDEX_COL_S
*cdesc
, *prevcdesc
= NULL
;
2085 IndexColType sfld
, altfld
, plusfld
, arrowfld
;
2086 int width
, fld
, col
, pluscol
, scol
, altcol
;
2093 /* figure out which field is status field */
2094 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2095 cdesc
->ctype
!= iNothing
;
2097 width
= cdesc
->width
;
2101 /* space between columns */
2102 if(col
> 0 && !(prevcdesc
&& prevcdesc
->ctype
== iText
))
2105 if(cdesc
->ctype
== iStatus
){
2107 sfld
= cdesc
->ctype
;
2111 if(cdesc
->ctype
== iFStatus
|| cdesc
->ctype
== iIStatus
){
2113 sfld
= cdesc
->ctype
;
2117 if(cdesc
->ctype
== iMessNo
){
2119 altfld
= cdesc
->ctype
;
2127 if(sfld
== iNothing
){
2138 current_index_state
->status_col
= scol
;
2139 current_index_state
->status_fld
= sfld
;
2145 /* figure out which column to use for threading '+' */
2147 && ps_global
->thread_disp_style
!= THREAD_NONE
2148 && ps_global
->VAR_THREAD_MORE_CHAR
[0]
2149 && ps_global
->VAR_THREAD_EXP_CHAR
[0])
2150 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2151 cdesc
->ctype
!= iNothing
;
2153 width
= cdesc
->width
;
2157 /* space between columns */
2158 if(col
> 0 && !(prevcdesc
&& prevcdesc
->ctype
== iText
))
2161 if((cdesc
->ctype
== iSubject
2162 || cdesc
->ctype
== iShortSubject
2163 || cdesc
->ctype
== iSubjectText
2164 || cdesc
->ctype
== iSubjKey
2165 || cdesc
->ctype
== iSubjKeyText
2166 || cdesc
->ctype
== iSubjKeyInit
2167 || cdesc
->ctype
== iSubjKeyInitText
)
2168 && (ps_global
->thread_disp_style
== THREAD_STRUCT
2169 || ps_global
->thread_disp_style
== THREAD_MUTTLIKE
2170 || ps_global
->thread_disp_style
== THREAD_INDENT_SUBJ1
2171 || ps_global
->thread_disp_style
== THREAD_INDENT_SUBJ2
)){
2172 plusfld
= cdesc
->ctype
;
2177 if((cdesc
->ctype
== iFrom
2178 || cdesc
->ctype
== iFromToNotNews
2179 || cdesc
->ctype
== iFromTo
2180 || cdesc
->ctype
== iAddress
2181 || cdesc
->ctype
== iMailbox
)
2182 && (ps_global
->thread_disp_style
== THREAD_INDENT_FROM1
2183 || ps_global
->thread_disp_style
== THREAD_INDENT_FROM2
2184 || ps_global
->thread_disp_style
== THREAD_STRUCT_FROM
)){
2185 plusfld
= cdesc
->ctype
;
2195 current_index_state
->plus_fld
= plusfld
;
2196 current_index_state
->plus_col
= pluscol
;
2198 arrowfld
= iNothing
;
2199 /* figure out which field is arrow field, if any */
2200 for(cdesc
= ps_global
->index_disp_format
, fld
= 0;
2201 cdesc
->ctype
!= iNothing
;
2203 width
= cdesc
->width
;
2207 if(cdesc
->ctype
== iArrow
){
2208 arrowfld
= cdesc
->ctype
;
2215 current_index_state
->arrow_fld
= arrowfld
;
2222 * insert_condensed_thread_cue - used on pith hook to add decoration to
2223 * subject or from text to show condensed thread info
2226 condensed_thread_cue(PINETHRD_S
*thd
, ICE_S
*ice
,
2227 char **fieldstr
, size_t *strsize
, int width
, int collapsed
)
2229 if(current_index_state
->plus_fld
!= iNothing
&& !THRD_INDX() && fieldstr
&& *fieldstr
){
2232 * There is an unwarranted assumption here that VAR_THREAD_MORE_CHAR[0]
2233 * and VAR_THREAD_EXP_CHAR[0] are ascii.
2234 * Could do something similar to the conversions done with keyword
2235 * initials in key_str.
2238 ice
->plus
= collapsed
? ps_global
->VAR_THREAD_MORE_CHAR
[0]
2239 : (thd
&& thd
->next
)
2240 ? ps_global
->VAR_THREAD_EXP_CHAR
[0] : ' ';
2242 if(strsize
&& *strsize
> 0 && width
!= 0){
2243 *(*fieldstr
)++ = ' ';
2249 if(strsize
&& *strsize
> 0 && width
!= 0){
2250 *(*fieldstr
)++ = ' ';
2262 truncate_subj_and_from_strings(void)
2269 * paint_index_hline - paint index line given what we got
2272 paint_index_hline(MAILSTREAM
*stream
, long int msgno
, ICE_S
*ice
)
2277 * Trust only what we get back that isn't bogus since
2278 * we were prevented from doing any fetches and such...
2280 if((ps_global
->redrawer
== redraw_index_body
2281 || ps_global
->prev_screen
== mail_index_screen
)
2282 && current_index_state
2283 && current_index_state
->stream
== stream
2284 && !ps_global
->msgmap
->hilited
){
2288 * This test isn't right if there are hidden lines. The line will
2289 * fail the test because it seems like it is past the end of the
2290 * screen but since the hidden lines don't take up space the line
2291 * might actually be on the screen. Don't know that it is worth
2292 * it to fix this, though, since you may have to file through
2293 * many hidden lines before finding the visible ones. I'm not sure
2294 * if the logic inside the if is correct when we do pass the
2295 * top-level test. Leave it for now. Hubert - 2002-06-28
2297 if((line
= (int)(msgno
- current_index_state
->msg_at_top
)) >= 0
2298 && line
< current_index_state
->lines_per_page
){
2299 if(any_lflagged(ps_global
->msgmap
, MN_HIDE
| MN_CHID
)){
2301 long zoomhide
, collapsehide
;
2303 zoomhide
= any_lflagged(ps_global
->msgmap
, MN_HIDE
);
2304 collapsehide
= any_lflagged(ps_global
->msgmap
, MN_CHID
);
2307 * Line is visible if it is selected and not hidden due to
2308 * thread collapse, or if there is no zooming happening and
2309 * it is not hidden due to thread collapse.
2311 for(line
= 0, n
= current_index_state
->msg_at_top
;
2315 && get_lflag(stream
, current_index_state
->msgmap
,
2318 || !get_lflag(stream
, current_index_state
->msgmap
, n
,
2322 && !get_lflag(stream
, current_index_state
->msgmap
,
2329 unsigned long rawno
;
2331 rawno
= mn_m2raw(current_index_state
->msgmap
, msgno
);
2333 thrd
= fetch_thread(stream
, rawno
);
2336 paint_index_line(ice
, line
,
2337 (THRD_INDX() && thrd
) ? thrd
->thrdno
: msgno
,
2338 current_index_state
->status_fld
,
2339 current_index_state
->plus_fld
,
2340 current_index_state
->arrow_fld
,
2341 ¤t_index_state
->entry_state
[line
],
2342 mn_is_cur(current_index_state
->msgmap
, msgno
),
2344 ? (count_lflags_in_thread(stream
, thrd
,
2345 current_index_state
->msgmap
,
2347 : get_lflag(stream
, current_index_state
->msgmap
,
2358 * pine_imap_env -- C-client's telling us an envelope just arrived
2359 * from the server. Use it if we can...
2362 pine_imap_envelope(MAILSTREAM
*stream
, long unsigned int rawno
, ENVELOPE
*env
)
2366 dprint((7, "imap_env(%ld)\n", rawno
));
2367 if(stream
&& !sp_mail_box_changed(stream
)
2368 && stream
== ps_global
->mail_stream
2369 && rawno
> 0L && rawno
<= stream
->nmsgs
2370 && (mc
= mail_elt(stream
,rawno
))
2373 && !get_lflag(stream
, NULL
, rawno
, MN_HIDE
| MN_CHID
| MN_EXLD
)){
2377 memset(&idata
, 0, sizeof(INDEXDATA_S
));
2379 idata
.size
= mc
->rfc822_size
;
2380 idata
.rawno
= rawno
;
2381 idata
.msgno
= mn_raw2m(sp_msgmap(stream
), rawno
);
2382 idata
.stream
= stream
;
2384 index_data_env(&idata
, env
);
2387 * Look for resent-to already in MAILCACHE data
2389 if(mc
->private.msg
.header
.text
.data
){
2392 static char *linelist
[] = {"resent-to" , NULL
};
2394 if(mail_match_lines(lines
= new_strlst(linelist
),
2395 mc
->private.msg
.lines
, 0L)){
2396 idata
.valid_resent_to
= 1;
2397 memset(&szt
, 0, sizeof(SIZEDTEXT
));
2398 textcpy(&szt
, &mc
->private.msg
.header
.text
);
2399 mail_filter((char *) szt
.data
, szt
.size
, lines
, 0L);
2400 idata
.resent_to_us
= parsed_resent_to_us((char *) szt
.data
);
2402 fs_give((void **) &szt
.data
);
2405 free_strlst(&lines
);
2408 ice
= (*format_index_line
)(&idata
);
2412 paint_index_hline(stream
, idata
.msgno
, ice
);
2417 /*----------------------------------------------------------------------
2418 Scroll to specified postion.
2421 Args: pos - position to scroll to.
2423 Returns: TRUE - did the scroll operation.
2424 FALSE - was not able to do the scroll operation.
2427 index_scroll_to_pos (long int pos
)
2429 static short bad_timing
= 0;
2436 * Put the requested line at the top of the screen...
2440 * Starting at msg 'pos' find next visible message.
2442 for(i
=pos
; i
<= mn_get_total(current_index_state
->msgmap
); i
++) {
2443 if(!msgline_hidden(current_index_state
->stream
,
2444 current_index_state
->msgmap
, i
, 0)){
2445 current_index_state
->msg_at_top
= i
;
2451 * If single selection, move selected message to be on the screen.
2453 if (mn_total_cur(current_index_state
->msgmap
) == 1L) {
2454 if (current_index_state
->msg_at_top
>
2455 mn_get_cur (current_index_state
->msgmap
)) {
2456 /* Selection was above screen, move to top of screen. */
2457 mn_set_cur(current_index_state
->msgmap
,current_index_state
->msg_at_top
);
2460 /* Scan through the screen. If selection found, leave where is.
2461 * Otherwise, move to end of screen */
2462 for( i
= current_index_state
->msg_at_top
,
2463 j
= current_index_state
->lines_per_page
;
2464 i
!= mn_get_cur(current_index_state
->msgmap
) &&
2465 i
<= mn_get_total(current_index_state
->msgmap
) &&
2468 if(!msgline_hidden(current_index_state
->stream
,
2469 current_index_state
->msgmap
, i
, 0)){
2475 /* Move to end of screen. */
2476 mn_set_cur(current_index_state
->msgmap
, k
);
2486 /*----------------------------------------------------------------------
2487 Adjust the index display state down a line
2489 Args: scroll_count -- number of lines to scroll
2491 Returns: TRUE - did the scroll operation.
2492 FALSE - was not able to do the scroll operation.
2495 index_scroll_down(long int scroll_count
)
2497 static short bad_timing
= 0;
2508 total
= mn_get_total (current_index_state
->msgmap
);
2509 for(k
= i
= current_index_state
->msg_at_top
; ; i
++){
2511 /* Only examine non-hidden messages. */
2512 if(!msgline_hidden(current_index_state
->stream
,
2513 current_index_state
->msgmap
, i
, 0)){
2514 /* Remember this message */
2516 /* Increment count of lines. */
2517 if (++j
>= scroll_count
) {
2518 /* Counted enough lines, stop. */
2519 current_index_state
->msg_at_top
= k
;
2524 /* If at last message, stop. */
2526 current_index_state
->msg_at_top
= k
;
2532 * If not multiple selection, see if selected message visable. if not
2533 * set it to last visable message.
2535 if(mn_total_cur(current_index_state
->msgmap
) == 1L) {
2537 cur
= mn_get_cur (current_index_state
->msgmap
);
2538 for (i
= current_index_state
->msg_at_top
; i
<= total
; ++i
) {
2539 if(!msgline_hidden(current_index_state
->stream
,
2540 current_index_state
->msgmap
, i
, 0)){
2541 if (++j
>= current_index_state
->lines_per_page
) {
2549 mn_set_cur(current_index_state
->msgmap
,
2550 current_index_state
->msg_at_top
);
2559 /*----------------------------------------------------------------------
2560 Adjust the index display state up a line
2562 Args: scroll_count -- number of lines to scroll
2564 Returns: TRUE - did the scroll operation.
2565 FALSE - was not able to do the scroll operation.
2569 index_scroll_up(long int scroll_count
)
2571 static short bad_timing
= 0;
2581 for(k
= i
= current_index_state
->msg_at_top
; ; i
--){
2583 /* Only examine non-hidden messages. */
2584 if(!msgline_hidden(current_index_state
->stream
,
2585 current_index_state
->msgmap
, i
, 0)){
2586 /* Remember this message */
2588 /* Increment count of lines. */
2589 if (++j
>= scroll_count
) {
2590 /* Counted enough lines, stop. */
2591 current_index_state
->msg_at_top
= k
;
2596 /* If at first message, stop */
2598 current_index_state
->msg_at_top
= k
;
2605 * If not multiple selection, see if selected message visable. if not
2606 * set it to last visable message.
2608 if(mn_total_cur(current_index_state
->msgmap
) == 1L) {
2610 cur
= mn_get_cur (current_index_state
->msgmap
);
2611 for ( i
= current_index_state
->msg_at_top
;
2612 i
<= mn_get_total(current_index_state
->msgmap
);
2614 if(!msgline_hidden(current_index_state
->stream
,
2615 current_index_state
->msgmap
, i
, 0)){
2616 if (++j
>= current_index_state
->lines_per_page
) {
2625 mn_set_cur(current_index_state
->msgmap
, k
);
2635 /*----------------------------------------------------------------------
2636 Calculate the message number that should be at the top of the display
2638 Args: current - the current message number
2639 lines_per_page - the number of lines for the body of the index only
2641 Returns: -1 if the current message is -1
2642 the message entry for the first message at the top of the screen.
2644 When paging in the index it is always on even page boundies, and the
2645 current message is always on the page thus the top of the page is
2646 completely determined by the current message and the number of lines
2650 top_ent_calc(MAILSTREAM
*stream
, MSGNO_S
*msgs
, long int at_top
, long int lines_per_page
)
2652 long current
, hidden
, lastn
;
2653 long n
, m
= 0L, t
= 1L;
2655 current
= (mn_total_cur(msgs
) <= 1L) ? mn_get_cur(msgs
) : at_top
;
2660 if(lines_per_page
== 0L)
2663 if(THRD_INDX_ENABLED()){
2665 PINETHRD_S
*thrd
= NULL
;
2667 rawno
= mn_m2raw(msgs
, mn_get_cur(msgs
));
2669 thrd
= fetch_thread(stream
, rawno
);
2673 if(any_lflagged(msgs
, MN_HIDE
)){
2674 PINETHRD_S
*is_current_thrd
;
2676 is_current_thrd
= thrd
;
2677 if(is_current_thrd
){
2678 if(mn_get_revsort(msgs
)){
2679 /* start with top of tail of thread list */
2680 thrd
= fetch_thread(stream
, mn_m2raw(msgs
, 1L));
2681 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
2682 thrd
= fetch_thread(stream
, thrd
->top
);
2685 /* start with head of thread list */
2686 thrd
= fetch_head_thread(stream
);
2692 n
= mn_raw2m(msgs
, thrd
->rawno
);
2695 if(!msgline_hidden(stream
, msgs
, n
, 0)
2696 && (++m
% lines_per_page
) == 1L)
2699 if(thrd
== is_current_thrd
)
2702 if(mn_get_revsort(msgs
) && thrd
->prevthd
)
2703 thrd
= fetch_thread(stream
, thrd
->prevthd
);
2704 else if(!mn_get_revsort(msgs
) && thrd
->nextthd
)
2705 thrd
= fetch_thread(stream
, thrd
->nextthd
);
2710 n
= mn_raw2m(msgs
, thrd
->rawno
);
2717 m
= lines_per_page
* ((n
- 1L)/ lines_per_page
) + 1L;
2720 * We want to find the m'th thread and the
2721 * message number that goes with that. We just have
2722 * to back up from where we are to get there.
2723 * If we have a reverse sort backing up is going
2724 * forward through the thread.
2726 while(thrd
&& m
< thrd
->thrdno
){
2728 if(mn_get_revsort(msgs
) && thrd
->nextthd
)
2729 thrd
= fetch_thread(stream
, thrd
->nextthd
);
2730 else if(!mn_get_revsort(msgs
) && thrd
->prevthd
)
2731 thrd
= fetch_thread(stream
, thrd
->prevthd
);
2739 t
= mn_raw2m(msgs
, n
);
2743 else{ /* viewing a thread */
2745 lastn
= mn_get_total(msgs
);
2748 /* get top of thread */
2749 if(thrd
&& thrd
->top
&& thrd
->top
!= thrd
->rawno
)
2750 thrd
= fetch_thread(stream
, thrd
->top
);
2753 if(mn_get_revsort(msgs
))
2754 lastn
= mn_raw2m(msgs
, thrd
->rawno
);
2756 t
= mn_raw2m(msgs
, thrd
->rawno
);
2761 /* n is the end of this thread */
2763 n
= mn_raw2m(msgs
, thrd
->rawno
);
2765 thrd
= fetch_thread(stream
, thrd
->branch
);
2767 thrd
= fetch_thread(stream
, thrd
->next
);
2773 if(mn_get_revsort(msgs
))
2779 for(m
= 0L, n
= t
; n
<= MIN(current
, lastn
); n
++)
2780 if(!msgline_hidden(stream
, msgs
, n
, 0)
2781 && (++m
% lines_per_page
) == 1L)
2787 else if((hidden
= any_lflagged(msgs
, MN_HIDE
| MN_CHID
)) != 0){
2789 if(current
< mn_get_total(msgs
) / 2){
2792 for(n
= 1L; n
<= MIN(current
, mn_get_total(msgs
)); n
++)
2793 if(!msgline_hidden(stream
, msgs
, n
, 0)
2794 && (++m
% lines_per_page
) == 1L)
2799 m
= mn_get_total(msgs
)-hidden
+1L;
2800 for(n
= mn_get_total(msgs
); n
>= 1L && t
> current
; n
--)
2801 if(!msgline_hidden(stream
, msgs
, n
, 0)
2802 && (--m
% lines_per_page
) == 1L)
2812 return(lines_per_page
* ((current
- 1L)/ lines_per_page
) + 1L);
2816 /*----------------------------------------------------------------------
2817 Clear various bits that make up a healthy display
2821 reset_index_border(void)
2823 mark_status_dirty();
2824 mark_keymenu_dirty();
2825 mark_titlebar_dirty();
2826 ps_global
->mangled_screen
= 1; /* signal FULL repaint */
2830 /*----------------------------------------------------------------------
2831 This redraws the body of the index screen, taking into
2832 account any change in the size of the screen. All the state needed to
2833 repaint is in the static variables so this can be called from
2837 redraw_index_body(void)
2841 if((agg
= (mn_total_cur(current_index_state
->msgmap
) > 1L)) != 0)
2842 restore_selected(current_index_state
->msgmap
);
2844 ps_global
->mangled_body
= 1;
2846 (void) update_index(ps_global
, current_index_state
);
2848 pseudo_selected(current_index_state
->stream
, current_index_state
->msgmap
);
2852 /*----------------------------------------------------------------------
2853 Give hint about Other command being optional. Some people get the idea
2854 that it is required to use the commands on the 2nd and 3rd keymenus.
2858 Result: message may be printed to status line
2861 warn_other_cmds(void)
2863 static int other_cmds
= 0;
2866 if(((ps_global
->first_time_user
|| ps_global
->show_new_version
) &&
2867 other_cmds
% 3 == 0 && other_cmds
< 10) || other_cmds
% 20 == 0)
2868 q_status_message(SM_ASYNC
, 0, 9,
2869 _("Remember the \"O\" command is always optional"));
2874 thread_command(struct pine
*state
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
,
2875 UCS preloadkeystroke
, int q_line
)
2877 PINETHRD_S
*thrd
= NULL
;
2878 unsigned long rawno
, save_branch
;
2880 int flags
= AC_FROM_THREAD
;
2882 if(!(stream
&& msgmap
))
2885 rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
));
2887 thrd
= fetch_thread(stream
, rawno
);
2892 save_branch
= thrd
->branch
;
2893 thrd
->branch
= 0L; /* branch is a sibling, not part of thread */
2895 if(!preloadkeystroke
){
2897 if(get_lflag(stream
, NULL
, rawno
, MN_COLL
) && thrd
->next
)
2903 if(count_lflags_in_thread(stream
, thrd
, msgmap
, MN_SLCT
)
2904 == count_lflags_in_thread(stream
, thrd
, msgmap
, MN_NONE
))
2908 we_cancel
= busy_cue(NULL
, NULL
, 1);
2910 /* save the SLCT flags in STMP for restoring at the bottom */
2911 copy_lflags(stream
, msgmap
, MN_SLCT
, MN_STMP
);
2913 /* clear the values from the SLCT flags */
2914 set_lflags(stream
, msgmap
, MN_SLCT
, 0);
2916 /* set SLCT for thrd on down */
2917 set_flags_for_thread(stream
, msgmap
, MN_SLCT
, thrd
, 1);
2918 thrd
->branch
= save_branch
;
2923 (void ) apply_command(state
, stream
, msgmap
, preloadkeystroke
, flags
,
2926 /* restore the original flags */
2927 copy_lflags(stream
, msgmap
, MN_STMP
, MN_SLCT
);
2929 if(any_lflagged(msgmap
, MN_HIDE
) > 0L){
2930 /* if nothing left selected, unhide all */
2931 if(any_lflagged(msgmap
, MN_SLCT
) == 0L){
2932 (void) unzoom_index(ps_global
, stream
, msgmap
);
2933 dprint((4, "\n\n ---- Exiting ZOOM mode ----\n"));
2934 q_status_message(SM_ORDER
,0,2, _("Index Zoom Mode is now off"));
2937 /* if current is hidden, adjust */
2938 adjust_cur_to_visible(stream
, msgmap
);
2943 /*----------------------------------------------------------------------
2944 Search the message headers as displayed in index
2946 Args: command_line -- The screen line to prompt on
2947 msg -- The current message number to start searching at
2948 max_msg -- The largest message number in the current folder
2950 The headers are searched exactly as they are displayed on the screen. The
2951 search will wrap around to the beginning if not string is not found right
2955 index_search(struct pine
*state
, MAILSTREAM
*stream
, int command_line
, MSGNO_S
*msgmap
)
2957 int rc
, select_all
= 0, flags
, prefetch
, we_turned_on
= 0;
2958 long i
, sorted_msg
, selected
= 0L;
2959 char prompt
[MAX_SEARCH
+50], new_string
[MAX_SEARCH
+1];
2960 char buf
[MAX_SCREEN_COLS
+1], *p
;
2962 char search_string
[MAX_SEARCH
+1];
2964 static HISTORY_S
*history
= NULL
;
2965 static ESCKEY_S header_search_key
[] = { {0, 0, NULL
, NULL
},
2966 {ctrl('Y'), 10, "^Y", N_("First Msg")},
2967 {ctrl('V'), 11, "^V", N_("Last Msg")},
2968 {KEY_UP
, 30, "", ""},
2969 {KEY_DOWN
, 31, "", ""},
2970 {-1, 0, NULL
, NULL
} };
2971 #define KU_IS (3) /* index of KEY_UP */
2972 #define PREFETCH_THIS_MANY_LINES (50)
2974 init_hist(&history
, HISTSIZE
);
2975 search_string
[0] = '\0';
2976 if((p
= get_prev_hist(history
, "", 0, NULL
)) != NULL
){
2977 strncpy(search_string
, p
, sizeof(search_string
));
2978 search_string
[sizeof(search_string
)-1] = '\0';
2981 dprint((4, "\n - search headers - \n"));
2983 if(!any_messages(msgmap
, NULL
, "to search")){
2986 else if(mn_total_cur(msgmap
) > 1L){
2987 q_status_message1(SM_ORDER
, 0, 2, "%s msgs selected; Can't search",
2988 comatose(mn_total_cur(msgmap
)));
2992 sorted_msg
= mn_get_cur(msgmap
);
2995 new_string
[0] = '\0';
2998 snprintf(prompt
, sizeof(prompt
), _("Word to search for [%s] : "), search_string
);
3000 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
3001 header_search_key
[0].ch
= ctrl('X');
3002 header_search_key
[0].rval
= 12;
3003 header_search_key
[0].name
= "^X";
3004 header_search_key
[0].label
= N_("Select Matches");
3007 header_search_key
[0].ch
= header_search_key
[0].rval
= 0;
3008 header_search_key
[0].name
= header_search_key
[0].label
= NULL
;
3012 * 2 is really 1 because there will be one real entry and
3013 * one entry of "" because of the get_prev_hist above.
3015 if(items_in_hist(history
) > 2){
3016 header_search_key
[KU_IS
].name
= HISTORY_UP_KEYNAME
;
3017 header_search_key
[KU_IS
].label
= HISTORY_KEYLABEL
;
3018 header_search_key
[KU_IS
+1].name
= HISTORY_DOWN_KEYNAME
;
3019 header_search_key
[KU_IS
+1].label
= HISTORY_KEYLABEL
;
3022 header_search_key
[KU_IS
].name
= "";
3023 header_search_key
[KU_IS
].label
= "";
3024 header_search_key
[KU_IS
+1].name
= "";
3025 header_search_key
[KU_IS
+1].label
= "";
3028 flags
= OE_APPEND_CURRENT
| OE_KEEP_TRAILING_SPACE
;
3030 rc
= optionally_enter(new_string
, command_line
, 0, sizeof(new_string
),
3031 prompt
, header_search_key
, help
, &flags
);
3034 help
= (help
!= NO_HELP
) ? NO_HELP
:
3035 F_ON(F_ENABLE_AGG_OPS
, ps_global
) ? h_os_index_whereis_agg
3036 : h_os_index_whereis
;
3040 q_status_message(SM_ORDER
, 0, 3, _("Searched to First Message."));
3041 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
3043 selected
= sorted_msg
;
3044 mn_dec_cur(stream
, msgmap
, MH_NONE
);
3045 sorted_msg
= mn_get_cur(msgmap
);
3047 while(selected
!= sorted_msg
);
3050 sorted_msg
= (mn_get_total(msgmap
) > 0L) ? 1L : 0L;
3052 mn_set_cur(msgmap
, sorted_msg
);
3056 q_status_message(SM_ORDER
, 0, 3, _("Searched to Last Message."));
3057 if(any_lflagged(msgmap
, MN_HIDE
| MN_CHID
)){
3059 selected
= sorted_msg
;
3060 mn_inc_cur(stream
, msgmap
, MH_NONE
);
3061 sorted_msg
= mn_get_cur(msgmap
);
3063 while(selected
!= sorted_msg
);
3066 sorted_msg
= mn_get_total(msgmap
);
3068 mn_set_cur(msgmap
, sorted_msg
);
3076 if((p
= get_prev_hist(history
, new_string
, 0, NULL
)) != NULL
){
3077 strncpy(new_string
, p
, sizeof(new_string
));
3078 new_string
[sizeof(new_string
)-1] = '\0';
3086 if((p
= get_next_hist(history
, new_string
, 0, NULL
)) != NULL
){
3087 strncpy(new_string
, p
, sizeof(new_string
));
3088 new_string
[sizeof(new_string
)-1] = '\0';
3096 if(rc
!= 4){ /* 4 is redraw */
3097 save_hist(history
, new_string
, 0, NULL
);
3102 if(rc
== 1 || (new_string
[0] == '\0' && search_string
[0] == '\0')) {
3103 cmd_cancelled(_("Search"));
3107 if(new_string
[0] == '\0'){
3108 strncpy(new_string
, search_string
, sizeof(new_string
));
3109 new_string
[sizeof(new_string
)-1] = '\0';
3112 strncpy(search_string
, new_string
, sizeof(search_string
));
3113 search_string
[sizeof(search_string
)-1] = '\0';
3115 we_turned_on
= intr_handling_on();
3118 for(i
= sorted_msg
+ ((select_all
)?0:1);
3119 i
<= mn_get_total(msgmap
) && !ps_global
->intr_pending
;
3121 if(msgline_hidden(stream
, msgmap
, i
, 0))
3125 prefetch
= PREFETCH_THIS_MANY_LINES
;
3127 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, prefetch
--, NULL
);
3129 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3131 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3135 set_lflag(stream
, msgmap
, i
, MN_SLCT
, 1);
3142 if(i
> mn_get_total(msgmap
)){
3143 for(i
= 1; i
< sorted_msg
&& !ps_global
->intr_pending
; i
++){
3144 if(msgline_hidden(stream
, msgmap
, i
, 0))
3148 prefetch
= PREFETCH_THIS_MANY_LINES
;
3150 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, prefetch
--, NULL
);
3152 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3154 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3158 set_lflag(stream
, msgmap
, i
, MN_SLCT
, 1);
3165 /* search current line */
3166 if(!select_all
&& !selected
){
3168 if(!msgline_hidden(stream
, msgmap
, i
, 0)){
3170 ic
= build_header_work(state
, stream
, msgmap
, i
, i
, 1, NULL
);
3172 ice
= (ic
&& THRD_INDX() && ic
->tice
) ? ic
->tice
: ic
;
3174 if(srchstr(simple_index_line(buf
, sizeof(buf
), ice
, i
),
3181 if(ps_global
->intr_pending
){
3182 q_status_message1(SM_ORDER
, 0, 3, _("Search cancelled.%s"),
3183 select_all
? _(" Selected set may be incomplete."):"");
3185 else if(select_all
){
3187 && any_lflagged(msgmap
, MN_SLCT
) > 0L
3188 && !any_lflagged(msgmap
, MN_HIDE
)
3189 && F_ON(F_AUTO_ZOOM
, state
))
3190 (void) zoom_index(state
, stream
, msgmap
, MN_SLCT
);
3192 q_status_message1(SM_ORDER
, 0, 3, _("%s messages found matching word"),
3193 long2string(selected
));
3196 q_status_message1(SM_ORDER
, 0, 3, _("Word found%s"),
3197 (i
< sorted_msg
) ? _(". Search wrapped to beginning") :
3198 (i
== sorted_msg
) ? _(". Current line contains only match") : "");
3199 mn_set_cur(msgmap
, i
);
3202 q_status_message(SM_ORDER
, 0, 3, _("Word not found"));
3205 intr_handling_off();
3210 * Original idea from Stephen Casner <casner@acm.org>.
3212 * Apply the appropriate reverse color transformation to the given
3213 * color pair and return a new color pair. The caller should free the
3218 apply_rev_color(COLOR_PAIR
*cp
, int style
)
3220 COLOR_PAIR
*rc
= pico_get_rev_color();
3223 if(style
== IND_COL_REV
){
3224 /* just use Reverse color regardless */
3225 return(new_color_pair(rc
->fg
, rc
->bg
));
3227 else if(style
== IND_COL_FG
){
3229 * If changing to Rev fg is readable and different
3230 * from what it already is, do it.
3232 if(strcmp(rc
->fg
, cp
->bg
) && strcmp(rc
->fg
, cp
->fg
))
3233 return(new_color_pair(rc
->fg
, cp
->bg
));
3235 else if(style
== IND_COL_BG
){
3237 * If changing to Rev bg is readable and different
3238 * from what it already is, do it.
3240 if(strcmp(rc
->bg
, cp
->fg
) && strcmp(rc
->bg
, cp
->bg
))
3241 return(new_color_pair(cp
->fg
, rc
->bg
));
3243 else if(style
== IND_COL_FG_NOAMBIG
){
3245 * If changing to Rev fg is readable, different
3246 * from what it already is, and not the same as
3247 * the Rev color, do it.
3249 if(strcmp(rc
->fg
, cp
->bg
) && strcmp(rc
->fg
, cp
->fg
) &&
3250 strcmp(rc
->bg
, cp
->bg
))
3251 return(new_color_pair(rc
->fg
, cp
->bg
));
3253 else if(style
== IND_COL_BG_NOAMBIG
){
3255 * If changing to Rev bg is readable, different
3256 * from what it already is, and not the same as
3257 * the Rev color, do it.
3259 if(strcmp(rc
->bg
, cp
->fg
) && strcmp(rc
->bg
, cp
->bg
) &&
3260 strcmp(rc
->fg
, cp
->fg
))
3261 return(new_color_pair(cp
->fg
, rc
->bg
));
3265 /* come here for IND_COL_FLIP and for the cases which fail the tests */
3266 return(new_color_pair(cp
->bg
, cp
->fg
)); /* flip the colors */
3273 /*----------------------------------------------------------------------
3274 Callback to get the text of the current message. Used to display
3275 a message in an alternate window.
3277 Args: cmd - what type of scroll operation.
3278 text - filled with pointer to text.
3280 style - Returns style of text. Can be:
3281 GETTEXT_TEXT - Is a pointer to text with CRLF deliminated
3283 GETTEXT_LINES - Is a pointer to NULL terminated array of
3284 char *. Each entry points to a line of
3287 this implementation always returns GETTEXT_TEXT.
3289 Returns: TRUE - did the scroll operation.
3290 FALSE - was not able to do the scroll operation.
3293 index_scroll_callback (cmd
, scroll_pos
)
3300 case MSWIN_KEY_SCROLLUPLINE
:
3301 paint
= index_scroll_up (scroll_pos
);
3304 case MSWIN_KEY_SCROLLDOWNLINE
:
3305 paint
= index_scroll_down (scroll_pos
);
3308 case MSWIN_KEY_SCROLLUPPAGE
:
3309 paint
= index_scroll_up (current_index_state
->lines_per_page
);
3312 case MSWIN_KEY_SCROLLDOWNPAGE
:
3313 paint
= index_scroll_down (current_index_state
->lines_per_page
);
3316 case MSWIN_KEY_SCROLLTO
:
3317 /* Normalize msgno in zoomed case */
3318 if(any_lflagged(ps_global
->msgmap
, MN_HIDE
| MN_CHID
)){
3322 x
< scroll_pos
&& n
< mn_get_total(ps_global
->msgmap
);
3324 if(!msgline_hidden(ps_global
->mail_stream
, ps_global
->msgmap
,
3328 scroll_pos
= n
- 1; /* list-position --> message number */
3331 paint
= index_scroll_to_pos (scroll_pos
+ 1);
3336 mswin_beginupdate();
3337 update_titlebar_message();
3338 update_titlebar_status();
3339 redraw_index_body();
3347 /*----------------------------------------------------------------------
3348 MSWin scroll callback to get the text of the current message
3350 Args: title - title for new window
3355 Returns: TRUE - got the requested text
3356 FALSE - was not able to get the requested text
3359 index_gettext_callback(title
, titlelen
, text
, l
, style
)
3372 if(mn_get_total(ps_global
->msgmap
) > 0L
3373 && (so
= so_get(CharStar
, NULL
, WRITE_ACCESS
))){
3374 gf_set_so_writec(&pc
, so
);
3376 if((env
= pine_mail_fetchstructure(ps_global
->mail_stream
,
3377 mn_m2raw(ps_global
->msgmap
,
3378 mn_get_cur(ps_global
->msgmap
)),
3380 && format_message(mn_m2raw(ps_global
->msgmap
,
3381 mn_get_cur(ps_global
->msgmap
)),
3382 env
, body
, NULL
, FM_NEW_MESS
, pc
)){
3383 snprintf(title
, titlelen
, "Folder %s -- Message %ld of %ld",
3384 strsquish(tmp_20k_buf
+ 500, SIZEOF_20KBUF
-500, ps_global
->cur_folder
, 50),
3385 mn_get_cur(ps_global
->msgmap
),
3386 mn_get_total(ps_global
->msgmap
));
3387 title
[titlelen
-1] = '\0';
3388 *text
= so_text(so
);
3389 *l
= strlen((char *)so_text(so
));
3390 *style
= GETTEXT_TEXT
;
3392 /* free alloc'd so, but preserve the text passed back to caller */
3393 so
->txt
= (void *) NULL
;
3397 gf_clear_so_writec(so
);
3409 index_sort_callback(set
, order
)
3416 sort_folder(ps_global
->mail_stream
, ps_global
->msgmap
,
3418 (order
& 0x00000100) != 0, SRT_VRB
);
3419 mswin_beginupdate();
3420 update_titlebar_message();
3421 update_titlebar_status();
3422 redraw_index_body();
3424 flush_status_messages(1);
3427 i
= (int) mn_get_sort(ps_global
->msgmap
);
3428 if(mn_get_revsort(ps_global
->msgmap
))
3440 index_popup(IndexType style
, MAILSTREAM
*stream
, MSGNO_S
*msgmap
, int full
)
3443 int view_in_new_wind_index
= -1;
3446 MPopup view_index_popup
[32];
3447 struct key_menu
*km
= (style
== ThreadIndex
)
3449 : (ps_global
->mail_stream
!= stream
)
3450 ? &simple_index_keymenu
3454 * Loosely follow the logic in do_index_border to figure
3455 * out which commands to show.
3459 if(km
!= &simple_index_keymenu
){
3460 view_index_popup
[n
].type
= tQueue
;
3461 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3462 ? "&View Thread" : "&View";
3463 view_index_popup
[n
].label
.style
= lNormal
;
3464 view_index_popup
[n
++].data
.val
= 'V';
3467 if(km
== &index_keymenu
){
3468 view_in_new_wind_index
= n
;
3469 view_index_popup
[n
].type
= tIndex
;
3470 view_index_popup
[n
].label
.style
= lNormal
;
3471 view_index_popup
[n
++].label
.string
= "View in New Window";
3474 if(km
!= &simple_index_keymenu
)
3475 view_index_popup
[n
++].type
= tSeparator
;
3477 if(km
== &thread_keymenu
){
3478 view_index_popup
[n
].type
= tQueue
;
3479 view_index_popup
[n
].label
.string
= "&Delete Thread";
3480 view_index_popup
[n
].label
.style
= lNormal
;
3481 view_index_popup
[n
++].data
.val
= 'D';
3483 view_index_popup
[n
].type
= tQueue
;
3484 view_index_popup
[n
].label
.string
= "&UnDelete Thread";
3485 view_index_popup
[n
].label
.style
= lNormal
;
3486 view_index_popup
[n
++].data
.val
= 'U';
3489 /* Make "delete/undelete" item sensitive */
3490 mc
= ((rawno
= mn_m2raw(msgmap
, mn_get_cur(msgmap
))) > 0L
3491 && stream
&& rawno
<= stream
->nmsgs
)
3492 ? mail_elt(stream
, rawno
) : NULL
;
3493 view_index_popup
[n
].type
= tQueue
;
3494 view_index_popup
[n
].label
.style
= lNormal
;
3495 if(mc
&& mc
->deleted
){
3496 view_index_popup
[n
].label
.string
= "&Undelete";
3497 view_index_popup
[n
++].data
.val
= 'U';
3500 view_index_popup
[n
].label
.string
= "&Delete";
3501 view_index_popup
[n
++].data
.val
= 'D';
3505 if(km
== &index_keymenu
&& F_ON(F_ENABLE_FLAG
, ps_global
)){
3506 view_index_popup
[n
].type
= tSubMenu
;
3507 view_index_popup
[n
].label
.string
= "Flag";
3508 view_index_popup
[n
++].data
.submenu
= flag_submenu(mc
);
3511 if(km
== &simple_index_keymenu
){
3512 view_index_popup
[n
].type
= tQueue
;
3513 view_index_popup
[n
].label
.style
= lNormal
;
3514 view_index_popup
[n
].label
.string
= "&Select";
3515 view_index_popup
[n
++].data
.val
= 'S';
3518 view_index_popup
[n
].type
= tQueue
;
3519 view_index_popup
[n
].label
.style
= lNormal
;
3520 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3521 ? "&Save Thread" : "&Save";
3522 view_index_popup
[n
++].data
.val
= 'S';
3524 view_index_popup
[n
].type
= tQueue
;
3525 view_index_popup
[n
].label
.style
= lNormal
;
3526 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3527 ? "&Export Thread" : "&Export";
3528 view_index_popup
[n
++].data
.val
= 'E';
3530 view_index_popup
[n
].type
= tQueue
;
3531 view_index_popup
[n
].label
.style
= lNormal
;
3532 view_index_popup
[n
].label
.string
= "Print";
3533 view_index_popup
[n
++].data
.val
= '%';
3535 view_index_popup
[n
].type
= tQueue
;
3536 view_index_popup
[n
].label
.style
= lNormal
;
3537 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3538 ? "&Reply To Thread" : "&Reply";
3539 view_index_popup
[n
++].data
.val
= 'R';
3541 view_index_popup
[n
].type
= tQueue
;
3542 view_index_popup
[n
].label
.style
= lNormal
;
3543 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3544 ? "&Forward Thread" : "&Forward";
3545 view_index_popup
[n
++].data
.val
= 'F';
3547 if(F_ON(F_ENABLE_BOUNCE
, ps_global
)){
3548 view_index_popup
[n
].type
= tQueue
;
3549 view_index_popup
[n
].label
.style
= lNormal
;
3550 view_index_popup
[n
].label
.string
= (km
== &thread_keymenu
)
3551 ? "&Bounce Thread" : "&Bounce";
3552 view_index_popup
[n
++].data
.val
= 'B';
3555 view_index_popup
[n
].type
= tQueue
;
3556 view_index_popup
[n
].label
.style
= lNormal
;
3557 view_index_popup
[n
].label
.string
= "&Take Addresses";
3558 view_index_popup
[n
++].data
.val
= 'T';
3560 if(F_ON(F_ENABLE_AGG_OPS
, ps_global
)){
3561 view_index_popup
[n
].type
= tQueue
;
3562 view_index_popup
[n
].label
.style
= lNormal
;
3563 view_index_popup
[n
].label
.string
= "[Un]Select Current";
3564 view_index_popup
[n
++].data
.val
= ':';
3568 view_index_popup
[n
].type
= tQueue
;
3569 view_index_popup
[n
].label
.style
= lNormal
;
3570 view_index_popup
[n
].label
.string
= "&WhereIs";
3571 view_index_popup
[n
++].data
.val
= 'W';
3573 view_index_popup
[n
++].type
= tSeparator
;
3576 if(km
== &simple_index_keymenu
){
3577 view_index_popup
[n
].type
= tQueue
;
3578 view_index_popup
[n
].label
.style
= lNormal
;
3579 view_index_popup
[n
].label
.string
= "&Exit Select";
3580 view_index_popup
[n
++].data
.val
= 'E';
3582 else if(km
== &index_keymenu
&& THREADING() && sp_viewing_a_thread(stream
)){
3583 view_index_popup
[n
].type
= tQueue
;
3584 view_index_popup
[n
].label
.style
= lNormal
;
3585 view_index_popup
[n
].label
.string
= "Thread Index";
3586 view_index_popup
[n
++].data
.val
= '<';
3589 view_index_popup
[n
].type
= tQueue
;
3590 view_index_popup
[n
].label
.style
= lNormal
;
3591 view_index_popup
[n
].label
.string
= "Folder &List";
3592 view_index_popup
[n
++].data
.val
= '<';
3595 view_index_popup
[n
].type
= tQueue
;
3596 view_index_popup
[n
].label
.style
= lNormal
;
3597 view_index_popup
[n
].label
.string
= "&Main Menu";
3598 view_index_popup
[n
++].data
.val
= 'M';
3600 view_index_popup
[n
].type
= tTail
;
3602 if(mswin_popup(view_index_popup
) == view_in_new_wind_index
3603 && view_in_new_wind_index
>= 0)
3604 view_in_new_window();
3609 pcpine_help_index(title
)
3613 * Title is size 256 in pico. Put in args.
3616 strncpy(title
, "Alpine MESSAGE INDEX Help", 256);
3618 return(pcpine_help(h_mail_index
));
3622 pcpine_help_index_simple(title
)
3626 * Title is size 256 in pico. Put in args.
3629 strncpy(title
, "Alpine SELECT MESSAGE Help", 256);
3631 return(pcpine_help(h_simple_index
));
3635 #include "../pico/osdep/mswin_tw.h"
3639 view_in_new_window(void)
3641 char title
[GETTEXT_TITLELEN
+1];
3645 MSWIN_TEXTWINDOW
*mswin_tw
= NULL
;
3647 /* Launch text in alt window. */
3648 if(index_gettext_callback(title
, sizeof (title
), &text
, &len
, &format
)){
3649 if(format
== GETTEXT_TEXT
)
3650 mswin_tw
= mswin_displaytext(title
, text
, (size_t) len
, NULL
,
3651 NULL
, MSWIN_DT_USEALTWINDOW
);
3652 else if(format
== GETTEXT_LINES
)
3653 mswin_tw
= mswin_displaytext(title
, NULL
, 0, text
,
3654 NULL
, MSWIN_DT_USEALTWINDOW
);
3656 if(mswin_tw
!= NULL
)
3657 mswin_set_readonly(mswin_tw
, FALSE
);
3661 #endif /* _WINDOWS */