1
#if !defined(lint) && !defined(DOS)
2
static char rcsid[] = "$Id: mailindx.c 380 2007-01-23 00:09:18Z hubert@u.washington.edu $";
6
* ========================================================================
7
* Copyright 2006-2007 University of Washington
9
* Licensed under the Apache License, Version 2.0 (the "License");
10
* you may not use this file except in compliance with the License.
11
* You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* ========================================================================
28
#include "../pith/flag.h"
29
#include "../pith/newmail.h"
30
#include "../pith/thread.h"
31
#include "../pith/conf.h"
32
#include "../pith/msgno.h"
33
#include "../pith/icache.h"
34
#include "../pith/state.h"
35
#include "../pith/bitmap.h"
36
#include "../pith/news.h"
37
#include "../pith/strlst.h"
38
#include "../pith/sequence.h"
39
#include "../pith/sort.h"
41
struct save_thrdinfo {
42
ICE_S *(*format_index_line)(INDEXDATA_S *);
43
void (*setup_header_widths)(MAILSTREAM *);
44
unsigned viewing_a_thread:1;
48
static OtherMenu what_keymenu = FirstMenu;
50
struct index_state *current_index_state = NULL;
56
void index_index_screen(struct pine *);
57
void thread_index_screen(struct pine *);
58
int update_index(struct pine *, struct index_state *);
59
int index_scroll_up(long);
60
int index_scroll_down(long);
61
int index_scroll_to_pos(long);
62
long top_ent_calc(MAILSTREAM *, MSGNO_S *, long, long);
63
void reset_index_border(void);
64
void redraw_index_body(void);
65
int paint_index_line(ICE_S *, int, long, IndexColType, IndexColType, IndexColType,
66
struct entry_state *, int, int);
67
void pine_imap_envelope(MAILSTREAM *, unsigned long, ENVELOPE *);
68
void index_search(struct pine *, MAILSTREAM *, int, MSGNO_S *);
69
COLOR_PAIR *apply_rev_color(COLOR_PAIR *, int);
71
int index_scroll_callback(int,long);
72
int index_gettext_callback(char *, size_t, void **, long *, int *);
73
void index_popup(MAILSTREAM *, MSGNO_S *, int);
74
char *pcpine_help_index(char *);
75
char *pcpine_help_index_simple(char *);
76
int pcpine_resize_index(void);
81
/*----------------------------------------------------------------------
86
do_index_border(CONTEXT_S *cntxt, char *folder, MAILSTREAM *stream, MSGNO_S *msgmap, IndexType style, int *which_keys, int flags)
88
struct key_menu *km = (style == ThreadIndex)
90
: (ps_global->mail_stream != stream)
91
? &simple_index_keymenu
94
if(flags & INDX_CLEAR)
97
if(flags & INDX_HEADER)
98
set_titlebar((style == ThreadIndex)
99
/* TRANSLATORS: these are some screen titles */
101
: (stream == ps_global->mail_stream)
102
? (style == MsgIndex || style == MultiMsgIndex)
104
: _("ZOOMED MESSAGE INDEX")
105
: (!strcmp(folder, INTERRUPTED_MAIL))
106
? _("COMPOSE: SELECT INTERRUPTED")
107
: (ps_global->VAR_FORM_FOLDER
108
&& !strcmp(ps_global->VAR_FORM_FOLDER, folder))
109
? _("COMPOSE: SELECT FORM LETTER")
110
: _("COMPOSE: SELECT POSTPONED"),
111
stream, cntxt, folder, msgmap, 1,
112
(style == ThreadIndex) ? ThrdIndex
114
&& sp_viewing_a_thread(stream))
119
if(flags & INDX_FOOTER) {
125
if(km == &index_keymenu){
126
if(THREADING() && sp_viewing_a_thread(stream)){
127
menu_init_binding(km, '<', MC_THRDINDX, "<",
128
N_("ThrdIndex"), BACK_KEY);
129
menu_add_binding(km, ',', MC_THRDINDX);
132
menu_init_binding(km, '<', MC_FOLDERS, "<",
133
N_("FldrList"), BACK_KEY);
134
menu_add_binding(km, ',', MC_FOLDERS);
136
if(F_OFF(F_ENABLE_PIPE,ps_global))
137
clrbitn(VIEW_PIPE_KEY, bitmap); /* always clear for DOS */
138
if(F_OFF(F_ENABLE_FULL_HDR,ps_global))
139
clrbitn(VIEW_FULL_HEADERS_KEY, bitmap);
140
if(F_OFF(F_ENABLE_BOUNCE,ps_global))
141
clrbitn(BOUNCE_KEY, bitmap);
142
if(F_OFF(F_ENABLE_FLAG,ps_global))
143
clrbitn(FLAG_KEY, bitmap);
144
if(F_OFF(F_ENABLE_AGG_OPS,ps_global)){
145
clrbitn(SELECT_KEY, bitmap);
146
clrbitn(APPLY_KEY, bitmap);
147
clrbitn(SELCUR_KEY, bitmap);
148
if(style != ZoomIndex)
149
clrbitn(ZOOM_KEY, bitmap);
153
if(style == MultiMsgIndex){
154
clrbitn(PREVM_KEY, bitmap);
155
clrbitn(NEXTM_KEY, bitmap);
159
if(km == &index_keymenu || km == &thread_keymenu){
161
km->keys[EXCLUDE_KEY].label = N_("eXclude");
162
KS_OSDATASET(&km->keys[EXCLUDE_KEY], KS_NONE);
165
clrbitn(UNEXCLUDE_KEY, bitmap);
166
km->keys[EXCLUDE_KEY].label = N_("eXpunge");
167
KS_OSDATASET(&km->keys[EXCLUDE_KEY], KS_EXPUNGE);
171
if(km != &simple_index_keymenu && !THRD_COLLAPSE_ENABLE())
172
clrbitn(COLLAPSE_KEY, bitmap);
174
menu_clear_binding(km, KEY_LEFT);
175
menu_clear_binding(km, KEY_RIGHT);
176
if(F_ON(F_ARROW_NAV, ps_global)){
177
if((cmd = menu_clear_binding(km, '<')) != MC_UNKNOWN){
178
menu_add_binding(km, '<', cmd);
179
menu_add_binding(km, KEY_LEFT, cmd);
182
if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
183
menu_add_binding(km, '>', cmd);
184
menu_add_binding(km, KEY_RIGHT, cmd);
188
if(menu_binding_index(km, MC_JUMP) >= 0){
189
for(cmd = 0; cmd < 10; cmd++)
190
if(F_ON(F_ENABLE_JUMP, ps_global))
191
(void) menu_add_binding(km, '0' + cmd, MC_JUMP);
193
(void) menu_clear_binding(km, '0' + cmd);
196
draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
197
1-FOOTER_ROWS(ps_global), 0, what_keymenu);
198
what_keymenu = SameMenu;
200
*which_keys = km->which; /* pass back to caller */
208
/*----------------------------------------------------------------------
209
Main loop executing commands for the mail index screen
211
Args: state -- the pine_state structure for next/prev screen pointers
212
and to pass to the index manager...
216
mail_index_screen(struct pine *state)
218
if(!state->mail_stream) {
219
q_status_message(SM_ORDER, 0, 3, _("No folder is currently open"));
220
state->prev_screen = mail_index_screen;
221
state->next_screen = main_menu_screen;
225
state->prev_screen = mail_index_screen;
226
state->next_screen = SCREEN_FUN_NULL;
229
&& sp_viewing_a_thread(state->mail_stream)
230
&& state->view_skipped_index
231
&& unview_thread(state, state->mail_stream, state->msgmap)){
232
state->next_screen = mail_index_screen;
233
state->view_skipped_index = 0;
234
state->mangled_screen = 1;
237
adjust_cur_to_visible(state->mail_stream, state->msgmap);
240
thread_index_screen(state);
242
index_index_screen(state);
247
index_index_screen(struct pine *state)
249
dprint((1, "\n\n ---- MAIL INDEX ----\n"));
251
setup_for_index_index_screen();
253
index_lister(state, state->context_current, state->cur_folder,
254
state->mail_stream, state->msgmap);
259
thread_index_screen(struct pine *state)
261
dprint((1, "\n\n ---- THREAD INDEX ----\n"));
263
setup_for_thread_index_screen();
265
index_lister(state, state->context_current, state->cur_folder,
266
state->mail_stream, state->msgmap);
271
stop_threading_temporarily(void)
273
struct save_thrdinfo *ti;
275
ps_global->turn_off_threading_temporarily = 1;
277
ti = (struct save_thrdinfo *) fs_get(sizeof(*ti));
278
ti->format_index_line = format_index_line;
279
ti->setup_header_widths = setup_header_widths;
280
ti->viewing_a_thread = sp_viewing_a_thread(ps_global->mail_stream);
282
setup_for_index_index_screen();
289
restore_threading(void **p)
291
struct save_thrdinfo *ti;
293
ps_global->turn_off_threading_temporarily = 0;
296
ti = (struct save_thrdinfo *) (*p);
297
format_index_line = ti->format_index_line;
298
setup_header_widths = ti->setup_header_widths;
299
sp_set_viewing_a_thread(ps_global->mail_stream, ti->viewing_a_thread);
306
/*----------------------------------------------------------------------
307
Main loop executing commands for the mail index screen
309
Args: state -- pine_state structure for display flags and such
310
msgmap -- c-client/pine message number mapping struct
314
index_lister(struct pine *state, CONTEXT_S *cntxt, char *folder, MAILSTREAM *stream, MSGNO_S *msgmap)
317
int cmd, which_keys, force,
318
cur_row, cur_col, km_popped, paint_status;
320
long i, j, k, old_max_msgno;
322
IndexType style, old_style = MsgIndex;
323
struct index_state id;
324
struct key_menu *km = NULL;
325
#if defined(DOS) || defined(OS2)
326
/* extern void (*while_waiting)(); */
329
dprint((1, "\n\n ---- INDEX MANAGER ----\n"));
331
ch = 'x'; /* For displaying msg 1st time thru */
334
state->mangled_screen = 1;
335
what_keymenu = FirstMenu;
336
old_max_msgno = mn_get_total(msgmap);
337
memset((void *)&id, 0, sizeof(struct index_state));
338
current_index_state = &id;
340
if(msgmap->top != 0L)
341
id.msg_at_top = msgmap->top;
344
set_need_format_setup(stream);
347
ps_global->user_says_cancel = 0;
353
if(!state->mangled_body
355
&& id.lines_per_page > 1){
356
id.entry_state[id.lines_per_page-2].id = 0;
357
id.entry_state[id.lines_per_page-1].id = 0;
360
state->mangled_body = 1;
364
/*------- Check for new mail -------*/
365
new_mail(force, NM_TIMING(ch), NM_STATUS_MSG);
366
force = 0; /* may not need to next time around */
369
* If the width of the message number field in the display changes
370
* we need to flush the cache and redraw. When the cache is cleared
371
* the widths are recalculated, taking into account the max msgno.
374
if(format_includes_msgno(stream) &&
375
(old_max_msgno < 1000L && mn_get_total(msgmap) >= 1000L
376
|| old_max_msgno < 10000L && mn_get_total(msgmap) >= 10000L
377
|| old_max_msgno < 100000L && mn_get_total(msgmap) >= 100000L)){
378
clear_index_cache(stream, IC_CLEAR_WIDTHS_DONE);
379
state->mangled_body = 1;
382
old_max_msgno = mn_get_total(msgmap);
385
* If the display includes the SMARTDATE ("Today", "Yesterday", ...)
386
* then when the day changes the date column will change. All of the
387
* Today's will become Yesterday's at midnight. So we have to
388
* clear the cache at midnight.
390
if(format_includes_smartdate(stream)){
395
parse_date(db, &nnow);
396
if(old_day != -1 && nnow.day != old_day){
397
clear_index_cache(stream, IC_CLEAR_WIDTHS_DONE);
398
state->mangled_body = 1;
405
state->mangled_header = 1;
407
if(state->mangled_screen){
408
state->mangled_header = 1;
409
state->mangled_body = 1;
410
state->mangled_footer = 1;
411
state->mangled_screen = 0;
415
* events may have occured that require us to shift from
420
: (any_lflagged(msgmap, MN_HIDE))
422
: (mn_total_cur(msgmap) > 1L) ? MultiMsgIndex : MsgIndex;
423
if(style != old_style){
424
state->mangled_header = 1;
425
state->mangled_footer = 1;
427
if(!(style == ThreadIndex || old_style == ThreadIndex))
431
/*------------ Update the title bar -----------*/
432
if(state->mangled_header) {
433
km = do_index_border(cntxt, folder, stream, msgmap,
434
style, NULL, INDX_HEADER);
435
state->mangled_header = 0;
438
else if(mn_get_total(msgmap) > 0) {
439
update_titlebar_message();
441
* If flags aren't available to update the status,
442
* defer it until after all the fetches associated
443
* with building index lines are done (no extra rtts!)...
445
paint_status = !update_titlebar_status();
448
current_index_state = &id;
450
/*------------ draw the index body ---------------*/
451
cur_row = update_index(state, &id);
452
if(F_OFF(F_SHOW_CURSOR, state)){
453
cur_row = state->ttyo->screen_rows - FOOTER_ROWS(state);
456
else if(id.status_col >= 0)
457
cur_col = MIN(id.status_col, state->ttyo->screen_cols-1);
459
ps_global->redrawer = redraw_index_body;
462
(void) update_titlebar_status();
464
/*------------ draw the footer/key menus ---------------*/
465
if(state->mangled_footer) {
466
if(!state->painted_footer_on_startup){
468
FOOTER_ROWS(state) = 3;
472
km = do_index_border(cntxt, folder, stream, msgmap, style,
473
&which_keys, INDX_FOOTER);
475
FOOTER_ROWS(state) = 1;
476
mark_keymenu_dirty();
480
state->mangled_footer = 0;
483
state->painted_body_on_startup = 0;
484
state->painted_footer_on_startup = 0;
486
/*-- Display any queued message (eg, new mail, command result --*/
488
FOOTER_ROWS(state) = 3;
489
mark_status_unknown();
494
FOOTER_ROWS(state) = 1;
495
mark_status_unknown();
498
if(F_ON(F_SHOW_CURSOR, state) && cur_row < 0){
499
cur_row = state->ttyo->screen_rows - FOOTER_ROWS(state);
502
cur_row = MIN(MAX(cur_row, 0), state->ttyo->screen_rows-1);
503
MoveCursor(cur_row, cur_col);
505
/* Let read_command do the fflush(stdout) */
507
/*---------- Read command and validate it ----------------*/
509
mouse_in_content(KEY_MOUSE, -1, -1, 0x5, 0);
510
register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
511
state->ttyo->screen_rows-(FOOTER_ROWS(ps_global)+1),
512
state->ttyo->screen_cols);
514
#if defined(DOS) || defined(OS2)
516
* AND pre-build header lines. This works just fine under
517
* DOS since we wait for characters in a loop. Something will
518
* will have to change under UNIX if we want to do the same.
520
/* while_waiting = build_header_cache; */
522
/* while_waiting = NULL; */
523
mswin_setscrollcallback (index_scroll_callback);
524
mswin_sethelptextcallback((stream == state->mail_stream)
526
: pcpine_help_index_simple);
527
mswin_setresizecallback(pcpine_resize_index);
530
ch = read_command(&utf8str);
532
clear_mfunc(mouse_in_content);
534
#if defined(DOS) || defined(OS2)
535
/* while_waiting = NULL; */
537
mswin_setscrollcallback(NULL);
538
mswin_sethelptextcallback(NULL);
539
mswin_clearresizecallback(pcpine_resize_index);
543
cmd = menu_command(ch, km);
559
/*----------- Execute the command ------------------*/
562
/*---------- Roll keymenu ----------*/
564
if(F_OFF(F_USE_FK, ps_global))
567
what_keymenu = NextMenu;
568
state->mangled_footer = 1;
572
/*---------- Scroll line up ----------*/
574
(void) process_cmd(state, stream, msgmap, MC_PREVITEM,
576
|| style == MultiMsgIndex
577
|| style == ZoomIndex)
579
: (style == ThreadIndex)
583
if(mn_get_cur(msgmap) < (id.msg_at_top + HS_MARGIN(state)))
589
/*---------- Scroll line down ----------*/
592
* Special Page framing handling here. If we
593
* did something that should scroll-by-a-line, frame
594
* the page by hand here rather than leave it to the
595
* page-by-page framing in update_index()...
597
(void) process_cmd(state, stream, msgmap, MC_NEXTITEM,
599
|| style == MultiMsgIndex
600
|| style == ZoomIndex)
602
: (style == ThreadIndex)
606
for(j = 0L, k = i = id.msg_at_top; ; i++){
607
if(!msgline_hidden(stream, msgmap, i, 0)){
609
if(j++ >= id.lines_per_page)
613
if(i >= mn_get_total(msgmap)){
614
k = 0L; /* don't scroll */
619
if(k && (mn_get_cur(msgmap) + HS_MARGIN(state)) >= k)
620
index_scroll_down(1L);
625
/*---------- Scroll page up ----------*/
628
for(k = i = id.msg_at_top; ; i--){
629
if(!msgline_hidden(stream, msgmap, i, 0)){
631
if(++j >= id.lines_per_page){
632
if((id.msg_at_top = i) == 1L)
633
q_status_message(SM_ORDER, 0, 1, _("First Index page"));
640
if((!THREADING() && mn_get_cur(msgmap) == 1L)
642
&& mn_get_cur(msgmap) == first_sorted_flagged(F_NONE,
646
q_status_message(SM_ORDER, 0, 1,
647
_("Already at start of Index"));
653
if(mn_get_total(msgmap) > 0L && mn_total_cur(msgmap) == 1L)
654
mn_set_cur(msgmap, k);
659
/*---------- Scroll page forward ----------*/
662
for(k = i = id.msg_at_top; ; i++){
663
if(!msgline_hidden(stream, msgmap, i, 0)){
665
if(++j >= id.lines_per_page){
666
if(i+id.lines_per_page > mn_get_total(msgmap))
667
q_status_message(SM_ORDER, 0, 1, _("Last Index page"));
674
if(i >= mn_get_total(msgmap)){
675
if(mn_get_cur(msgmap) == k)
676
q_status_message(SM_ORDER,0,1,_("Already at end of Index"));
682
if(mn_get_total(msgmap) > 0L && mn_total_cur(msgmap) == 1L)
683
mn_set_cur(msgmap, k);
688
/*---------- Scroll to first page ----------*/
690
if((mn_get_total(msgmap) > 0L)
691
&& (mn_total_cur(msgmap) <= 1L)){
692
long cur_msg = mn_get_cur(msgmap), selected;
694
if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
697
mn_dec_cur(stream, msgmap, MH_NONE);
698
cur_msg = mn_get_cur(msgmap);
700
while(selected != cur_msg);
703
cur_msg = (mn_get_total(msgmap) > 0L) ? 1L : 0L;
704
mn_set_cur(msgmap, cur_msg);
705
q_status_message(SM_ORDER, 0, 3, _("First Index Page"));
709
/*---------- Scroll to last page ----------*/
711
if((mn_get_total(msgmap) > 0L)
712
&& (mn_total_cur(msgmap) <= 1L)){
713
long cur_msg = mn_get_cur(msgmap), selected;
715
if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
718
mn_inc_cur(stream, msgmap, MH_NONE);
719
cur_msg = mn_get_cur(msgmap);
721
while(selected != cur_msg);
724
cur_msg = mn_get_total(msgmap);
725
mn_set_cur(msgmap, cur_msg);
726
q_status_message(SM_ORDER, 0, 3, _("Last Index Page"));
730
/*---------- Search (where is command) ----------*/
732
index_search(state, stream, -FOOTER_ROWS(ps_global), msgmap);
733
state->mangled_footer = 1;
737
/*-------------- jump command -------------*/
738
/* NOTE: preempt the process_cmd() version because
739
* we need to get at the number..
742
j = jump_to(msgmap, -FOOTER_ROWS(ps_global), ch, NULL,
743
(style == ThreadIndex) ? ThrdIndx : MsgIndx);
745
if(style == ThreadIndex){
748
thrd = find_thread_by_number(stream, msgmap, j, NULL);
750
if(thrd && thrd->rawno)
751
mn_set_cur(msgmap, mn_raw2m(msgmap, thrd->rawno));
754
/* jump to message */
755
if(mn_total_cur(msgmap) > 1L){
756
mn_reset_cur(msgmap, j);
759
mn_set_cur(msgmap, j);
766
state->mangled_footer = 1;
770
case MC_VIEW_ENTRY : /* only happens in thread index */
773
* If the feature F_THRD_AUTO_VIEW is turned on and there
774
* is only one message in the thread, then we skip the index
775
* view of the thread and go straight to the message view.
778
if(THRD_AUTO_VIEW() && style == ThreadIndex){
781
thrd = fetch_thread(stream,
782
mn_m2raw(msgmap, mn_get_cur(msgmap)));
784
&& (count_lflags_in_thread(stream, thrd,
785
msgmap, MN_NONE) == 1)){
786
if(view_thread(state, stream, msgmap, 1)){
787
state->view_skipped_index = 1;
794
if(view_thread(state, stream, msgmap, 1)){
795
ps_global->next_screen = mail_index_screen;
796
ps_global->redrawer = NULL;
797
current_index_state = NULL;
799
fs_give((void **)&(id.entry_state));
808
msgmap->top = msgmap->top_after_thrd;
809
if(unview_thread(state, stream, msgmap)){
810
state->next_screen = mail_index_screen;
811
state->view_skipped_index = 0;
812
state->mangled_screen = 1;
813
ps_global->redrawer = NULL;
814
current_index_state = NULL;
816
fs_give((void **)&(id.entry_state));
830
mouse_get_last (NULL, &mp);
833
for(i = id.msg_at_top;
834
mp.row >= 0 && i <= mn_get_total(msgmap);
836
if(!msgline_hidden(stream, msgmap, i, 0)){
841
if(mn_get_total(msgmap) && mp.row < 0){
844
if(mn_total_cur(msgmap) == 1L)
845
mn_set_cur(msgmap, new_cur);
847
if(mp.flags & M_KEY_CONTROL){
848
if(F_ON(F_ENABLE_AGG_OPS, ps_global)){
849
(void) select_by_current(state, msgmap, MsgIndx);
852
else if(!(mp.flags & M_KEY_SHIFT)){
855
&& mp.col == id.plus_col
856
&& style != ThreadIndex){
857
collapse_or_expand(state, stream, msgmap,
860
else if (mp.doubleclick){
861
if(mp.button == M_BUTTON_LEFT){
862
if(stream == state->mail_stream){
873
ps_global->redrawer = NULL;
874
current_index_state = NULL;
876
fs_give((void **)&(id.entry_state));
885
case M_BUTTON_MIDDLE:
888
case M_BUTTON_RIGHT :
890
if (!mp.doubleclick){
891
if(mn_total_cur(msgmap) == 1L)
892
mn_set_cur(msgmap, new_cur);
894
cur_row = update_index(state, &id);
896
index_popup(stream, msgmap, TRUE);
907
case M_BUTTON_MIDDLE :
910
case M_BUTTON_RIGHT :
912
index_popup(stream, msgmap, FALSE);
922
/*---------- Resize ----------*/
925
* If we were smarter we could do the
926
* IC_CLEAR_WIDTHS_DONE trick here. The problem is
927
* that entire columns of the format can go away or
928
* appear because the width gets smaller or larger,
929
* so in that case we need to re-do. If we could tell
930
* when that happened or not we could set the flag
933
clear_index_cache(stream, 0);
934
reset_index_border();
938
/*---------- Redraw ----------*/
940
force = 1; /* check for new mail! */
941
reset_index_border();
945
/*---------- No op command ----------*/
947
break; /* no op check for new mail */
950
/*--------- keystroke not bound to command --------*/
956
bogus_command(ch, F_ON(F_USE_FK,state) ? "F1" : "?");
961
thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state));
977
PINETHRD_S *thrd = NULL;
980
rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
982
thrd = fetch_thread(stream, rawno);
984
collapsed = thrd && thrd->next
985
&& get_lflag(stream, NULL, rawno, MN_COLL);
989
thread_command(state, stream, msgmap,
990
ch, -FOOTER_ROWS(state));
991
/* increment current */
992
if(cmd == MC_DELETE){
993
advance_cur_after_delete(state, stream, msgmap,
995
|| style == MultiMsgIndex
996
|| style == ZoomIndex)
998
: (style == ThreadIndex)
1002
else if((cmd == MC_SELCUR
1003
&& (state->ugly_consider_advancing_bit
1004
|| F_OFF(F_UNSELECT_WONT_ADVANCE, state)))
1005
|| (state->ugly_consider_advancing_bit
1007
&& F_ON(F_SAVE_ADVANCES, state))){
1008
mn_inc_cur(stream, msgmap, MH_NONE);
1012
goto do_the_default;
1019
bogus_utf8_command(utf8str, NULL);
1023
/*---------- First HELP command with menu hidden ----------*/
1025
if(FOOTER_ROWS(state) == 1 && km_popped == 0){
1027
mark_status_unknown();
1028
mark_keymenu_dirty();
1029
state->mangled_footer = 1;
1032
/* else fall thru to normal default */
1035
/*---------- Default -- all other command ----------*/
1038
if(stream == state->mail_stream){
1039
msgmap->top = id.msg_at_top;
1040
process_cmd(state, stream, msgmap, cmd,
1042
|| style == MultiMsgIndex
1043
|| style == ZoomIndex)
1045
: (style == ThreadIndex)
1049
if(state->next_screen != SCREEN_FUN_NULL){
1050
ps_global->redrawer = NULL;
1051
current_index_state = NULL;
1053
fs_give((void **)&(id.entry_state));
1058
if(stream != state->mail_stream){
1060
* Must have had an failed open. repair our
1063
id.stream = stream = state->mail_stream;
1064
id.msgmap = msgmap = state->msgmap;
1067
current_index_state = &id;
1069
if(cmd == MC_ZOOM && THRD_INDX())
1073
else{ /* special processing */
1076
helper(h_simple_index,
1077
(!strcmp(folder, INTERRUPTED_MAIL))
1078
? _("HELP FOR SELECTING INTERRUPTED MSG")
1079
: _("HELP FOR SELECTING POSTPONED MSG"),
1081
state->mangled_screen = 1;
1084
case MC_DELETE : /* delete */
1085
dprint((3, "Special delete: msg %s\n",
1086
long2string(mn_get_cur(msgmap))));
1092
raw = mn_m2raw(msgmap, mn_get_cur(msgmap));
1093
if(raw > 0L && stream
1094
&& raw <= stream->nmsgs
1095
&& (mc = mail_elt(stream, raw))
1097
if((t = mn_get_cur(msgmap)) > 0L)
1098
clear_index_cache_ent(stream, t, 0);
1100
mail_setflag(stream,long2string(raw),"\\DELETED");
1101
update_titlebar_status();
1105
q_status_message1(SM_ORDER, 0, 1,
1106
del ? _("Message %s deleted") : _("Message %s already deleted"),
1107
long2string(mn_get_cur(msgmap)));
1112
case MC_UNDELETE : /* UNdelete */
1113
dprint((3, "Special UNdelete: msg %s\n",
1114
long2string(mn_get_cur(msgmap))));
1120
raw = mn_m2raw(msgmap, mn_get_cur(msgmap));
1121
if(raw > 0L && stream
1122
&& raw <= stream->nmsgs
1123
&& (mc = mail_elt(stream, raw))
1125
if((t = mn_get_cur(msgmap)) > 0L)
1126
clear_index_cache_ent(stream, t, 0);
1128
mail_clearflag(stream, long2string(raw),
1130
update_titlebar_status();
1134
q_status_message1(SM_ORDER, 0, 1,
1135
del ? _("Message %s UNdeleted") : _("Message %s NOT deleted"),
1136
long2string(mn_get_cur(msgmap)));
1141
case MC_EXIT : /* exit */
1142
ps_global->redrawer = NULL;
1143
current_index_state = NULL;
1145
fs_give((void **)&(id.entry_state));
1149
case MC_SELECT : /* select */
1150
ps_global->redrawer = NULL;
1151
current_index_state = NULL;
1153
fs_give((void **)&(id.entry_state));
1157
case MC_PREVITEM : /* previous */
1158
mn_dec_cur(stream, msgmap, MH_NONE);
1161
case MC_NEXTITEM : /* next */
1162
mn_inc_cur(stream, msgmap, MH_NONE);
1166
bogus_command(ch, NULL);
1170
} /* The big switch */
1171
} /* the BIG while loop! */
1176
/*----------------------------------------------------------------------
1177
Manage index body painting
1179
Args: state - pine struct containing selected message data
1180
index_state - struct describing what's currently displayed
1182
Returns: screen row number of first highlighted message
1184
The idea is pretty simple. Maintain an array of index line id's that
1185
are displayed and their hilited state. Decide what's to be displayed
1186
and update the screen appropriately. All index screen painting
1187
is done here. Pretty simple, huh?
1190
update_index(struct pine *state, struct index_state *screen)
1192
int i, retval = -1, row, already_fetched = 0;
1194
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
screen->entry_state[i].id = 0;
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);
1438
* This works for forward or reverse sort because the thrdno's
1439
* will have been reversed.
1441
thrd = fetch_thread(screen->stream,
1442
mn_m2raw(screen->msgmap, screen->msg_at_top));
1444
scroll_setrange(screen->lines_per_page,
1445
screen->msgmap->max_thrdno - 1L);
1446
scroll_setpos(thrd->thrdno - 1L);
1450
else if(n = any_lflagged(screen->msgmap, MN_HIDE | MN_CHID)){
1453
range = mn_get_total(screen->msgmap) - n - 1L;
1454
scroll_setrange(screen->lines_per_page, range);
1456
if(range >= screen->lines_per_page){ /* else not needed */
1457
if(screen->msg_at_top < mn_get_total(screen->msgmap) / 2){
1458
for(n = 1, x = 0; n != screen->msg_at_top; n++)
1459
if(!msgline_hidden(screen->stream, screen->msgmap, n, 0))
1463
for(n = mn_get_total(screen->msgmap), x = range;
1464
n != screen->msg_at_top; n--)
1465
if(!msgline_hidden(screen->stream, screen->msgmap, n, 0))
1473
scroll_setrange(screen->lines_per_page,
1474
mn_get_total(screen->msgmap) - 1L);
1475
scroll_setpos(screen->msg_at_top - 1L);
1480
* Set up c-client call back to tell us about IMAP envelope arrivals
1481
* Can't do it (easily) if single lines on the screen need information
1482
* about more than a single message before they can be drawn.
1484
if(F_OFF(F_QUELL_IMAP_ENV_CB, ps_global) && !THRD_INDX()
1485
&& !(THREADING() && (sp_viewing_a_thread(screen->stream)
1486
|| ps_global->thread_disp_style == THREAD_MUTTLIKE
1487
|| any_lflagged(screen->msgmap, MN_COLL))))
1488
mail_parameters(NULL, SET_IMAPENVELOPE, (void *) pine_imap_envelope);
1491
visible = screen->msgmap->visible_threads;
1492
else if(THREADING() && sp_viewing_a_thread(screen->stream)){
1494
* We know that all visible messages in the thread are marked
1497
for(visible = 0L, n = screen->msg_at_top;
1498
visible < (int) screen->lines_per_page
1499
&& n <= mn_get_total(screen->msgmap); n++){
1501
if(!get_lflag(screen->stream, screen->msgmap, n, MN_CHID2))
1504
if(!msgline_hidden(screen->stream, screen->msgmap, n, 0))
1509
visible = mn_get_total(screen->msgmap)
1510
- any_lflagged(screen->msgmap, MN_HIDE|MN_CHID);
1512
/*---- march thru display lines, painting whatever is needed ----*/
1513
for(i = 0, n = screen->msg_at_top; i < (int) screen->lines_per_page; i++){
1514
if(visible == 0L || n < 1 || n > mn_get_total(screen->msgmap)){
1515
if(screen->entry_state[i].id != LINE_HASH_N){
1516
screen->entry_state[i].hilite = 0;
1517
screen->entry_state[i].bolded = 0;
1518
screen->entry_state[i].msgno = 0L;
1519
screen->entry_state[i].id = LINE_HASH_N;
1520
ClearLine(HEADER_ROWS(state) + i);
1527
* This changes status_col as a side effect so it has to be
1528
* executed before next line.
1530
ice = build_header_line(state, screen->stream, screen->msgmap,
1531
n, &already_fetched);
1536
unsigned long rawno;
1538
rawno = mn_m2raw(screen->msgmap, n);
1540
thrd = fetch_thread(screen->stream, rawno);
1543
row = paint_index_line(ice, i,
1544
(THRD_INDX() && thrd) ? thrd->thrdno : n,
1545
screen->status_fld, screen->plus_fld,
1546
screen->arrow_fld, &screen->entry_state[i],
1547
mn_is_cur(screen->msgmap, n),
1549
? (count_lflags_in_thread(screen->stream,
1553
: get_lflag(screen->stream, screen->msgmap,
1555
if(row && retval < 0)
1559
/*--- increment n ---*/
1560
while((visible == -1L || visible > 0L)
1561
&& ++n <= mn_get_total(screen->msgmap)
1562
&& msgline_hidden(screen->stream, screen->msgmap, n, 0))
1566
mail_parameters(NULL, SET_IMAPENVELOPE, (void *) NULL);
1572
dprint((7, "--update_index done\n"));
1578
/*----------------------------------------------------------------------
1579
Create a string summarizing the message header for index on screen
1581
Args: stream -- mail stream to fetch envelope info from
1582
msgmap -- message number to pine sort mapping
1583
msgno -- Message number to create line for
1585
Result: returns a malloced string
1586
saves string in a cache for next call for same header
1589
build_header_line(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, int *already_fetched)
1591
return(build_header_work(state, stream, msgmap, msgno,
1592
current_index_state->msg_at_top,
1593
current_index_state->lines_per_page,
1598
/*----------------------------------------------------------------------
1599
Paint the given index line
1602
Args: ice -- index cache entry
1603
line -- index line number on screen, starting at 0 for first
1604
visible line, 1, 2, ...
1605
msgno -- for painting the message number field
1606
sfld -- field type of the status field, which is
1607
where we'll put the X for selected if necessary
1608
pfld -- field type where the thread indicator symbol goes
1609
afld -- field type of column which corresponds to the
1610
index-format ARROW token
1611
entry -- cache used to help us decide whether or not we need to
1612
redraw the index line or if we can just leave it alone because
1613
we know it is already correct
1614
cur -- is this the current message?
1615
sel -- is this message in the selected set?
1617
Returns: screen row number if this is current message, else 0
1620
paint_index_line(ICE_S *argice, int line, long int msgno, IndexColType sfld,
1621
IndexColType pfld, IndexColType afld, struct entry_state *entry,
1624
COLOR_PAIR *lastc = NULL, *base_color = NULL;
1628
int save_schar1 = -1, save_schar2 = -1, save_pchar = -1, save, i;
1629
int draw_whole_line = 0, draw_partial_line = 0;
1630
int n = MAX_SCREEN_COLS*6;
1631
char draw[MAX_SCREEN_COLS*6+1], *p;
1633
ice = (THRD_INDX() && argice) ? argice->tice : argice;
1635
/* This better not happen! */
1637
q_status_message1(SM_ORDER | SM_DING, 5, 5,
1638
"NULL ice in paint_index_line: %s",
1639
THRD_INDX() ? "THRD_INDX" : "reg index");
1640
dprint((1, "NULL ice in paint_index_line: %s\n",
1641
THRD_INDX() ? "THRD_INDX" : "reg index"));
1645
if(entry->msgno != msgno || ice->id == 0 || entry->id != ice->id){
1648
draw_whole_line = 1;
1650
else if((cur != entry->hilite) || (sel != entry->bolded)
1651
|| (ice->plus != entry->plus)){
1652
draw_partial_line = 1;
1655
if(draw_whole_line || draw_partial_line){
1657
if(F_ON(F_FORCE_LOW_SPEED,ps_global) || ps_global->low_speed){
1659
memset(draw, 0, sizeof(draw));
1662
for(ifield = ice->ifield; ifield && p-draw < n; ifield = ifield->next){
1664
/* space between fields */
1665
if(ifield != ice->ifield)
1668
/* message number string is generated on the fly */
1669
if(ifield->ctype == iMessNo){
1670
ielem = ifield->ielem;
1671
if(ielem && ielem->datalen >= ifield->width){
1672
snprintf(ielem->data, ielem->datalen+1, "%*.ld", ifield->width, msgno);
1673
ielem->data[ifield->width] = '\0';
1674
ielem->data[ielem->datalen] = '\0';
1678
if(ifield->ctype == sfld){
1679
ielem = ifield->ielem;
1680
if(ielem && ielem->datalen > 0){
1681
if(draw_partial_line)
1682
MoveCursor(HEADER_ROWS(ps_global) + line, (int) (p-draw));
1684
if(ielem->datalen == 1){
1685
save_schar1 = ielem->data[0];
1686
ielem->data[0] = (sel) ? 'X' : (cur && save_schar1 == ' ') ? '-' : save_schar1;
1687
if(draw_partial_line)
1688
Writechar(ielem->data[0], 0);
1690
if(ielem->next && ielem->next->datalen){
1691
save_schar2 = ielem->next->data[0];
1693
ielem->next->data[0] = '>';
1695
if(draw_partial_line)
1696
Writechar(ielem->next->data[0], 0);
1699
else if(ielem->datalen > 1){
1700
save_schar1 = ielem->data[0];
1701
ielem->data[0] = (sel) ? 'X' : (cur && save_schar1 == ' ') ? '-' : save_schar1;
1702
if(draw_partial_line)
1703
Writechar(ielem->data[0], 0);
1705
save_schar2 = ielem->data[1];
1707
ielem->data[1] = '>';
1708
if(draw_partial_line)
1709
Writechar(ielem->data[1], 0);
1714
else if(ifield->ctype == afld){
1716
if(draw_partial_line){
1717
MoveCursor(HEADER_ROWS(ps_global) + line, (int) (p-draw));
1718
for(i = 0; i < ifield->width-1; i++)
1719
Writechar(cur ? '-' : ' ', 0);
1721
Writechar(cur ? '>' : ' ', 0);
1724
ielem = ifield->ielem;
1725
if(ielem && ielem->datalen >= ifield->width){
1726
for(i = 0; i < ifield->width-1; i++)
1727
ielem->data[i] = cur ? '-' : ' ';
1729
ielem->data[i] = cur ? '>' : ' ';
1732
else if(ifield->ctype == pfld){
1733
ielem = ifield->ielem;
1734
if(ielem && ielem->datalen > 0){
1735
save_pchar = ielem->data[0];
1736
ielem->data[0] = ice->plus;
1738
if(draw_partial_line){
1739
MoveCursor(HEADER_ROWS(ps_global) + line, (int) (p-draw));
1740
Writechar(ielem->data[0], 0);
1746
for(ielem = ifield->ielem;
1747
ielem && ielem->print_format && p-draw < n;
1748
ielem = ielem->next){
1753
bytes_added = utf8_pad_to_width(p, src,
1754
((p-draw)+n+1) * sizeof(char),
1755
ielem->wid, ifield->leftadj);
1761
if(ifield->ctype == sfld){
1762
ielem = ifield->ielem;
1763
if(ielem && ielem->datalen > 0){
1764
if(ielem->datalen == 1){
1765
ielem->data[0] = save_schar1;
1766
if(ielem->next && ielem->next->datalen)
1767
ielem->next->data[0] = save_schar2;
1769
else if(ielem->datalen > 1){
1770
ielem->data[0] = save_schar1;
1771
ielem->data[1] = save_schar2;
1775
else if(ifield->ctype == afld){
1776
ielem = ifield->ielem;
1777
if(ielem && ielem->datalen >= ifield->width)
1778
for(i = 0; i < ifield->width; i++)
1779
ielem->data[i] = ' ';
1781
else if(ifield->ctype == pfld){
1782
ielem = ifield->ielem;
1783
if(ielem && ielem->datalen > 0)
1784
ielem->data[0] = save_pchar;
1791
PutLine0(HEADER_ROWS(ps_global) + line, 0, draw);
1794
int uc, ac, do_arrow;
1796
int inverse_hack = 0, need_inverse_hack = 0;
1799
/* so we can restore current color at the end */
1800
if(uc=pico_usingcolor())
1801
lastc = pico_get_cur_color();
1804
* There are two possible "arrow" cursors. One is the one that
1805
* you get when you are at a slow speed or you turn that slow
1806
* speed one on. It is drawn as part of the status column.
1807
* That one is the one associated with the variable "ac".
1808
* It is always the base_color or the inverse of the base_color.
1810
* The other "arrow" cursor is the one you get by including the
1811
* ARROW token in the index-format. It may be configured to
1814
* The arrow cursors have two special properties that make
1815
* them different from other sections or fields.
1816
* First, the arrow cursors only show up on the current line.
1817
* Second, the arrow cursors are drawn with generated data, not
1818
* data that is present in the passed in data.
1821
/* ac is for the old integrated arrow cursor */
1822
ac = F_ON(F_FORCE_ARROW,ps_global);
1824
/* do_arrow is for the ARROW token in index-format */
1825
do_arrow = (afld != iNothing);
1827
MoveCursor(HEADER_ROWS(ps_global) + line, 0);
1829
/* find the base color for the whole line */
1830
if(cur && !ac && !do_arrow){
1832
* This stanza handles the current line marking in the
1833
* regular, non-arrow-cursor case.
1837
* If the current line has a linecolor, apply the
1838
* appropriate reverse transformation to show it is current.
1840
if(uc && ice->linecolor && ice->linecolor->fg[0]
1841
&& ice->linecolor->bg[0] && pico_is_good_colorpair(ice->linecolor)){
1842
base_color = apply_rev_color(ice->linecolor,
1843
ps_global->index_color_style);
1845
(void)pico_set_colorp(base_color, PSC_NONE);
1853
else if(uc && ice->linecolor && ice->linecolor->fg[0]
1854
&& ice->linecolor->bg[0]
1855
&& pico_is_good_colorpair(ice->linecolor)){
1856
(void)pico_set_colorp(ice->linecolor, PSC_NONE);
1857
base_color = ice->linecolor;
1862
memset(draw, 0, sizeof(draw));
1865
doing_bold = (sel && F_ON(F_SELECTED_SHOWN_BOLD, ps_global) && StartBold());
1867
/* draw each field */
1868
for(ifield = ice->ifield; ifield && p-draw < n; ifield = ifield->next){
1873
* Fix up the data for some special cases.
1876
/* message number string is generated on the fly */
1877
if(ifield->ctype == iMessNo){
1878
ielem = ifield->ielem;
1879
if(ielem && ielem->datalen >= ifield->width){
1880
snprintf(ielem->data, ielem->datalen+1, "%*.ld", ifield->width, msgno);
1881
ielem->data[ifield->width] = '\0';
1882
ielem->data[ielem->datalen] = '\0';
1886
if(ifield->ctype == sfld){
1887
ielem = ifield->ielem;
1888
if(ielem && ielem->datalen > 0){
1889
if(ielem->datalen == 1){
1890
save_schar1 = ielem->data[0];
1891
if(sel && !doing_bold){
1892
ielem->data[0] = 'X';
1895
else if(ac && cur && ielem->data[0] == ' ')
1896
ielem->data[0] = '-';
1898
if(ielem->next && ielem->next->datalen){
1899
save_schar2 = ielem->next->data[0];
1900
if(ac && cur && ielem->next->data[0] != '\0')
1901
ielem->next->data[0] = '>';
1904
else if(ielem->datalen > 1){
1905
if(sel && !doing_bold){
1906
ielem->data[0] = 'X';
1909
else if(ac && cur && ielem->data[0] == ' ')
1910
ielem->data[0] = '-';
1912
save_schar2 = ielem->data[1];
1913
if(ac && cur && ielem->data[1] != '\0')
1914
ielem->data[1] = '>';
1918
else if(ifield->ctype == afld && do_arrow && cur){
1920
ielem = ifield->ielem;
1921
if(ielem && ielem->datalen >= ifield->width){
1922
for(i = 0; i < ifield->width-1; i++)
1923
ielem->data[i] = cur ? '-' : ' ';
1925
ielem->data[i] = '>';
1928
else if(ifield->ctype == pfld){
1929
ielem = ifield->ielem;
1930
if(ielem && ielem->datalen > 0){
1931
save_pchar = ielem->data[0];
1932
ielem->data[0] = ice->plus;
1936
/* space between fields */
1937
if(ifield != ice->ifield){
1941
Write_to_screen(" ");
1946
for(ielem = ifield->ielem; ielem; ielem = ielem->next){
1951
bytes_added = utf8_pad_to_width(draw, src,
1952
(n+1) * sizeof(char),
1953
ielem->wid, ifield->leftadj);
1957
* Switch to color for ielem.
1958
* But don't switch if we drew an X in this column,
1959
* because that overwrites the colored thing, and don't
1960
* switch if this is the ARROW field and this is not
1961
* the current message. ARROW field is only colored for
1962
* the current message.
1964
if(ielem->color && pico_is_good_colorpair(ielem->color)
1965
&& !(do_arrow && ifield->ctype == afld && !cur)
1966
&& (!drew_X || ielem != ifield->ielem)){
1967
need_inverse_hack = 0;
1968
(void) pico_set_colorp(ielem->color, PSC_NORM);
1971
need_inverse_hack = 1;
1973
if(need_inverse_hack && inverse_hack)
1976
Write_to_screen(draw);
1977
if(need_inverse_hack && inverse_hack)
1980
(void) pico_set_colorp(base_color, PSC_NORM);
1984
* Restore the data for the special cases.
1987
if(ifield->ctype == sfld){
1988
ielem = ifield->ielem;
1989
if(ielem && ielem->datalen > 0){
1990
if(ielem->datalen == 1){
1991
ielem->data[0] = save_schar1;
1992
if(ielem->next && ielem->next->datalen)
1993
ielem->next->data[0] = save_schar2;
1995
else if(ielem->datalen > 1){
1996
ielem->data[0] = save_schar1;
1997
ielem->data[1] = save_schar2;
2001
else if(ifield->ctype == afld){
2002
ielem = ifield->ielem;
2003
if(ielem && ielem->datalen >= ifield->width)
2004
for(i = 0; i < ifield->width; i++)
2005
ielem->data[i] = ' ';
2007
else if(ifield->ctype == pfld){
2008
ielem = ifield->ielem;
2009
if(ielem && ielem->datalen > 0)
2010
ielem->data[0] = save_pchar;
2017
if(base_color && base_color != lastc && base_color != ice->linecolor)
2018
free_color_pair(&base_color);
2021
(void)pico_set_colorp(lastc, PSC_NORM);
2022
free_color_pair(&lastc);
2027
entry->hilite = cur;
2028
entry->bolded = sel;
2029
entry->msgno = msgno;
2030
entry->plus = ice->plus;
2031
entry->id = ice->id;
2033
if(!ice->color_lookup_done && pico_usingcolor())
2036
return(cur ? (line + HEADER_ROWS(ps_global)) : 0);
2040
* setup_index_state - hooked onto pith_opt_save_index_state to setup
2041
* current_index_state after setup_{index,thread}_header_widths
2044
setup_index_state(int threaded)
2046
if(current_index_state){
2048
current_index_state->status_col = 0;
2049
current_index_state->status_fld = iStatus;
2050
current_index_state->plus_fld = iNothing;
2051
current_index_state->arrow_fld = iNothing;
2054
IndexColType sfld, altfld, plusfld, arrowfld;
2055
int width, fld, col, pluscol, scol, altcol;
2062
/* figure out which field is status field */
2063
for(cdesc = ps_global->index_disp_format, fld = 0;
2064
cdesc->ctype != iNothing;
2066
width = cdesc->width;
2070
/* space between columns */
2074
if(cdesc->ctype == iStatus){
2076
sfld = cdesc->ctype;
2080
if(cdesc->ctype == iFStatus || cdesc->ctype == iIStatus){
2082
sfld = cdesc->ctype;
2086
if(cdesc->ctype == iMessNo){
2088
altfld = cdesc->ctype;
2095
if(sfld == iNothing){
2107
current_index_state->status_col = scol;
2108
current_index_state->status_fld = sfld;
2113
/* figure out which column to use for threading '+' */
2115
&& ps_global->thread_disp_style != THREAD_NONE
2116
&& ps_global->VAR_THREAD_MORE_CHAR[0]
2117
&& ps_global->VAR_THREAD_EXP_CHAR[0])
2118
for(cdesc = ps_global->index_disp_format, fld = 0;
2119
cdesc->ctype != iNothing;
2121
width = cdesc->width;
2125
/* space between columns */
2129
if((cdesc->ctype == iSubject
2130
|| cdesc->ctype == iSubjectText
2131
|| cdesc->ctype == iSubjKey
2132
|| cdesc->ctype == iSubjKeyText
2133
|| cdesc->ctype == iSubjKeyInit
2134
|| cdesc->ctype == iSubjKeyInitText)
2135
&& (ps_global->thread_disp_style == THREAD_STRUCT
2136
|| ps_global->thread_disp_style == THREAD_MUTTLIKE
2137
|| ps_global->thread_disp_style == THREAD_INDENT_SUBJ1
2138
|| ps_global->thread_disp_style == THREAD_INDENT_SUBJ2)){
2139
plusfld = cdesc->ctype;
2144
if((cdesc->ctype == iFrom
2145
|| cdesc->ctype == iFromToNotNews
2146
|| cdesc->ctype == iFromTo
2147
|| cdesc->ctype == iAddress
2148
|| cdesc->ctype == iMailbox)
2149
&& (ps_global->thread_disp_style == THREAD_INDENT_FROM1
2150
|| ps_global->thread_disp_style == THREAD_INDENT_FROM2
2151
|| ps_global->thread_disp_style == THREAD_STRUCT_FROM)){
2152
plusfld = cdesc->ctype;
2161
current_index_state->plus_fld = plusfld;
2162
current_index_state->plus_col = pluscol;
2166
arrowfld = iNothing;
2167
/* figure out which field is arrow field, if any */
2168
for(cdesc = ps_global->index_disp_format, fld = 0;
2169
cdesc->ctype != iNothing;
2171
width = cdesc->width;
2175
if(cdesc->ctype == iArrow){
2176
arrowfld = cdesc->ctype;
2183
current_index_state->arrow_fld = arrowfld;
2190
* insert_condensed_thread_cue - used on pith hook to add decoration to
2191
* subject or from text to show condensed thread info
2194
condensed_thread_cue(PINETHRD_S *thd, ICE_S *ice, char **fieldstr, int width, int collapsed)
2196
if(current_index_state->plus_fld != iNothing && !THRD_INDX() && fieldstr && *fieldstr){
2199
* There is an unwarranted assumption here that VAR_THREAD_MORE_CHAR[0]
2200
* and VAR_THREAD_EXP_CHAR[0] are ascii.
2201
* Could do something similar to the conversions done with keyword
2202
* initials in key_str.
2205
ice->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
2206
: (thd && thd->next)
2207
? ps_global->VAR_THREAD_EXP_CHAR[0] : ' ';
2210
*(*fieldstr)++ = ' ';
2215
*(*fieldstr)++ = ' ';
2225
* paint_index_hline - paint index line given what we got
2228
paint_index_hline(MAILSTREAM *stream, long int msgno, ICE_S *ice)
2233
* Trust only what we get back that isn't bogus since
2234
* we were prevented from doing any fetches and such...
2236
if((ps_global->redrawer == redraw_index_body
2237
|| ps_global->prev_screen == mail_index_screen)
2238
&& current_index_state
2239
&& current_index_state->stream == stream
2240
&& !ps_global->msgmap->hilited){
2244
* This test isn't right if there are hidden lines. The line will
2245
* fail the test because it seems like it is past the end of the
2246
* screen but since the hidden lines don't take up space the line
2247
* might actually be on the screen. Don't know that it is worth
2248
* it to fix this, though, since you may have to file through
2249
* many hidden lines before finding the visible ones. I'm not sure
2250
* if the logic inside the if is correct when we do pass the
2251
* top-level test. Leave it for now. Hubert - 2002-06-28
2253
if((line = (int)(msgno - current_index_state->msg_at_top)) >= 0
2254
&& line < current_index_state->lines_per_page){
2255
if(any_lflagged(ps_global->msgmap, MN_HIDE | MN_CHID)){
2257
long zoomhide, collapsehide;
2259
zoomhide = any_lflagged(ps_global->msgmap, MN_HIDE);
2260
collapsehide = any_lflagged(ps_global->msgmap, MN_CHID);
2263
* Line is visible if it is selected and not hidden due to
2264
* thread collapse, or if there is no zooming happening and
2265
* it is not hidden due to thread collapse.
2267
for(line = 0, n = current_index_state->msg_at_top;
2271
&& get_lflag(stream, current_index_state->msgmap,
2274
|| !get_lflag(stream, current_index_state->msgmap, n,
2278
&& !get_lflag(stream, current_index_state->msgmap,
2285
unsigned long rawno;
2287
rawno = mn_m2raw(current_index_state->msgmap, msgno);
2289
thrd = fetch_thread(stream, rawno);
2292
paint_index_line(ice, line,
2293
(THRD_INDX() && thrd) ? thrd->thrdno : msgno,
2294
current_index_state->status_fld,
2295
current_index_state->plus_fld,
2296
current_index_state->arrow_fld,
2297
¤t_index_state->entry_state[line],
2298
mn_is_cur(current_index_state->msgmap, msgno),
2300
? (count_lflags_in_thread(stream, thrd,
2301
current_index_state->msgmap,
2303
: get_lflag(stream, current_index_state->msgmap,
2314
* pine_imap_env -- C-client's telling us an envelope just arrived
2315
* from the server. Use it if we can...
2318
pine_imap_envelope(MAILSTREAM *stream, long unsigned int rawno, ENVELOPE *env)
2322
dprint((7, "imap_env(%ld)\n", rawno));
2323
if(stream && !sp_mail_box_changed(stream)
2324
&& stream == ps_global->mail_stream
2325
&& rawno > 0L && rawno <= stream->nmsgs
2326
&& (mc = mail_elt(stream,rawno))
2329
&& !get_lflag(stream, NULL, rawno, MN_HIDE | MN_CHID | MN_EXLD)){
2333
memset(&idata, 0, sizeof(INDEXDATA_S));
2335
idata.size = mc->rfc822_size;
2336
idata.rawno = rawno;
2337
idata.msgno = mn_raw2m(sp_msgmap(stream), rawno);
2338
idata.stream = stream;
2340
index_data_env(&idata, env);
2343
* Look for resent-to already in MAILCACHE data
2345
if(mc->private.msg.header.text.data){
2348
static char *linelist[] = {"resent-to" , NULL};
2350
if(mail_match_lines(lines = new_strlst(linelist),
2351
mc->private.msg.lines, 0L)){
2352
idata.valid_resent_to = 1;
2353
memset(&szt, 0, sizeof(SIZEDTEXT));
2354
textcpy(&szt, &mc->private.msg.header.text);
2355
mail_filter((char *) szt.data, szt.size, lines, 0L);
2356
idata.resent_to_us = parsed_resent_to_us((char *) szt.data);
2357
fs_give((void **) &szt.data);
2360
free_strlst(&lines);
2363
ice = (*format_index_line)(&idata);
2367
paint_index_hline(stream, idata.msgno, ice);
2372
/*----------------------------------------------------------------------
2373
Scroll to specified postion.
2376
Args: pos - position to scroll to.
2378
Returns: TRUE - did the scroll operation.
2379
FALSE - was not able to do the scroll operation.
2382
index_scroll_to_pos (long int pos)
2384
static short bad_timing = 0;
2391
* Put the requested line at the top of the screen...
2395
* Starting at msg 'pos' find next visible message.
2397
for(i=pos; i <= mn_get_total(current_index_state->msgmap); i++) {
2398
if(!msgline_hidden(current_index_state->stream,
2399
current_index_state->msgmap, i, 0)){
2400
current_index_state->msg_at_top = i;
2406
* If single selection, move selected message to be on the screen.
2408
if (mn_total_cur(current_index_state->msgmap) == 1L) {
2409
if (current_index_state->msg_at_top >
2410
mn_get_cur (current_index_state->msgmap)) {
2411
/* Selection was above screen, move to top of screen. */
2412
mn_set_cur(current_index_state->msgmap,current_index_state->msg_at_top);
2415
/* Scan through the screen. If selection found, leave where is.
2416
* Otherwise, move to end of screen */
2417
for( i = current_index_state->msg_at_top,
2418
j = current_index_state->lines_per_page;
2419
i != mn_get_cur(current_index_state->msgmap) &&
2420
i <= mn_get_total(current_index_state->msgmap) &&
2423
if(!msgline_hidden(current_index_state->stream,
2424
current_index_state->msgmap, i, 0)){
2430
/* Move to end of screen. */
2431
mn_set_cur(current_index_state->msgmap, k);
2441
/*----------------------------------------------------------------------
2442
Adjust the index display state down a line
2444
Args: scroll_count -- number of lines to scroll
2446
Returns: TRUE - did the scroll operation.
2447
FALSE - was not able to do the scroll operation.
2450
index_scroll_down(long int scroll_count)
2452
static short bad_timing = 0;
2463
total = mn_get_total (current_index_state->msgmap);
2464
for(k = i = current_index_state->msg_at_top; ; i++){
2466
/* Only examine non-hidden messages. */
2467
if(!msgline_hidden(current_index_state->stream,
2468
current_index_state->msgmap, i, 0)){
2469
/* Remember this message */
2471
/* Increment count of lines. */
2472
if (++j >= scroll_count) {
2473
/* Counted enough lines, stop. */
2474
current_index_state->msg_at_top = k;
2479
/* If at last message, stop. */
2481
current_index_state->msg_at_top = k;
2487
* If not multiple selection, see if selected message visable. if not
2488
* set it to last visable message.
2490
if(mn_total_cur(current_index_state->msgmap) == 1L) {
2492
cur = mn_get_cur (current_index_state->msgmap);
2493
for (i = current_index_state->msg_at_top; i <= total; ++i) {
2494
if(!msgline_hidden(current_index_state->stream,
2495
current_index_state->msgmap, i, 0)){
2496
if (++j >= current_index_state->lines_per_page) {
2504
mn_set_cur(current_index_state->msgmap,
2505
current_index_state->msg_at_top);
2514
/*----------------------------------------------------------------------
2515
Adjust the index display state up a line
2517
Args: scroll_count -- number of lines to scroll
2519
Returns: TRUE - did the scroll operation.
2520
FALSE - was not able to do the scroll operation.
2524
index_scroll_up(long int scroll_count)
2526
static short bad_timing = 0;
2536
for(k = i = current_index_state->msg_at_top; ; i--){
2538
/* Only examine non-hidden messages. */
2539
if(!msgline_hidden(current_index_state->stream,
2540
current_index_state->msgmap, i, 0)){
2541
/* Remember this message */
2543
/* Increment count of lines. */
2544
if (++j >= scroll_count) {
2545
/* Counted enough lines, stop. */
2546
current_index_state->msg_at_top = k;
2551
/* If at first message, stop */
2553
current_index_state->msg_at_top = k;
2560
* If not multiple selection, see if selected message visable. if not
2561
* set it to last visable message.
2563
if(mn_total_cur(current_index_state->msgmap) == 1L) {
2565
cur = mn_get_cur (current_index_state->msgmap);
2566
for ( i = current_index_state->msg_at_top;
2567
i <= mn_get_total(current_index_state->msgmap);
2569
if(!msgline_hidden(current_index_state->stream,
2570
current_index_state->msgmap, i, 0)){
2571
if (++j >= current_index_state->lines_per_page) {
2580
mn_set_cur(current_index_state->msgmap, k);
2590
/*----------------------------------------------------------------------
2591
Calculate the message number that should be at the top of the display
2593
Args: current - the current message number
2594
lines_per_page - the number of lines for the body of the index only
2596
Returns: -1 if the current message is -1
2597
the message entry for the first message at the top of the screen.
2599
When paging in the index it is always on even page boundies, and the
2600
current message is always on the page thus the top of the page is
2601
completely determined by the current message and the number of lines
2605
top_ent_calc(MAILSTREAM *stream, MSGNO_S *msgs, long int at_top, long int lines_per_page)
2607
long current, hidden, visible, lastn;
2608
long n, m = 0L, t = 1L;
2610
current = (mn_total_cur(msgs) <= 1L) ? mn_get_cur(msgs) : at_top;
2615
if(lines_per_page == 0L)
2618
if(THRD_INDX_ENABLED()){
2620
PINETHRD_S *thrd = NULL;
2622
rawno = mn_m2raw(msgs, mn_get_cur(msgs));
2624
thrd = fetch_thread(stream, rawno);
2628
if(any_lflagged(msgs, MN_HIDE)){
2630
PINETHRD_S *is_current_thrd;
2632
is_current_thrd = thrd;
2633
if(is_current_thrd){
2634
if(mn_get_revsort(msgs)){
2635
/* start with top of tail of thread list */
2636
thrd = fetch_thread(stream, mn_m2raw(msgs, 1L));
2637
if(thrd && thrd->top && thrd->top != thrd->rawno)
2638
thrd = fetch_thread(stream, thrd->top);
2641
/* start with head of thread list */
2642
thrd = fetch_head_thread(stream);
2648
n = mn_raw2m(msgs, thrd->rawno);
2651
if(!msgline_hidden(stream, msgs, n, 0)
2652
&& (++m % lines_per_page) == 1L)
2655
if(thrd == is_current_thrd)
2658
if(mn_get_revsort(msgs) && thrd->prevthd)
2659
thrd = fetch_thread(stream, thrd->prevthd);
2660
else if(!mn_get_revsort(msgs) && thrd->nextthd)
2661
thrd = fetch_thread(stream, thrd->nextthd);
2666
n = mn_raw2m(msgs, thrd->rawno);
2673
m = lines_per_page * ((n - 1L)/ lines_per_page) + 1L;
2676
* We want to find the m'th thread and the
2677
* message number that goes with that. We just have
2678
* to back up from where we are to get there.
2679
* If we have a reverse sort backing up is going
2680
* forward through the thread.
2682
while(thrd && m < thrd->thrdno){
2684
if(mn_get_revsort(msgs) && thrd->nextthd)
2685
thrd = fetch_thread(stream, thrd->nextthd);
2686
else if(!mn_get_revsort(msgs) && thrd->prevthd)
2687
thrd = fetch_thread(stream, thrd->prevthd);
2695
t = mn_raw2m(msgs, n);
2699
else{ /* viewing a thread */
2701
lastn = mn_get_total(msgs);
2704
/* get top of thread */
2705
if(thrd && thrd->top && thrd->top != thrd->rawno)
2706
thrd = fetch_thread(stream, thrd->top);
2709
if(mn_get_revsort(msgs))
2710
lastn = mn_raw2m(msgs, thrd->rawno);
2712
t = mn_raw2m(msgs, thrd->rawno);
2717
/* n is the end of this thread */
2719
n = mn_raw2m(msgs, thrd->rawno);
2721
thrd = fetch_thread(stream, thrd->branch);
2723
thrd = fetch_thread(stream, thrd->next);
2729
if(mn_get_revsort(msgs))
2735
for(m = 0L, n = t; n <= MIN(current, lastn); n++)
2736
if(!msgline_hidden(stream, msgs, n, 0)
2737
&& (++m % lines_per_page) == 1L)
2743
else if(hidden = any_lflagged(msgs, MN_HIDE | MN_CHID)){
2745
if(current < mn_get_total(msgs) / 2){
2748
for(n = 1L; n <= MIN(current, mn_get_total(msgs)); n++)
2749
if(!msgline_hidden(stream, msgs, n, 0)
2750
&& (++m % lines_per_page) == 1L)
2755
m = mn_get_total(msgs)-hidden+1L;
2756
for(n = mn_get_total(msgs); n >= 1L && t > current; n--)
2757
if(!msgline_hidden(stream, msgs, n, 0)
2758
&& (--m % lines_per_page) == 1L)
2768
return(lines_per_page * ((current - 1L)/ lines_per_page) + 1L);
2772
/*----------------------------------------------------------------------
2773
Clear various bits that make up a healthy display
2777
reset_index_border(void)
2779
mark_status_dirty();
2780
mark_keymenu_dirty();
2781
mark_titlebar_dirty();
2782
ps_global->mangled_screen = 1; /* signal FULL repaint */
2786
/*----------------------------------------------------------------------
2787
This redraws the body of the index screen, taking into
2788
account any change in the size of the screen. All the state needed to
2789
repaint is in the static variables so this can be called from
2793
redraw_index_body(void)
2797
if(agg = (mn_total_cur(current_index_state->msgmap) > 1L))
2798
restore_selected(current_index_state->msgmap);
2800
ps_global->mangled_body = 1;
2802
(void) update_index(ps_global, current_index_state);
2804
pseudo_selected(current_index_state->msgmap);
2808
/*----------------------------------------------------------------------
2809
Give hint about Other command being optional. Some people get the idea
2810
that it is required to use the commands on the 2nd and 3rd keymenus.
2814
Result: message may be printed to status line
2817
warn_other_cmds(void)
2819
static int other_cmds = 0;
2822
if(((ps_global->first_time_user || ps_global->show_new_version) &&
2823
other_cmds % 3 == 0 && other_cmds < 10) || other_cmds % 20 == 0)
2824
q_status_message(SM_ASYNC, 0, 9,
2825
"Remember the \"O\" command is always optional");
2830
thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int preloadkeystroke, int q_line)
2832
PINETHRD_S *thrd = NULL;
2833
unsigned long rawno, save_branch;
2835
int flags = AC_FROM_THREAD;
2837
if(!(stream && msgmap))
2840
rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
2842
thrd = fetch_thread(stream, rawno);
2847
save_branch = thrd->branch;
2848
thrd->branch = 0L; /* branch is a sibling, not part of thread */
2850
if(!preloadkeystroke){
2852
if(get_lflag(stream, NULL, rawno, MN_COLL) && thrd->next)
2858
if(count_lflags_in_thread(stream, thrd, msgmap, MN_SLCT)
2859
== count_lflags_in_thread(stream, thrd, msgmap, MN_NONE))
2863
we_cancel = busy_cue(NULL, NULL, 1);
2865
/* save the SLCT flags in STMP for restoring at the bottom */
2866
copy_lflags(stream, msgmap, MN_SLCT, MN_STMP);
2868
/* clear the values from the SLCT flags */
2869
set_lflags(stream, msgmap, MN_SLCT, 0);
2871
/* set SLCT for thrd on down */
2872
set_flags_for_thread(stream, msgmap, MN_SLCT, thrd, 1);
2873
thrd->branch = save_branch;
2878
(void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
2881
/* restore the original flags */
2882
copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
2884
if(any_lflagged(msgmap, MN_HIDE) > 0L){
2887
/* if nothing left selected, unhide all */
2888
if(any_lflagged(msgmap, MN_SLCT) == 0L){
2889
(void) unzoom_index(ps_global, stream, msgmap);
2890
dprint((4, "\n\n ---- Exiting ZOOM mode ----\n"));
2891
q_status_message(SM_ORDER,0,2, _("Index Zoom Mode is now off"));
2894
/* if current is hidden, adjust */
2895
adjust_cur_to_visible(stream, msgmap);
2900
/*----------------------------------------------------------------------
2901
Search the message headers as displayed in index
2903
Args: command_line -- The screen line to prompt on
2904
msg -- The current message number to start searching at
2905
max_msg -- The largest message number in the current folder
2907
The headers are searched exactly as they are displayed on the screen. The
2908
search will wrap around to the beginning if not string is not found right
2912
index_search(struct pine *state, MAILSTREAM *stream, int command_line, MSGNO_S *msgmap)
2914
int rc, select_all = 0, flags, sectnum;
2915
long i, sorted_msg, selected = 0L;
2916
char prompt[MAX_SEARCH+50], new_string[MAX_SEARCH+1];
2917
char buf[MAX_SCREEN_COLS+1];
2919
static char search_string[MAX_SEARCH+1] = { '\0' };
2921
static ESCKEY_S header_search_key[] = { {0, 0, NULL, NULL },
2922
{ctrl('Y'), 10, "^Y", N_("First Msg")},
2923
{ctrl('V'), 11, "^V", N_("Last Msg")},
2924
{-1, 0, NULL, NULL} };
2926
dprint((4, "\n - search headers - \n"));
2928
if(!any_messages(msgmap, NULL, "to search")){
2931
else if(mn_total_cur(msgmap) > 1L){
2932
q_status_message1(SM_ORDER, 0, 2, "%s msgs selected; Can't search",
2933
comatose(mn_total_cur(msgmap)));
2937
sorted_msg = mn_get_cur(msgmap);
2940
new_string[0] = '\0';
2943
snprintf(prompt, sizeof(prompt), _("Word to search for [%s] : "), search_string);
2945
if(F_ON(F_ENABLE_AGG_OPS, ps_global)){
2946
header_search_key[0].ch = ctrl('X');
2947
header_search_key[0].rval = 12;
2948
header_search_key[0].name = "^X";
2949
header_search_key[0].label = N_("Select Matches");
2952
header_search_key[0].ch = header_search_key[0].rval = 0;
2953
header_search_key[0].name = header_search_key[0].label = NULL;
2956
flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
2958
rc = optionally_enter(new_string, command_line, 0, sizeof(new_string),
2959
prompt, header_search_key, help, &flags);
2962
help = (help != NO_HELP) ? NO_HELP :
2963
F_ON(F_ENABLE_AGG_OPS, ps_global) ? h_os_index_whereis_agg
2964
: h_os_index_whereis;
2968
q_status_message(SM_ORDER, 0, 3, _("Searched to First Message."));
2969
if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
2971
selected = sorted_msg;
2972
mn_dec_cur(stream, msgmap, MH_NONE);
2973
sorted_msg = mn_get_cur(msgmap);
2975
while(selected != sorted_msg);
2978
sorted_msg = (mn_get_total(msgmap) > 0L) ? 1L : 0L;
2980
mn_set_cur(msgmap, sorted_msg);
2984
q_status_message(SM_ORDER, 0, 3, _("Searched to Last Message."));
2985
if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
2987
selected = sorted_msg;
2988
mn_inc_cur(stream, msgmap, MH_NONE);
2989
sorted_msg = mn_get_cur(msgmap);
2991
while(selected != sorted_msg);
2994
sorted_msg = mn_get_total(msgmap);
2996
mn_set_cur(msgmap, sorted_msg);
3004
if(rc != 4) /* redraw */
3008
if(rc == 1 || (new_string[0] == '\0' && search_string[0] == '\0')) {
3009
cmd_cancelled("Search");
3013
if(new_string[0] == '\0'){
3014
strncpy(new_string, search_string, sizeof(new_string));
3015
new_string[sizeof(new_string)-1] = '\0';
3018
strncpy(search_string, new_string, sizeof(search_string));
3019
search_string[sizeof(search_string)-1] = '\0';
3025
for(i = sorted_msg + ((select_all)?0:1);
3026
i <= mn_get_total(msgmap) && !ps_global->intr_pending;
3028
if(msgline_hidden(stream, msgmap, i, 0))
3031
ic = build_header_line(state, stream, msgmap, i, NULL);
3033
ice = (ic && THRD_INDX() && ic->tice) ? ic->tice : ic;
3035
if(srchstr(simple_index_line(buf, sizeof(buf), ps_global->ttyo->screen_cols, ice, i),
3039
set_lflag(stream, msgmap, i, MN_SLCT, 1);
3045
if(i > mn_get_total(msgmap)){
3046
for(i = 1; i < sorted_msg && !ps_global->intr_pending; i++){
3047
if(msgline_hidden(stream, msgmap, i, 0))
3050
ic = build_header_line(state, stream, msgmap, i, NULL);
3052
ice = (ic && THRD_INDX() && ic->tice) ? ic->tice : ic;
3054
if(srchstr(simple_index_line(buf, sizeof(buf), ps_global->ttyo->screen_cols, ice, i),
3058
set_lflag(stream, msgmap, i, MN_SLCT, 1);
3065
if(ps_global->intr_pending){
3066
q_status_message1(SM_ORDER, 0, 3, "Search cancelled.%s",
3067
select_all ? " Selected set may be incomplete.":"");
3069
else if(select_all){
3071
&& any_lflagged(msgmap, MN_SLCT) > 0L
3072
&& !any_lflagged(msgmap, MN_HIDE)
3073
&& F_ON(F_AUTO_ZOOM, state))
3074
(void) zoom_index(state, stream, msgmap);
3076
q_status_message1(SM_ORDER, 0, 3, _("%s messages found matching word"),
3077
long2string(selected));
3080
q_status_message1(SM_ORDER, 0, 3, "Word found%s",
3082
? ". Search wrapped to beginning" : "");
3083
mn_set_cur(msgmap, i);
3086
q_status_message(SM_ORDER, 0, 3, _("Word not found"));
3089
intr_handling_off();
3095
* Original idea from Stephen Casner <casner@acm.org>.
3097
* Apply the appropriate reverse color transformation to the given
3098
* color pair and return a new color pair. The caller should free the
3103
apply_rev_color(COLOR_PAIR *cp, int style)
3105
COLOR_PAIR *rc = pico_get_rev_color();
3108
if(style == IND_COL_REV){
3109
/* just use Reverse color regardless */
3110
return(new_color_pair(rc->fg, rc->bg));
3112
else if(style == IND_COL_FG){
3114
* If changing to Rev fg is readable and different
3115
* from what it already is, do it.
3117
if(strcmp(rc->fg, cp->bg) && strcmp(rc->fg, cp->fg))
3118
return(new_color_pair(rc->fg, cp->bg));
3120
else if(style == IND_COL_BG){
3122
* If changing to Rev bg is readable and different
3123
* from what it already is, do it.
3125
if(strcmp(rc->bg, cp->fg) && strcmp(rc->bg, cp->bg))
3126
return(new_color_pair(cp->fg, rc->bg));
3128
else if(style == IND_COL_FG_NOAMBIG){
3130
* If changing to Rev fg is readable, different
3131
* from what it already is, and not the same as
3132
* the Rev color, do it.
3134
if(strcmp(rc->fg, cp->bg) && strcmp(rc->fg, cp->fg) &&
3135
strcmp(rc->bg, cp->bg))
3136
return(new_color_pair(rc->fg, cp->bg));
3138
else if(style == IND_COL_BG_NOAMBIG){
3140
* If changing to Rev bg is readable, different
3141
* from what it already is, and not the same as
3142
* the Rev color, do it.
3144
if(strcmp(rc->bg, cp->fg) && strcmp(rc->bg, cp->bg) &&
3145
strcmp(rc->fg, cp->fg))
3146
return(new_color_pair(cp->fg, rc->bg));
3150
/* come here for IND_COL_FLIP and for the cases which fail the tests */
3151
return(new_color_pair(cp->bg, cp->fg)); /* flip the colors */
3158
/*----------------------------------------------------------------------
3159
Callback to get the text of the current message. Used to display
3160
a message in an alternate window.
3162
Args: cmd - what type of scroll operation.
3163
text - filled with pointer to text.
3165
style - Returns style of text. Can be:
3166
GETTEXT_TEXT - Is a pointer to text with CRLF deliminated
3168
GETTEXT_LINES - Is a pointer to NULL terminated array of
3169
char *. Each entry points to a line of
3172
this implementation always returns GETTEXT_TEXT.
3174
Returns: TRUE - did the scroll operation.
3175
FALSE - was not able to do the scroll operation.
3178
index_scroll_callback (cmd, scroll_pos)
3185
case MSWIN_KEY_SCROLLUPLINE:
3186
paint = index_scroll_up (scroll_pos);
3189
case MSWIN_KEY_SCROLLDOWNLINE:
3190
paint = index_scroll_down (scroll_pos);
3193
case MSWIN_KEY_SCROLLUPPAGE:
3194
paint = index_scroll_up (current_index_state->lines_per_page);
3197
case MSWIN_KEY_SCROLLDOWNPAGE:
3198
paint = index_scroll_down (current_index_state->lines_per_page);
3201
case MSWIN_KEY_SCROLLTO:
3202
/* Normalize msgno in zoomed case */
3203
if(any_lflagged(ps_global->msgmap, MN_HIDE | MN_CHID)){
3207
x < scroll_pos && n < mn_get_total(ps_global->msgmap);
3209
if(!msgline_hidden(ps_global->mail_stream, ps_global->msgmap,
3213
scroll_pos = n - 1; /* list-position --> message number */
3216
paint = index_scroll_to_pos (scroll_pos + 1);
3221
mswin_beginupdate();
3222
update_titlebar_message();
3223
update_titlebar_status();
3224
redraw_index_body();
3232
/*----------------------------------------------------------------------
3233
MSWin scroll callback to get the text of the current message
3235
Args: title - title for new window
3240
Returns: TRUE - got the requested text
3241
FALSE - was not able to get the requested text
3244
index_gettext_callback(title, titlelen, text, l, style)
3257
if(mn_get_total(ps_global->msgmap) > 0L
3258
&& (so = so_get(CharStar, NULL, WRITE_ACCESS))){
3259
gf_set_so_writec(&pc, so);
3261
if((env = pine_mail_fetchstructure(ps_global->mail_stream,
3262
mn_m2raw(ps_global->msgmap,
3263
mn_get_cur(ps_global->msgmap)),
3265
&& format_message(mn_m2raw(ps_global->msgmap,
3266
mn_get_cur(ps_global->msgmap)),
3267
env, body, NULL, FM_NEW_MESS | FM_UTF8, pc)){
3268
snprintf(title, titlelen, "Folder %s -- Message %ld of %ld",
3269
strsquish(tmp_20k_buf + 500, SIZEOF_20KBUF-500, ps_global->cur_folder, 50),
3270
mn_get_cur(ps_global->msgmap),
3271
mn_get_total(ps_global->msgmap));
3272
title[titlelen-1] = '\0';
3273
*text = so_text(so);
3274
*l = strlen((char *)so_text(so));
3275
*style = GETTEXT_TEXT;
3277
/* free alloc'd so, but preserve the text passed back to caller */
3278
so->txt = (void *) NULL;
3282
gf_clear_so_writec(so);
3294
index_sort_callback(set, order)
3301
sort_folder(ps_global->mail_stream, ps_global->msgmap,
3303
(order & 0x00000100) != 0, SRT_VRB);
3304
mswin_beginupdate();
3305
update_titlebar_message();
3306
update_titlebar_status();
3307
redraw_index_body();
3309
flush_status_messages(1);
3312
i = (int) mn_get_sort(ps_global->msgmap);
3313
if(mn_get_revsort(ps_global->msgmap))
3325
index_popup(stream, msgmap, full)
3333
MPopup view_index_popup[32];
3336
view_index_popup[0].type = tQueue;
3337
view_index_popup[0].label.string = "&View";
3338
view_index_popup[0].label.style = lNormal;
3339
view_index_popup[0].data.val = 'V';
3341
view_index_popup[1].type = tIndex;
3342
view_index_popup[1].label.style = lNormal;
3343
view_index_popup[1].label.string = "View in New Window";
3345
view_index_popup[2].type = tSeparator;
3347
/* Make "delete/undelete" item sensitive */
3348
mc = ((rawno = mn_m2raw(msgmap, mn_get_cur(msgmap))) > 0L
3349
&& stream && rawno <= stream->nmsgs)
3350
? mail_elt(stream, rawno) : NULL;
3351
view_index_popup[3].type = tQueue;
3352
view_index_popup[3].label.style = lNormal;
3353
if(mc && mc->deleted){
3354
view_index_popup[3].label.string = "&Undelete";
3355
view_index_popup[3].data.val = 'U';
3358
view_index_popup[3].label.string = "&Delete";
3359
view_index_popup[3].data.val = 'D';
3362
if(F_ON(F_ENABLE_FLAG, ps_global)){
3363
view_index_popup[4].type = tSubMenu;
3364
view_index_popup[4].label.string = "Flag";
3365
view_index_popup[4].data.submenu = flag_submenu(mc);
3371
view_index_popup[n].type = tQueue;
3372
view_index_popup[n].label.style = lNormal;
3373
view_index_popup[n].label.string = "&Save";
3374
view_index_popup[n++].data.val = 'S';
3376
view_index_popup[n].type = tQueue;
3377
view_index_popup[n].label.style = lNormal;
3378
view_index_popup[n].label.string = "Print";
3379
view_index_popup[n++].data.val = '%';
3381
view_index_popup[n].type = tQueue;
3382
view_index_popup[n].label.style = lNormal;
3383
view_index_popup[n].label.string = "&Reply";
3384
view_index_popup[n++].data.val = 'R';
3386
view_index_popup[n].type = tQueue;
3387
view_index_popup[n].label.style = lNormal;
3388
view_index_popup[n].label.string = "&Forward";
3389
view_index_popup[n++].data.val = 'F';
3391
view_index_popup[n++].type = tSeparator;
3396
view_index_popup[n].type = tQueue;
3397
view_index_popup[n].label.style = lNormal;
3398
view_index_popup[n].label.string = "Folder &List";
3399
view_index_popup[n++].data.val = '<';
3401
view_index_popup[n].type = tQueue;
3402
view_index_popup[n].label.style = lNormal;
3403
view_index_popup[n].label.string = "&Main Menu";
3404
view_index_popup[n++].data.val = 'M';
3406
view_index_popup[n].type = tTail;
3408
if((n = mswin_popup(view_index_popup)) == 1 && full){
3409
char title[GETTEXT_TITLELEN+1];
3414
/* Launch text in alt window. */
3415
if (index_gettext_callback (title, sizeof(title), &text,
3417
if (format == GETTEXT_TEXT)
3418
mswin_displaytext (title, text, (size_t)len, NULL, NULL, MSWIN_DT_USEALTWINDOW);
3419
else if (format == GETTEXT_LINES)
3420
mswin_displaytext (title, NULL, 0, text, NULL, MSWIN_DT_USEALTWINDOW);
3427
pcpine_help_index(title)
3431
* Title is size 256 in pico. Put in args.
3434
strncpy(title, "Alpine MESSAGE INDEX Help", 256);
3436
return(pcpine_help(h_mail_index));
3440
pcpine_help_index_simple(title)
3444
* Title is size 256 in pico. Put in args.
3447
strncpy(title, "Alpine SELECT MESSAGE Help", 256);
3449
return(pcpine_help(h_simple_index));
3454
pcpine_resize_index()
3456
int orig_col = ps_global->ttyo->screen_cols;
3458
reset_index_border();
3459
(void) get_windsize (ps_global->ttyo);
3461
if(orig_col != ps_global->ttyo->screen_cols)
3462
clear_index_cache(ps_global->mail_stream, 0);
3464
mswin_beginupdate();
3465
update_titlebar_message();
3466
update_titlebar_status();
3467
redraw_index_body();
3472
#endif /* _WINDOWS */