~ubuntu-branches/debian/squeeze/alpine/squeeze

« back to all changes in this revision

Viewing changes to alpine/mailindx.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if !defined(lint) && !defined(DOS)
 
2
static char rcsid[] = "$Id: mailindx.c 380 2007-01-23 00:09:18Z hubert@u.washington.edu $";
 
3
#endif
 
4
 
 
5
/*
 
6
 * ========================================================================
 
7
 * Copyright 2006-2007 University of Washington
 
8
 *
 
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
 
12
 *
 
13
 *     http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 * ========================================================================
 
16
 */
 
17
 
 
18
#include "headers.h"
 
19
#include "mailindx.h"
 
20
#include "mailcmd.h"
 
21
#include "status.h"
 
22
#include "context.h"
 
23
#include "keymenu.h"
 
24
#include "alpine.h"
 
25
#include "help.h"
 
26
#include "radio.h"
 
27
#include "titlebar.h"
 
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"
 
40
 
 
41
struct save_thrdinfo {
 
42
    ICE_S    *(*format_index_line)(INDEXDATA_S *);
 
43
    void      (*setup_header_widths)(MAILSTREAM *);
 
44
    unsigned  viewing_a_thread:1;
 
45
};
 
46
 
 
47
 
 
48
static OtherMenu what_keymenu = FirstMenu;
 
49
 
 
50
struct index_state *current_index_state = NULL;
 
51
 
 
52
 
 
53
/*
 
54
 * Internal prototypes
 
55
 */
 
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);
 
70
#ifdef  _WINDOWS
 
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);
 
77
#endif
 
78
 
 
79
 
 
80
 
 
81
/*----------------------------------------------------------------------
 
82
 
 
83
 
 
84
  ----*/
 
85
struct key_menu *
 
86
do_index_border(CONTEXT_S *cntxt, char *folder, MAILSTREAM *stream, MSGNO_S *msgmap, IndexType style, int *which_keys, int flags)
 
87
{
 
88
    struct key_menu *km = (style == ThreadIndex)
 
89
                            ? &thread_keymenu
 
90
                            : (ps_global->mail_stream != stream)
 
91
                              ? &simple_index_keymenu
 
92
                              : &index_keymenu;
 
93
 
 
94
    if(flags & INDX_CLEAR)
 
95
      ClearScreen();
 
96
 
 
97
    if(flags & INDX_HEADER)
 
98
      set_titlebar((style == ThreadIndex)
 
99
                     /* TRANSLATORS: these are some screen titles */
 
100
                     ? _("THREAD INDEX")
 
101
                     : (stream == ps_global->mail_stream)
 
102
                       ? (style == MsgIndex || style == MultiMsgIndex)
 
103
                         ? _("MESSAGE INDEX")
 
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
 
113
                                          : (THREADING()
 
114
                                             && sp_viewing_a_thread(stream))
 
115
                                            ? ThrdMsgNum
 
116
                                            : MessageNumber,
 
117
                   0, 0, NULL);
 
118
 
 
119
    if(flags & INDX_FOOTER) {
 
120
        bitmap_t bitmap;
 
121
        int      cmd;
 
122
 
 
123
        setbitmap(bitmap);
 
124
 
 
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);
 
130
            }
 
131
            else{
 
132
                menu_init_binding(km, '<', MC_FOLDERS, "<",
 
133
                                  N_("FldrList"), BACK_KEY);
 
134
                menu_add_binding(km, ',', MC_FOLDERS);
 
135
            }
 
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);
 
150
 
 
151
            }
 
152
 
 
153
            if(style == MultiMsgIndex){
 
154
                clrbitn(PREVM_KEY, bitmap);
 
155
                clrbitn(NEXTM_KEY, bitmap);
 
156
            }
 
157
        }
 
158
 
 
159
        if(km == &index_keymenu || km == &thread_keymenu){
 
160
            if(IS_NEWS(stream)){
 
161
                km->keys[EXCLUDE_KEY].label = N_("eXclude");
 
162
                KS_OSDATASET(&km->keys[EXCLUDE_KEY], KS_NONE);
 
163
            }
 
164
            else {
 
165
                clrbitn(UNEXCLUDE_KEY, bitmap);
 
166
                km->keys[EXCLUDE_KEY].label = N_("eXpunge");
 
167
                KS_OSDATASET(&km->keys[EXCLUDE_KEY], KS_EXPUNGE);
 
168
            }
 
169
        }
 
170
 
 
171
        if(km != &simple_index_keymenu && !THRD_COLLAPSE_ENABLE())
 
172
          clrbitn(COLLAPSE_KEY, bitmap);
 
173
 
 
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);
 
180
            }
 
181
 
 
182
            if((cmd = menu_clear_binding(km, '>')) != MC_UNKNOWN){
 
183
                menu_add_binding(km, '>', cmd);
 
184
                menu_add_binding(km, KEY_RIGHT, cmd);
 
185
            }
 
186
        }
 
187
 
 
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);
 
192
              else
 
193
                (void) menu_clear_binding(km, '0' + cmd);
 
194
        }
 
195
 
 
196
        draw_keymenu(km, bitmap, ps_global->ttyo->screen_cols,
 
197
                     1-FOOTER_ROWS(ps_global), 0, what_keymenu);
 
198
        what_keymenu = SameMenu;
 
199
        if(which_keys)
 
200
          *which_keys = km->which;  /* pass back to caller */
 
201
    }
 
202
 
 
203
    return(km);
 
204
}
 
205
 
 
206
      
 
207
    
 
208
/*----------------------------------------------------------------------
 
209
        Main loop executing commands for the mail index screen
 
210
 
 
211
   Args: state -- the pine_state structure for next/prev screen pointers
 
212
                  and to pass to the index manager...
 
213
 ----*/
 
214
 
 
215
void
 
216
mail_index_screen(struct pine *state)
 
217
{
 
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;
 
222
        return;
 
223
    }
 
224
 
 
225
    state->prev_screen = mail_index_screen;
 
226
    state->next_screen = SCREEN_FUN_NULL;
 
227
 
 
228
    if(THRD_AUTO_VIEW()
 
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;
 
235
    }
 
236
 
 
237
    adjust_cur_to_visible(state->mail_stream, state->msgmap);
 
238
 
 
239
    if(THRD_INDX())
 
240
      thread_index_screen(state);
 
241
    else
 
242
      index_index_screen(state);
 
243
}
 
244
 
 
245
 
 
246
void
 
247
index_index_screen(struct pine *state)
 
248
{
 
249
    dprint((1, "\n\n ---- MAIL INDEX ----\n"));
 
250
 
 
251
    setup_for_index_index_screen();
 
252
 
 
253
    index_lister(state, state->context_current, state->cur_folder,
 
254
                 state->mail_stream, state->msgmap);
 
255
}
 
256
 
 
257
 
 
258
void
 
259
thread_index_screen(struct pine *state)
 
260
{
 
261
    dprint((1, "\n\n ---- THREAD INDEX ----\n"));
 
262
 
 
263
    setup_for_thread_index_screen();
 
264
 
 
265
    index_lister(state, state->context_current, state->cur_folder,
 
266
                 state->mail_stream, state->msgmap);
 
267
}
 
268
 
 
269
 
 
270
void *
 
271
stop_threading_temporarily(void)
 
272
{
 
273
    struct save_thrdinfo *ti;
 
274
 
 
275
    ps_global->turn_off_threading_temporarily = 1;
 
276
 
 
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);
 
281
 
 
282
    setup_for_index_index_screen();
 
283
 
 
284
    return((void *) ti);
 
285
}
 
286
 
 
287
 
 
288
void
 
289
restore_threading(void **p)
 
290
{
 
291
    struct save_thrdinfo *ti;
 
292
 
 
293
    ps_global->turn_off_threading_temporarily = 0;
 
294
 
 
295
    if(p && *p){
 
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);
 
300
 
 
301
        fs_give(p);
 
302
    }
 
303
}
 
304
 
 
305
 
 
306
/*----------------------------------------------------------------------
 
307
        Main loop executing commands for the mail index screen
 
308
 
 
309
   Args: state -- pine_state structure for display flags and such
 
310
         msgmap -- c-client/pine message number mapping struct
 
311
 ----*/
 
312
 
 
313
int
 
314
index_lister(struct pine *state, CONTEXT_S *cntxt, char *folder, MAILSTREAM *stream, MSGNO_S *msgmap)
 
315
{
 
316
    UCS          ch;
 
317
    int          cmd, which_keys, force,
 
318
                 cur_row, cur_col, km_popped, paint_status;
 
319
    int          old_day = -1;
 
320
    long         i, j, k, old_max_msgno;
 
321
    char        *utf8str;
 
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)(); */
 
327
#endif
 
328
 
 
329
    dprint((1, "\n\n ---- INDEX MANAGER ----\n"));
 
330
    
 
331
    ch                    = 'x';        /* For displaying msg 1st time thru */
 
332
    force                 = 0;
 
333
    km_popped             = 0;
 
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;
 
339
    id.msgmap             = msgmap;
 
340
    if(msgmap->top != 0L)
 
341
      id.msg_at_top = msgmap->top;
 
342
 
 
343
    id.stream = stream;
 
344
    set_need_format_setup(stream);
 
345
 
 
346
    while (1) {
 
347
        ps_global->user_says_cancel = 0;
 
348
 
 
349
        if(km_popped){
 
350
            km_popped--;
 
351
            if(km_popped == 0){
 
352
                clearfooter(state);
 
353
                if(!state->mangled_body
 
354
                   && id.entry_state
 
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;
 
358
                }
 
359
                else
 
360
                  state->mangled_body = 1;
 
361
            }
 
362
        }
 
363
 
 
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 */
 
367
 
 
368
        /*
 
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.
 
372
         */
 
373
 
 
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;
 
380
        }
 
381
 
 
382
        old_max_msgno = mn_get_total(msgmap);
 
383
 
 
384
        /*
 
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.
 
389
         */
 
390
        if(format_includes_smartdate(stream)){
 
391
            char        db[200];
 
392
            struct date nnow;
 
393
 
 
394
            rfc822_date(db);
 
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;
 
399
            }
 
400
 
 
401
            old_day = nnow.day;
 
402
        }
 
403
 
 
404
        if(streams_died())
 
405
          state->mangled_header = 1;
 
406
 
 
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;
 
412
        }
 
413
 
 
414
        /*
 
415
         * events may have occured that require us to shift from
 
416
         * mode to another...
 
417
         */
 
418
        style = THRD_INDX()
 
419
                  ? ThreadIndex
 
420
                  : (any_lflagged(msgmap, MN_HIDE))
 
421
                    ? ZoomIndex
 
422
                    : (mn_total_cur(msgmap) > 1L) ? MultiMsgIndex : MsgIndex;
 
423
        if(style != old_style){
 
424
            state->mangled_header = 1;
 
425
            state->mangled_footer = 1;
 
426
            old_style = style;
 
427
            if(!(style == ThreadIndex || old_style == ThreadIndex))
 
428
              id.msg_at_top = 0L;
 
429
        }
 
430
 
 
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;
 
436
            paint_status = 0;
 
437
        } 
 
438
        else if(mn_get_total(msgmap) > 0) {
 
439
            update_titlebar_message();
 
440
            /*
 
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!)...
 
444
             */
 
445
            paint_status = !update_titlebar_status();
 
446
        }
 
447
 
 
448
        current_index_state = &id;
 
449
 
 
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);
 
454
            cur_col = 0;
 
455
        }
 
456
        else if(id.status_col >= 0)
 
457
          cur_col = MIN(id.status_col, state->ttyo->screen_cols-1);
 
458
 
 
459
        ps_global->redrawer = redraw_index_body;
 
460
 
 
461
        if(paint_status)
 
462
          (void) update_titlebar_status();
 
463
 
 
464
        /*------------ draw the footer/key menus ---------------*/
 
465
        if(state->mangled_footer) {
 
466
            if(!state->painted_footer_on_startup){
 
467
                if(km_popped){
 
468
                    FOOTER_ROWS(state) = 3;
 
469
                    clearfooter(state);
 
470
                }
 
471
 
 
472
                km = do_index_border(cntxt, folder, stream, msgmap, style,
 
473
                                     &which_keys, INDX_FOOTER);
 
474
                if(km_popped){
 
475
                    FOOTER_ROWS(state) = 1;
 
476
                    mark_keymenu_dirty();
 
477
                }
 
478
            }
 
479
 
 
480
            state->mangled_footer = 0;
 
481
        }
 
482
 
 
483
        state->painted_body_on_startup   = 0;
 
484
        state->painted_footer_on_startup = 0;
 
485
 
 
486
        /*-- Display any queued message (eg, new mail, command result --*/
 
487
        if(km_popped){
 
488
            FOOTER_ROWS(state) = 3;
 
489
            mark_status_unknown();
 
490
        }
 
491
 
 
492
        display_message(ch);
 
493
        if(km_popped){
 
494
            FOOTER_ROWS(state) = 1;
 
495
            mark_status_unknown();
 
496
        }
 
497
 
 
498
        if(F_ON(F_SHOW_CURSOR, state) && cur_row < 0){
 
499
            cur_row = state->ttyo->screen_rows - FOOTER_ROWS(state);
 
500
        }
 
501
 
 
502
        cur_row = MIN(MAX(cur_row, 0), state->ttyo->screen_rows-1);
 
503
        MoveCursor(cur_row, cur_col);
 
504
 
 
505
        /* Let read_command do the fflush(stdout) */
 
506
 
 
507
        /*---------- Read command and validate it ----------------*/
 
508
#ifdef  MOUSE
 
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);
 
513
#endif
 
514
#if defined(DOS) || defined(OS2)
 
515
        /*
 
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.
 
519
         */
 
520
        /* while_waiting = build_header_cache; */
 
521
#ifdef  _WINDOWS
 
522
        /* while_waiting = NULL; */
 
523
        mswin_setscrollcallback (index_scroll_callback);
 
524
        mswin_sethelptextcallback((stream == state->mail_stream)
 
525
                                    ? pcpine_help_index
 
526
                                    : pcpine_help_index_simple);
 
527
        mswin_setresizecallback(pcpine_resize_index);
 
528
#endif
 
529
#endif
 
530
        ch = read_command(&utf8str);
 
531
#ifdef  MOUSE
 
532
        clear_mfunc(mouse_in_content);
 
533
#endif
 
534
#if defined(DOS) || defined(OS2)
 
535
        /* while_waiting = NULL; */
 
536
#ifdef  _WINDOWS
 
537
        mswin_setscrollcallback(NULL);
 
538
        mswin_sethelptextcallback(NULL);
 
539
        mswin_clearresizecallback(pcpine_resize_index);
 
540
#endif
 
541
#endif
 
542
 
 
543
        cmd = menu_command(ch, km);
 
544
 
 
545
        if(km_popped)
 
546
          switch(cmd){
 
547
            case MC_NONE :
 
548
            case MC_OTHER :
 
549
            case MC_RESIZE :
 
550
            case MC_REPAINT :
 
551
              km_popped++;
 
552
              break;
 
553
 
 
554
            default:
 
555
              clearfooter(state);
 
556
              break;
 
557
          }
 
558
 
 
559
        /*----------- Execute the command ------------------*/
 
560
        switch(cmd){
 
561
 
 
562
            /*---------- Roll keymenu ----------*/
 
563
          case MC_OTHER :
 
564
            if(F_OFF(F_USE_FK, ps_global))
 
565
              warn_other_cmds();
 
566
 
 
567
            what_keymenu = NextMenu;
 
568
            state->mangled_footer = 1;
 
569
            break;
 
570
 
 
571
 
 
572
            /*---------- Scroll line up ----------*/
 
573
          case MC_CHARUP :
 
574
            (void) process_cmd(state, stream, msgmap, MC_PREVITEM,
 
575
                               (style == MsgIndex
 
576
                                || style == MultiMsgIndex
 
577
                                || style == ZoomIndex)
 
578
                                   ? MsgIndx
 
579
                                   : (style == ThreadIndex)
 
580
                                     ? ThrdIndx
 
581
                                     : View,
 
582
                               &force);
 
583
            if(mn_get_cur(msgmap) < (id.msg_at_top + HS_MARGIN(state)))
 
584
              index_scroll_up(1L);
 
585
 
 
586
            break;
 
587
 
 
588
 
 
589
            /*---------- Scroll line down ----------*/
 
590
          case MC_CHARDOWN :
 
591
            /*
 
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()...
 
596
             */
 
597
            (void) process_cmd(state, stream, msgmap, MC_NEXTITEM,
 
598
                               (style == MsgIndex
 
599
                                || style == MultiMsgIndex
 
600
                                || style == ZoomIndex)
 
601
                                   ? MsgIndx
 
602
                                   : (style == ThreadIndex)
 
603
                                     ? ThrdIndx
 
604
                                     : View,
 
605
                               &force);
 
606
            for(j = 0L, k = i = id.msg_at_top; ; i++){
 
607
                if(!msgline_hidden(stream, msgmap, i, 0)){
 
608
                    k = i;
 
609
                    if(j++ >= id.lines_per_page)
 
610
                      break;
 
611
                }
 
612
 
 
613
                if(i >= mn_get_total(msgmap)){
 
614
                    k = 0L;             /* don't scroll */
 
615
                    break;
 
616
                }
 
617
            }
 
618
 
 
619
            if(k && (mn_get_cur(msgmap) + HS_MARGIN(state)) >= k)
 
620
              index_scroll_down(1L);
 
621
 
 
622
            break;
 
623
 
 
624
 
 
625
            /*---------- Scroll page up ----------*/
 
626
          case MC_PAGEUP :
 
627
            j = -1L;
 
628
            for(k = i = id.msg_at_top; ; i--){
 
629
                if(!msgline_hidden(stream, msgmap, i, 0)){
 
630
                    k = i;
 
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"));
 
634
 
 
635
                        break;
 
636
                    }
 
637
                }
 
638
 
 
639
                if(i <= 1L){
 
640
                    if((!THREADING() && mn_get_cur(msgmap) == 1L)
 
641
                       || (THREADING()
 
642
                           && mn_get_cur(msgmap) == first_sorted_flagged(F_NONE,
 
643
                                                                         stream,
 
644
                                                                         0L,
 
645
                                                                FSF_SKIP_CHID)))
 
646
                      q_status_message(SM_ORDER, 0, 1,
 
647
                          _("Already at start of Index"));
 
648
 
 
649
                    break;
 
650
                }
 
651
            }
 
652
 
 
653
            if(mn_get_total(msgmap) > 0L && mn_total_cur(msgmap) == 1L)
 
654
              mn_set_cur(msgmap, k);
 
655
 
 
656
            break;
 
657
 
 
658
 
 
659
            /*---------- Scroll page forward ----------*/
 
660
          case MC_PAGEDN :
 
661
            j = -1L;
 
662
            for(k = i = id.msg_at_top; ; i++){
 
663
                if(!msgline_hidden(stream, msgmap, i, 0)){
 
664
                    k = i;
 
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"));
 
668
 
 
669
                        id.msg_at_top = i;
 
670
                        break;
 
671
                    }
 
672
                }
 
673
 
 
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"));
 
677
 
 
678
                    break;
 
679
                }
 
680
            }
 
681
 
 
682
            if(mn_get_total(msgmap) > 0L && mn_total_cur(msgmap) == 1L)
 
683
              mn_set_cur(msgmap, k);
 
684
 
 
685
            break;
 
686
 
 
687
 
 
688
            /*---------- Scroll to first page ----------*/
 
689
          case MC_HOMEKEY :
 
690
            if((mn_get_total(msgmap) > 0L)
 
691
               && (mn_total_cur(msgmap) <= 1L)){
 
692
                long cur_msg = mn_get_cur(msgmap), selected;
 
693
 
 
694
                if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
 
695
                    do {
 
696
                        selected = cur_msg;
 
697
                        mn_dec_cur(stream, msgmap, MH_NONE);
 
698
                        cur_msg = mn_get_cur(msgmap);
 
699
                    }
 
700
                    while(selected != cur_msg);
 
701
                }
 
702
                else
 
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"));
 
706
            }
 
707
            break;
 
708
 
 
709
            /*---------- Scroll to last page ----------*/
 
710
          case MC_ENDKEY :
 
711
            if((mn_get_total(msgmap) > 0L)
 
712
               && (mn_total_cur(msgmap) <= 1L)){
 
713
                long cur_msg = mn_get_cur(msgmap), selected;
 
714
 
 
715
                if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
 
716
                    do {
 
717
                        selected = cur_msg;
 
718
                        mn_inc_cur(stream, msgmap, MH_NONE);
 
719
                        cur_msg = mn_get_cur(msgmap);
 
720
                    }
 
721
                    while(selected != cur_msg);
 
722
                }
 
723
                else
 
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"));
 
727
            }
 
728
            break;
 
729
 
 
730
            /*---------- Search (where is command) ----------*/
 
731
          case MC_WHEREIS :
 
732
            index_search(state, stream, -FOOTER_ROWS(ps_global), msgmap);
 
733
            state->mangled_footer = 1;
 
734
            break;
 
735
 
 
736
 
 
737
            /*-------------- jump command -------------*/
 
738
            /* NOTE: preempt the process_cmd() version because
 
739
             *       we need to get at the number..
 
740
             */
 
741
          case MC_JUMP :
 
742
            j = jump_to(msgmap, -FOOTER_ROWS(ps_global), ch, NULL,
 
743
                        (style == ThreadIndex) ? ThrdIndx : MsgIndx);
 
744
            if(j > 0L){
 
745
                if(style == ThreadIndex){
 
746
                    PINETHRD_S *thrd;
 
747
 
 
748
                    thrd = find_thread_by_number(stream, msgmap, j, NULL);
 
749
 
 
750
                    if(thrd && thrd->rawno)
 
751
                      mn_set_cur(msgmap, mn_raw2m(msgmap, thrd->rawno));
 
752
                }
 
753
                else{
 
754
                    /* jump to message */
 
755
                    if(mn_total_cur(msgmap) > 1L){
 
756
                        mn_reset_cur(msgmap, j);
 
757
                    }
 
758
                    else{
 
759
                        mn_set_cur(msgmap, j);
 
760
                    }
 
761
                }
 
762
 
 
763
                id.msg_at_top = 0L;
 
764
            }
 
765
 
 
766
            state->mangled_footer = 1;
 
767
            break;
 
768
 
 
769
 
 
770
          case MC_VIEW_ENTRY :          /* only happens in thread index */
 
771
 
 
772
            /*
 
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.
 
776
             */
 
777
view_a_thread:
 
778
            if(THRD_AUTO_VIEW() && style == ThreadIndex){
 
779
                PINETHRD_S *thrd;
 
780
 
 
781
                thrd = fetch_thread(stream,
 
782
                                    mn_m2raw(msgmap, mn_get_cur(msgmap)));
 
783
                if(thrd
 
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;
 
788
                        cmd = MC_VIEW_TEXT;
 
789
                        goto do_the_default;
 
790
                    }
 
791
                }
 
792
            }
 
793
 
 
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;
 
798
                if(id.entry_state)
 
799
                  fs_give((void **)&(id.entry_state));
 
800
 
 
801
                return(0);
 
802
            }
 
803
 
 
804
            break;
 
805
 
 
806
 
 
807
          case MC_THRDINDX :
 
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;
 
815
                if(id.entry_state)
 
816
                  fs_give((void **)&(id.entry_state));
 
817
 
 
818
                return(0);
 
819
            }
 
820
 
 
821
            break;
 
822
 
 
823
 
 
824
#ifdef MOUSE        
 
825
          case MC_MOUSE:
 
826
            {
 
827
              MOUSEPRESS mp;
 
828
              int        new_cur;
 
829
 
 
830
              mouse_get_last (NULL, &mp);
 
831
              mp.row -= 2;
 
832
 
 
833
              for(i = id.msg_at_top;
 
834
                  mp.row >= 0 && i <= mn_get_total(msgmap);
 
835
                  i++)
 
836
                if(!msgline_hidden(stream, msgmap, i, 0)){
 
837
                    mp.row--;
 
838
                    new_cur = i;
 
839
                }
 
840
 
 
841
              if(mn_get_total(msgmap) && mp.row < 0){
 
842
                  switch(mp.button){
 
843
                    case M_BUTTON_LEFT :
 
844
                      if(mn_total_cur(msgmap) == 1L)
 
845
                        mn_set_cur(msgmap, new_cur);
 
846
 
 
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);
 
850
                          }
 
851
                      }
 
852
                      else if(!(mp.flags & M_KEY_SHIFT)){
 
853
                          if (THREADING()
 
854
                              && mp.col >= 0
 
855
                              && mp.col == id.plus_col
 
856
                              && style != ThreadIndex){
 
857
                              collapse_or_expand(state, stream, msgmap,
 
858
                                                 mn_get_cur(msgmap));
 
859
                          }
 
860
                          else if (mp.doubleclick){
 
861
                              if(mp.button == M_BUTTON_LEFT){
 
862
                                  if(stream == state->mail_stream){
 
863
                                      if(THRD_INDX()){
 
864
                                          cmd = MC_VIEW_ENTRY;
 
865
                                          goto view_a_thread;
 
866
                                      }
 
867
                                      else{
 
868
                                          cmd = MC_VIEW_TEXT;
 
869
                                          goto do_the_default;
 
870
                                      }
 
871
                                  }
 
872
 
 
873
                                  ps_global->redrawer = NULL;
 
874
                                  current_index_state = NULL;
 
875
                                  if(id.entry_state)
 
876
                                    fs_give((void **)&(id.entry_state));
 
877
 
 
878
                                  return(0);
 
879
                              }
 
880
                          }
 
881
                      }
 
882
 
 
883
                      break;
 
884
 
 
885
                    case M_BUTTON_MIDDLE:
 
886
                      break;
 
887
 
 
888
                    case M_BUTTON_RIGHT :
 
889
#ifdef _WINDOWS
 
890
                      if (!mp.doubleclick){
 
891
                          if(mn_total_cur(msgmap) == 1L)
 
892
                            mn_set_cur(msgmap, new_cur);
 
893
 
 
894
                          cur_row = update_index(state, &id);
 
895
 
 
896
                          index_popup(stream, msgmap, TRUE);
 
897
                      }
 
898
#endif
 
899
                      break;
 
900
                  }
 
901
              }
 
902
              else{
 
903
                  switch(mp.button){
 
904
                    case M_BUTTON_LEFT :
 
905
                      break;
 
906
 
 
907
                    case M_BUTTON_MIDDLE :
 
908
                      break;
 
909
 
 
910
                    case M_BUTTON_RIGHT :
 
911
#ifdef  _WINDOWS
 
912
                      index_popup(stream, msgmap, FALSE);
 
913
#endif
 
914
                      break;
 
915
                  }
 
916
              }
 
917
            }
 
918
 
 
919
            break;
 
920
#endif  /* MOUSE */
 
921
 
 
922
            /*---------- Resize ----------*/
 
923
          case MC_RESIZE:
 
924
            /*
 
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
 
931
             * selectively.
 
932
             */
 
933
            clear_index_cache(stream, 0);
 
934
            reset_index_border();
 
935
            break;
 
936
 
 
937
 
 
938
            /*---------- Redraw ----------*/
 
939
          case MC_REPAINT :
 
940
            force = 1;                  /* check for new mail! */
 
941
            reset_index_border();
 
942
            break;
 
943
 
 
944
 
 
945
            /*---------- No op command ----------*/
 
946
          case MC_NONE :
 
947
            break;      /* no op check for new mail */
 
948
 
 
949
 
 
950
            /*--------- keystroke not bound to command --------*/
 
951
          case MC_CHARRIGHT :
 
952
          case MC_CHARLEFT :
 
953
          case MC_GOTOBOL :
 
954
          case MC_GOTOEOL :
 
955
          case MC_UNKNOWN :
 
956
            bogus_command(ch, F_ON(F_USE_FK,state) ? "F1" : "?");
 
957
            break;
 
958
 
 
959
 
 
960
          case MC_COLLAPSE :
 
961
            thread_command(state, stream, msgmap, ch, -FOOTER_ROWS(state));
 
962
            break;
 
963
 
 
964
          case MC_DELETE :
 
965
          case MC_UNDELETE :
 
966
          case MC_REPLY :
 
967
          case MC_FORWARD :
 
968
          case MC_TAKE :
 
969
          case MC_SAVE :
 
970
          case MC_EXPORT :
 
971
          case MC_BOUNCE :
 
972
          case MC_PIPE :
 
973
          case MC_FLAG :
 
974
          case MC_SELCUR :
 
975
            { int collapsed = 0;
 
976
              unsigned long rawno;
 
977
              PINETHRD_S *thrd = NULL;
 
978
 
 
979
              if(THREADING()){
 
980
                  rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
 
981
                  if(rawno)
 
982
                    thrd = fetch_thread(stream, rawno);
 
983
 
 
984
                  collapsed = thrd && thrd->next
 
985
                              && get_lflag(stream, NULL, rawno, MN_COLL);
 
986
              }
 
987
 
 
988
              if(collapsed){
 
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,
 
994
                                               (style == MsgIndex
 
995
                                                  || style == MultiMsgIndex
 
996
                                                  || style == ZoomIndex)
 
997
                                                    ? MsgIndx
 
998
                                                    : (style == ThreadIndex)
 
999
                                                      ? ThrdIndx
 
1000
                                                      : View);
 
1001
                  }
 
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
 
1006
                              && cmd == MC_SAVE
 
1007
                              && F_ON(F_SAVE_ADVANCES, state))){
 
1008
                      mn_inc_cur(stream, msgmap, MH_NONE);
 
1009
                  }
 
1010
              }
 
1011
              else
 
1012
                goto do_the_default;
 
1013
            }
 
1014
 
 
1015
            break;
 
1016
 
 
1017
 
 
1018
          case MC_UTF8:
 
1019
            bogus_utf8_command(utf8str, NULL);
 
1020
            break;
 
1021
 
 
1022
 
 
1023
            /*---------- First HELP command with menu hidden ----------*/
 
1024
          case MC_HELP :
 
1025
            if(FOOTER_ROWS(state) == 1 && km_popped == 0){
 
1026
                km_popped = 2;
 
1027
                mark_status_unknown();
 
1028
                mark_keymenu_dirty();
 
1029
                state->mangled_footer = 1;
 
1030
                break;
 
1031
            }
 
1032
            /* else fall thru to normal default */
 
1033
 
 
1034
 
 
1035
            /*---------- Default -- all other command ----------*/
 
1036
          default:
 
1037
   do_the_default:
 
1038
            if(stream == state->mail_stream){
 
1039
                msgmap->top = id.msg_at_top;
 
1040
                process_cmd(state, stream, msgmap, cmd,
 
1041
                            (style == MsgIndex
 
1042
                             || style == MultiMsgIndex
 
1043
                             || style == ZoomIndex)
 
1044
                               ? MsgIndx
 
1045
                               : (style == ThreadIndex)
 
1046
                                 ? ThrdIndx
 
1047
                                 : View,
 
1048
                            &force);
 
1049
                if(state->next_screen != SCREEN_FUN_NULL){
 
1050
                    ps_global->redrawer = NULL;
 
1051
                    current_index_state = NULL;
 
1052
                    if(id.entry_state)
 
1053
                      fs_give((void **)&(id.entry_state));
 
1054
 
 
1055
                    return(0);
 
1056
                }
 
1057
                else{
 
1058
                    if(stream != state->mail_stream){
 
1059
                        /*
 
1060
                         * Must have had an failed open.  repair our
 
1061
                         * pointers...
 
1062
                         */
 
1063
                        id.stream = stream = state->mail_stream;
 
1064
                        id.msgmap = msgmap = state->msgmap;
 
1065
                    }
 
1066
 
 
1067
                    current_index_state = &id;
 
1068
 
 
1069
                    if(cmd == MC_ZOOM && THRD_INDX())
 
1070
                      id.msg_at_top = 0L;
 
1071
                }
 
1072
            }
 
1073
            else{                       /* special processing */
 
1074
                switch(cmd){
 
1075
                  case MC_HELP :
 
1076
                    helper(h_simple_index,
 
1077
                           (!strcmp(folder, INTERRUPTED_MAIL))
 
1078
                             ? _("HELP FOR SELECTING INTERRUPTED MSG")
 
1079
                             : _("HELP FOR SELECTING POSTPONED MSG"),
 
1080
                           HLPD_SIMPLE);
 
1081
                    state->mangled_screen = 1;
 
1082
                    break;
 
1083
 
 
1084
                  case MC_DELETE :      /* delete */
 
1085
                    dprint((3, "Special delete: msg %s\n",
 
1086
                              long2string(mn_get_cur(msgmap))));
 
1087
                    {
 
1088
                        long          raw, t;
 
1089
                        int           del = 0;
 
1090
                        MESSAGECACHE *mc;
 
1091
 
 
1092
                        raw = mn_m2raw(msgmap, mn_get_cur(msgmap));
 
1093
                        if(raw > 0L && stream
 
1094
                           && raw <= stream->nmsgs
 
1095
                           && (mc = mail_elt(stream, raw))
 
1096
                           && !mc->deleted){
 
1097
                            if((t = mn_get_cur(msgmap)) > 0L)
 
1098
                              clear_index_cache_ent(stream, t, 0);
 
1099
 
 
1100
                            mail_setflag(stream,long2string(raw),"\\DELETED");
 
1101
                            update_titlebar_status();
 
1102
                            del++;
 
1103
                        }
 
1104
 
 
1105
                        q_status_message1(SM_ORDER, 0, 1,
 
1106
                                          del ? _("Message %s deleted") : _("Message %s already deleted"),
 
1107
                                          long2string(mn_get_cur(msgmap)));
 
1108
                    }
 
1109
 
 
1110
                    break;
 
1111
 
 
1112
                  case MC_UNDELETE :    /* UNdelete */
 
1113
                    dprint((3, "Special UNdelete: msg %s\n",
 
1114
                              long2string(mn_get_cur(msgmap))));
 
1115
                    {
 
1116
                        long          raw, t;
 
1117
                        int           del = 0;
 
1118
                        MESSAGECACHE *mc;
 
1119
 
 
1120
                        raw = mn_m2raw(msgmap, mn_get_cur(msgmap));
 
1121
                        if(raw > 0L && stream
 
1122
                           && raw <= stream->nmsgs
 
1123
                           && (mc = mail_elt(stream, raw))
 
1124
                           && mc->deleted){
 
1125
                            if((t = mn_get_cur(msgmap)) > 0L)
 
1126
                              clear_index_cache_ent(stream, t, 0);
 
1127
 
 
1128
                            mail_clearflag(stream, long2string(raw),
 
1129
                                           "\\DELETED");
 
1130
                            update_titlebar_status();
 
1131
                            del++;
 
1132
                        }
 
1133
 
 
1134
                        q_status_message1(SM_ORDER, 0, 1,
 
1135
                                          del ? _("Message %s UNdeleted") : _("Message %s NOT deleted"),
 
1136
                                          long2string(mn_get_cur(msgmap)));
 
1137
                    }
 
1138
 
 
1139
                    break;
 
1140
 
 
1141
                  case MC_EXIT :        /* exit */
 
1142
                    ps_global->redrawer = NULL;
 
1143
                    current_index_state = NULL;
 
1144
                    if(id.entry_state)
 
1145
                      fs_give((void **)&(id.entry_state));
 
1146
 
 
1147
                    return(1);
 
1148
 
 
1149
                  case MC_SELECT :      /* select */
 
1150
                    ps_global->redrawer = NULL;
 
1151
                    current_index_state = NULL;
 
1152
                    if(id.entry_state)
 
1153
                      fs_give((void **)&(id.entry_state));
 
1154
 
 
1155
                    return(0);
 
1156
 
 
1157
                  case MC_PREVITEM :            /* previous */
 
1158
                    mn_dec_cur(stream, msgmap, MH_NONE);
 
1159
                    break;
 
1160
 
 
1161
                  case MC_NEXTITEM :            /* next */
 
1162
                    mn_inc_cur(stream, msgmap, MH_NONE);
 
1163
                    break;
 
1164
 
 
1165
                  default :
 
1166
                    bogus_command(ch, NULL);
 
1167
                    break;
 
1168
                }
 
1169
            }
 
1170
        }                               /* The big switch */
 
1171
    }                                   /* the BIG while loop! */
 
1172
}
 
1173
 
 
1174
 
 
1175
 
 
1176
/*----------------------------------------------------------------------
 
1177
  Manage index body painting
 
1178
 
 
1179
  Args: state - pine struct containing selected message data
 
1180
        index_state - struct describing what's currently displayed
 
1181
 
 
1182
  Returns: screen row number of first highlighted message
 
1183
 
 
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?
 
1188
 ----*/
 
1189
int
 
1190
update_index(struct pine *state, struct index_state *screen)
 
1191
{
 
1192
    int  i, retval = -1, row, already_fetched = 0;
 
1193
    long n, visible;
 
1194
    PINETHRD_S *thrd = NULL;
 
1195
 
 
1196
    dprint((7, "--update_index--\n"));
 
1197
 
 
1198
    if(!screen)
 
1199
      return(-1);
 
1200
    
 
1201
#ifdef _WINDOWS
 
1202
    mswin_beginupdate();
 
1203
#endif
 
1204
 
 
1205
    /*---- reset the works if necessary ----*/
 
1206
    if(state->mangled_body){
 
1207
        ClearBody();
 
1208
        if(screen->entry_state){
 
1209
            fs_give((void **)&(screen->entry_state));
 
1210
            screen->lines_per_page = 0;
 
1211
        }
 
1212
    }
 
1213
 
 
1214
    state->mangled_body = 0;
 
1215
 
 
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));
 
1224
        if(!i){
 
1225
            size_t len = screen->lines_per_page * sizeof(struct entry_state);
 
1226
            screen->entry_state = (struct entry_state *) fs_get(len);
 
1227
        }
 
1228
        else
 
1229
          fs_resize((void **)&(screen->entry_state),
 
1230
                    (size_t)screen->lines_per_page);
 
1231
 
 
1232
        for(; i < screen->lines_per_page; i++)  /* init new entries */
 
1233
          screen->entry_state[i].id = 0;
 
1234
    }
 
1235
 
 
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,
 
1240
                                          screen->msg_at_top,
 
1241
                                          screen->lines_per_page);
 
1242
    }
 
1243
    else if(mn_get_cur(screen->msgmap) < screen->msg_at_top){
 
1244
        long i, j, k;
 
1245
 
 
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;
 
1249
                i > 0L && j > 0L;
 
1250
                j--)
 
1251
              if(!msgline_hidden(screen->stream, screen->msgmap, j, 0)){
 
1252
                  k = j;
 
1253
                  i--;
 
1254
              }
 
1255
 
 
1256
            if(i == screen->lines_per_page)
 
1257
              break;                            /* can't scroll back ? */
 
1258
            else
 
1259
              screen->msg_at_top = k;
 
1260
        }
 
1261
    }
 
1262
    else if(mn_get_cur(screen->msgmap) >= screen->msg_at_top
 
1263
                                                     + screen->lines_per_page){
 
1264
        long i, j, k;
 
1265
 
 
1266
        while(1){
 
1267
            for(i = screen->lines_per_page, j = k = screen->msg_at_top;
 
1268
                j <= mn_get_total(screen->msgmap) && i > 0L;
 
1269
                j++)
 
1270
              if(!msgline_hidden(screen->stream, screen->msgmap, j, 0)){
 
1271
                  k = j;
 
1272
                  i--;
 
1273
                  if(mn_get_cur(screen->msgmap) <= k)
 
1274
                    break;
 
1275
              }
 
1276
 
 
1277
            if(mn_get_cur(screen->msgmap) <= k)
 
1278
              break;
 
1279
            else{
 
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)){
 
1283
                      k = i;
 
1284
                      break;
 
1285
                  }
 
1286
 
 
1287
                screen->msg_at_top = k;
 
1288
            }
 
1289
        }
 
1290
    }
 
1291
 
 
1292
#ifdef  _WINDOWS
 
1293
    /*
 
1294
     * Set scroll range and position.  Note that message numbers start at 1
 
1295
     * while scroll position starts at 0.
 
1296
     */
 
1297
 
 
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;
 
1301
 
 
1302
        /*
 
1303
         * We know that all visible messages in the thread are marked
 
1304
         * with MN_CHID2.
 
1305
         */
 
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);
 
1311
 
 
1312
        if(thrd){
 
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,
 
1316
                                          n-1L, MN_CHID2))
 
1317
                  n--;
 
1318
 
 
1319
                lowest_numbered_msg = n;
 
1320
            }
 
1321
            else
 
1322
              lowest_numbered_msg = mn_raw2m(screen->msgmap, thrd->rawno);
 
1323
        }
 
1324
        
 
1325
        if(thrd){
 
1326
            n = lowest_numbered_msg;
 
1327
            for(; n <= mn_get_total(screen->msgmap); n++){
 
1328
 
 
1329
                if(!get_lflag(screen->stream, screen->msgmap, n, MN_CHID2))
 
1330
                  break;
 
1331
                
 
1332
                if(!msgline_hidden(screen->stream, screen->msgmap, n, 0)){
 
1333
                    range++;
 
1334
                    if(n < screen->msg_at_top)
 
1335
                      x++;
 
1336
                }
 
1337
            }
 
1338
        }
 
1339
 
 
1340
        scroll_setrange(screen->lines_per_page, range-1L);
 
1341
        scroll_setpos(x);
 
1342
    }
 
1343
    else if(THRD_INDX()){
 
1344
        if(any_lflagged(screen->msgmap, MN_HIDE)){
 
1345
            long x = 0L, range;
 
1346
 
 
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;
 
1351
                int         thrddir;
 
1352
                long        xdir;
 
1353
 
 
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);
 
1360
                
 
1361
                if(topthrd){
 
1362
                    /*
 
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.
 
1368
                     */
 
1369
                    if((!mn_get_revsort(screen->msgmap)
 
1370
                        && topthrd->thrdno <= screen->msgmap->max_thrdno/2)
 
1371
                       ||
 
1372
                       (mn_get_revsort(screen->msgmap)
 
1373
                        && topthrd->thrdno > screen->msgmap->max_thrdno/2)){
 
1374
 
 
1375
                        /* start with head of thread list */
 
1376
                        if(topthrd && topthrd->head)
 
1377
                          thrd = fetch_thread(screen->stream, topthrd->head);
 
1378
                        else
 
1379
                          thrd = NULL;
 
1380
 
 
1381
                        thrddir = 1;
 
1382
                    }
 
1383
                    else{
 
1384
                        long tailrawno;
 
1385
 
 
1386
                        /*
 
1387
                         * Start with tail thread and work back.
 
1388
                         */
 
1389
                        if(mn_get_revsort(screen->msgmap))
 
1390
                          tailrawno = mn_m2raw(screen->msgmap, 1L);
 
1391
                        else
 
1392
                          tailrawno = mn_m2raw(screen->msgmap,
 
1393
                                               mn_get_total(screen->msgmap));
 
1394
 
 
1395
                        thrd = fetch_thread(screen->stream, tailrawno);
 
1396
                        if(thrd && thrd->top && thrd->top != thrd->rawno)
 
1397
                          thrd = fetch_thread(screen->stream, thrd->top);
 
1398
 
 
1399
                        thrddir = -1;
 
1400
                    }
 
1401
 
 
1402
                    /*
 
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.
 
1406
                     */
 
1407
                    if(topthrd->thrdno <= screen->msgmap->max_thrdno/2){
 
1408
                        x = 0L;
 
1409
                        xdir = 1L;
 
1410
                    }
 
1411
                    else{
 
1412
                        x = range;
 
1413
                        xdir = -1L;
 
1414
                    }
 
1415
 
 
1416
                    while(thrd && thrd != topthrd){
 
1417
                        if(!msgline_hidden(screen->stream, screen->msgmap,
 
1418
                                           mn_raw2m(screen->msgmap,thrd->rawno),
 
1419
                                           0))
 
1420
                          x += xdir;
 
1421
                        
 
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);
 
1426
                        else
 
1427
                          thrd = NULL;
 
1428
                    }
 
1429
                }
 
1430
 
 
1431
                scroll_setpos(x);
 
1432
            }
 
1433
        }
 
1434
        else{
 
1435
            long x;
 
1436
 
 
1437
            /*
 
1438
             * This works for forward or reverse sort because the thrdno's
 
1439
             * will have been reversed.
 
1440
             */
 
1441
            thrd = fetch_thread(screen->stream,
 
1442
                                mn_m2raw(screen->msgmap, screen->msg_at_top));
 
1443
            if(thrd){
 
1444
                scroll_setrange(screen->lines_per_page,
 
1445
                                screen->msgmap->max_thrdno - 1L);
 
1446
                scroll_setpos(thrd->thrdno - 1L);
 
1447
            }
 
1448
        }
 
1449
    }
 
1450
    else if(n = any_lflagged(screen->msgmap, MN_HIDE | MN_CHID)){
 
1451
        long x, range;
 
1452
 
 
1453
        range = mn_get_total(screen->msgmap) - n - 1L;
 
1454
        scroll_setrange(screen->lines_per_page, range);
 
1455
 
 
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))
 
1460
                    x++;
 
1461
            }
 
1462
            else{
 
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))
 
1466
                    x--;
 
1467
            }
 
1468
 
 
1469
            scroll_setpos(x);
 
1470
        }
 
1471
    }
 
1472
    else{
 
1473
        scroll_setrange(screen->lines_per_page,
 
1474
                        mn_get_total(screen->msgmap) - 1L);
 
1475
        scroll_setpos(screen->msg_at_top - 1L);
 
1476
    }
 
1477
#endif
 
1478
 
 
1479
    /*
 
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.
 
1483
     */
 
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);
 
1489
 
 
1490
    if(THRD_INDX())
 
1491
      visible = screen->msgmap->visible_threads;
 
1492
    else if(THREADING() && sp_viewing_a_thread(screen->stream)){
 
1493
        /*
 
1494
         * We know that all visible messages in the thread are marked
 
1495
         * with MN_CHID2.
 
1496
         */
 
1497
        for(visible = 0L, n = screen->msg_at_top;
 
1498
            visible < (int) screen->lines_per_page
 
1499
            && n <= mn_get_total(screen->msgmap); n++){
 
1500
 
 
1501
            if(!get_lflag(screen->stream, screen->msgmap, n, MN_CHID2))
 
1502
              break;
 
1503
            
 
1504
            if(!msgline_hidden(screen->stream, screen->msgmap, n, 0))
 
1505
              visible++;
 
1506
        }
 
1507
    }
 
1508
    else
 
1509
      visible = mn_get_total(screen->msgmap)
 
1510
                  - any_lflagged(screen->msgmap, MN_HIDE|MN_CHID);
 
1511
 
 
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);
 
1521
            }
 
1522
        }
 
1523
        else{
 
1524
            ICE_S *ice;
 
1525
 
 
1526
            /*
 
1527
             * This changes status_col as a side effect so it has to be
 
1528
             * executed before next line.
 
1529
             */
 
1530
            ice = build_header_line(state, screen->stream, screen->msgmap,
 
1531
                                    n, &already_fetched);
 
1532
            if(visible > 0L)
 
1533
              visible--;
 
1534
 
 
1535
            if(THRD_INDX()){
 
1536
                unsigned long rawno;
 
1537
 
 
1538
                rawno = mn_m2raw(screen->msgmap, n);
 
1539
                if(rawno)
 
1540
                  thrd = fetch_thread(screen->stream, rawno);
 
1541
            }
 
1542
 
 
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),
 
1548
                                   THRD_INDX()
 
1549
                                     ? (count_lflags_in_thread(screen->stream,
 
1550
                                                               thrd,
 
1551
                                                               screen->msgmap,
 
1552
                                                               MN_SLCT) > 0)
 
1553
                                     : get_lflag(screen->stream, screen->msgmap,
 
1554
                                                 n, MN_SLCT));
 
1555
            if(row && retval < 0)
 
1556
              retval = row;
 
1557
        }
 
1558
 
 
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))
 
1563
          ;
 
1564
    }
 
1565
 
 
1566
    mail_parameters(NULL, SET_IMAPENVELOPE, (void *) NULL);
 
1567
 
 
1568
#ifdef _WINDOWS
 
1569
    mswin_endupdate();
 
1570
#endif
 
1571
    fflush(stdout);
 
1572
    dprint((7, "--update_index done\n"));
 
1573
    return(retval);
 
1574
}
 
1575
 
 
1576
 
 
1577
 
 
1578
/*----------------------------------------------------------------------
 
1579
      Create a string summarizing the message header for index on screen
 
1580
 
 
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
 
1584
 
 
1585
  Result: returns a malloced string
 
1586
          saves string in a cache for next call for same header
 
1587
 ----*/
 
1588
ICE_S *
 
1589
build_header_line(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, int *already_fetched)
 
1590
{
 
1591
    return(build_header_work(state, stream, msgmap, msgno,
 
1592
                             current_index_state->msg_at_top,
 
1593
                             current_index_state->lines_per_page,
 
1594
                             already_fetched));
 
1595
}
 
1596
 
 
1597
 
 
1598
/*----------------------------------------------------------------------
 
1599
     Paint the given index line
 
1600
 
 
1601
 
 
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?
 
1616
 
 
1617
  Returns: screen row number if this is current message, else 0
 
1618
 ----*/
 
1619
int
 
1620
paint_index_line(ICE_S *argice, int line, long int msgno, IndexColType sfld,
 
1621
                 IndexColType pfld, IndexColType afld, struct entry_state *entry,
 
1622
                 int cur, int sel)
 
1623
{
 
1624
  COLOR_PAIR *lastc = NULL, *base_color = NULL;
 
1625
  ICE_S      *ice;
 
1626
  IFIELD_S   *ifield;
 
1627
  IELEM_S    *ielem;
 
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;
 
1632
 
 
1633
  ice = (THRD_INDX() && argice) ? argice->tice : argice;
 
1634
 
 
1635
  /* This better not happen! */
 
1636
  if(!ice){
 
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"));
 
1642
    return 0;
 
1643
  }
 
1644
 
 
1645
  if(entry->msgno != msgno || ice->id == 0 || entry->id != ice->id){
 
1646
    entry->id = 0L;
 
1647
    entry->msgno = 0L;
 
1648
    draw_whole_line = 1;
 
1649
  }
 
1650
  else if((cur != entry->hilite) || (sel != entry->bolded)
 
1651
          || (ice->plus != entry->plus)){
 
1652
    draw_partial_line = 1;
 
1653
  }
 
1654
 
 
1655
  if(draw_whole_line || draw_partial_line){
 
1656
 
 
1657
    if(F_ON(F_FORCE_LOW_SPEED,ps_global) || ps_global->low_speed){
 
1658
 
 
1659
      memset(draw, 0, sizeof(draw));
 
1660
      p = draw;
 
1661
 
 
1662
      for(ifield = ice->ifield; ifield && p-draw < n; ifield = ifield->next){
 
1663
 
 
1664
        /* space between fields */
 
1665
        if(ifield != ice->ifield)
 
1666
          *p++ = ' ';
 
1667
 
 
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';
 
1675
          }
 
1676
        }
 
1677
 
 
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));
 
1683
 
 
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);
 
1689
 
 
1690
              if(ielem->next && ielem->next->datalen){
 
1691
                save_schar2 = ielem->next->data[0];
 
1692
                if(cur)
 
1693
                  ielem->next->data[0] = '>';
 
1694
 
 
1695
                if(draw_partial_line)
 
1696
                  Writechar(ielem->next->data[0], 0);
 
1697
              }
 
1698
            }
 
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);
 
1704
 
 
1705
              save_schar2 = ielem->data[1];
 
1706
              if(cur){
 
1707
                ielem->data[1] = '>';
 
1708
                if(draw_partial_line)
 
1709
                  Writechar(ielem->data[1], 0);
 
1710
              }
 
1711
            }
 
1712
          }
 
1713
        }
 
1714
        else if(ifield->ctype == afld){
 
1715
 
 
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);
 
1720
 
 
1721
            Writechar(cur ? '>' : ' ', 0);
 
1722
          }
 
1723
 
 
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 ? '-' : ' ';
 
1728
 
 
1729
            ielem->data[i] = cur ? '>' : ' ';
 
1730
          }
 
1731
        }
 
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;
 
1737
 
 
1738
            if(draw_partial_line){
 
1739
              MoveCursor(HEADER_ROWS(ps_global) + line, (int) (p-draw));
 
1740
              Writechar(ielem->data[0], 0);
 
1741
              Writechar(' ', 0);
 
1742
            }
 
1743
          }
 
1744
        }
 
1745
 
 
1746
        for(ielem = ifield->ielem;
 
1747
            ielem && ielem->print_format && p-draw < n;
 
1748
            ielem = ielem->next){
 
1749
          char *src;
 
1750
          size_t bytes_added;
 
1751
 
 
1752
          src = ielem->data;
 
1753
          bytes_added = utf8_pad_to_width(p, src,
 
1754
                                          ((p-draw)+n+1) * sizeof(char),
 
1755
                                          ielem->wid, ifield->leftadj);
 
1756
          p += bytes_added;
 
1757
        }
 
1758
 
 
1759
        draw[n] = '\0';
 
1760
 
 
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;
 
1768
            }
 
1769
            else if(ielem->datalen > 1){
 
1770
              ielem->data[0] = save_schar1;
 
1771
              ielem->data[1] = save_schar2;
 
1772
            }
 
1773
          }
 
1774
        }
 
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] = ' ';
 
1780
        }
 
1781
        else if(ifield->ctype == pfld){
 
1782
          ielem = ifield->ielem;
 
1783
          if(ielem && ielem->datalen > 0)
 
1784
            ielem->data[0] = save_pchar;
 
1785
        }
 
1786
      }
 
1787
 
 
1788
      *p = '\0';
 
1789
 
 
1790
      if(draw_whole_line)
 
1791
        PutLine0(HEADER_ROWS(ps_global) + line, 0, draw);
 
1792
    }
 
1793
    else{
 
1794
      int   uc, ac, do_arrow;
 
1795
      int   i, drew_X = 0;
 
1796
      int   inverse_hack = 0, need_inverse_hack = 0;
 
1797
      int   doing_bold = 0;
 
1798
 
 
1799
      /* so we can restore current color at the end */
 
1800
      if(uc=pico_usingcolor())
 
1801
        lastc = pico_get_cur_color();
 
1802
 
 
1803
      /*
 
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.
 
1809
       *
 
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
 
1812
       * be colored.
 
1813
       *
 
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.
 
1819
       */
 
1820
 
 
1821
      /* ac is for the old integrated arrow cursor */
 
1822
      ac = F_ON(F_FORCE_ARROW,ps_global);
 
1823
 
 
1824
      /* do_arrow is for the ARROW token in index-format */
 
1825
      do_arrow = (afld != iNothing);
 
1826
 
 
1827
      MoveCursor(HEADER_ROWS(ps_global) + line, 0);
 
1828
 
 
1829
      /* find the base color for the whole line */
 
1830
      if(cur && !ac && !do_arrow){
 
1831
        /*
 
1832
         * This stanza handles the current line marking in the
 
1833
         * regular, non-arrow-cursor case.
 
1834
         */
 
1835
 
 
1836
        /*
 
1837
         * If the current line has a linecolor, apply the
 
1838
         * appropriate reverse transformation to show it is current.
 
1839
         */
 
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);
 
1844
 
 
1845
          (void)pico_set_colorp(base_color, PSC_NONE);
 
1846
        }
 
1847
        else{
 
1848
          inverse_hack++;
 
1849
          if(uc)
 
1850
            base_color = lastc;
 
1851
        }
 
1852
      }
 
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;
 
1858
      }
 
1859
      else
 
1860
        base_color = lastc;
 
1861
 
 
1862
      memset(draw, 0, sizeof(draw));
 
1863
      p = draw;
 
1864
 
 
1865
      doing_bold = (sel && F_ON(F_SELECTED_SHOWN_BOLD, ps_global) && StartBold());
 
1866
 
 
1867
      /* draw each field */
 
1868
      for(ifield = ice->ifield; ifield && p-draw < n; ifield = ifield->next){
 
1869
 
 
1870
        drew_X = 0;
 
1871
 
 
1872
        /*
 
1873
         * Fix up the data for some special cases.
 
1874
         */
 
1875
 
 
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';
 
1883
          }
 
1884
        }
 
1885
 
 
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';
 
1893
                drew_X++;
 
1894
              }
 
1895
              else if(ac && cur && ielem->data[0] == ' ')
 
1896
                ielem->data[0] = '-';
 
1897
 
 
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] = '>';
 
1902
              }
 
1903
            }
 
1904
            else if(ielem->datalen > 1){
 
1905
              if(sel && !doing_bold){
 
1906
                ielem->data[0] = 'X';
 
1907
                drew_X++;
 
1908
              }
 
1909
              else if(ac && cur && ielem->data[0] == ' ')
 
1910
                ielem->data[0] = '-';
 
1911
 
 
1912
              save_schar2 = ielem->data[1];
 
1913
              if(ac && cur && ielem->data[1] != '\0')
 
1914
                ielem->data[1] = '>';
 
1915
            }
 
1916
          }
 
1917
        }
 
1918
        else if(ifield->ctype == afld && do_arrow && cur){
 
1919
 
 
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 ? '-' : ' ';
 
1924
 
 
1925
            ielem->data[i] = '>';
 
1926
          }
 
1927
        }
 
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;
 
1933
          }
 
1934
        }
 
1935
 
 
1936
        /* space between fields */
 
1937
        if(ifield != ice->ifield){
 
1938
          if(inverse_hack)
 
1939
            StartInverse();
 
1940
 
 
1941
          Write_to_screen(" ");
 
1942
          if(inverse_hack)
 
1943
            EndInverse();
 
1944
        }
 
1945
 
 
1946
        for(ielem = ifield->ielem; ielem; ielem = ielem->next){
 
1947
          char *src;
 
1948
          size_t bytes_added;
 
1949
 
 
1950
          src = ielem->data;
 
1951
          bytes_added = utf8_pad_to_width(draw, src,
 
1952
                                          (n+1) * sizeof(char),
 
1953
                                          ielem->wid, ifield->leftadj);
 
1954
          draw[n] = '\0';
 
1955
 
 
1956
          /*
 
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.
 
1963
           */
 
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);
 
1969
          }
 
1970
          else
 
1971
            need_inverse_hack = 1;
 
1972
 
 
1973
          if(need_inverse_hack && inverse_hack)
 
1974
            StartInverse();
 
1975
 
 
1976
          Write_to_screen(draw);
 
1977
          if(need_inverse_hack && inverse_hack)
 
1978
            EndInverse();
 
1979
 
 
1980
          (void) pico_set_colorp(base_color, PSC_NORM);
 
1981
        }
 
1982
 
 
1983
        /*
 
1984
         * Restore the data for the special cases.
 
1985
         */
 
1986
 
 
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;
 
1994
            }
 
1995
            else if(ielem->datalen > 1){
 
1996
              ielem->data[0] = save_schar1;
 
1997
              ielem->data[1] = save_schar2;
 
1998
            }
 
1999
          }
 
2000
        }
 
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] = ' ';
 
2006
        }
 
2007
        else if(ifield->ctype == pfld){
 
2008
          ielem = ifield->ielem;
 
2009
          if(ielem && ielem->datalen > 0)
 
2010
            ielem->data[0] = save_pchar;
 
2011
        }
 
2012
      }
 
2013
 
 
2014
      if(doing_bold)
 
2015
        EndBold();
 
2016
 
 
2017
      if(base_color && base_color != lastc && base_color != ice->linecolor)
 
2018
        free_color_pair(&base_color);
 
2019
 
 
2020
      if(lastc){
 
2021
        (void)pico_set_colorp(lastc, PSC_NORM);
 
2022
        free_color_pair(&lastc);
 
2023
      }
 
2024
    }
 
2025
  }
 
2026
 
 
2027
  entry->hilite = cur;
 
2028
  entry->bolded = sel;
 
2029
  entry->msgno  = msgno;
 
2030
  entry->plus   = ice->plus;
 
2031
  entry->id     = ice->id;
 
2032
 
 
2033
  if(!ice->color_lookup_done && pico_usingcolor())
 
2034
    entry->id = 0;
 
2035
 
 
2036
  return(cur ? (line + HEADER_ROWS(ps_global)) : 0);
 
2037
}
 
2038
 
 
2039
/*
 
2040
 * setup_index_state - hooked onto pith_opt_save_index_state to setup
 
2041
 *                     current_index_state after setup_{index,thread}_header_widths
 
2042
 */
 
2043
void
 
2044
setup_index_state(int threaded)
 
2045
{
 
2046
    if(current_index_state){
 
2047
        if(threaded){
 
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;
 
2052
        } else {
 
2053
            INDEX_COL_S  *cdesc;
 
2054
            IndexColType  sfld, altfld, plusfld, arrowfld;
 
2055
            int           width, fld, col, pluscol, scol, altcol;
 
2056
 
 
2057
            col = 0;
 
2058
            scol = -1;
 
2059
            sfld = iNothing;
 
2060
            altcol = -1;
 
2061
            altfld = iNothing;
 
2062
            /* figure out which field is status field */
 
2063
            for(cdesc = ps_global->index_disp_format, fld = 0;
 
2064
                cdesc->ctype != iNothing;
 
2065
                cdesc++){
 
2066
                width = cdesc->width;
 
2067
                if(width == 0)
 
2068
                  continue;
 
2069
 
 
2070
                /* space between columns */
 
2071
                if(col > 0)
 
2072
                  col++;
 
2073
 
 
2074
                if(cdesc->ctype == iStatus){
 
2075
                    scol = col;
 
2076
                    sfld = cdesc->ctype;
 
2077
                    break;
 
2078
                }
 
2079
 
 
2080
                if(cdesc->ctype == iFStatus || cdesc->ctype == iIStatus){
 
2081
                    scol = col;
 
2082
                    sfld = cdesc->ctype;
 
2083
                    break;
 
2084
                }
 
2085
 
 
2086
                if(cdesc->ctype == iMessNo){
 
2087
                    altcol = col;
 
2088
                    altfld = cdesc->ctype;
 
2089
                }
 
2090
 
 
2091
                col += width;
 
2092
                fld++;
 
2093
            }
 
2094
 
 
2095
            if(sfld == iNothing){
 
2096
                if(altcol == -1){
 
2097
                    scol = 0;
 
2098
                }
 
2099
                else{
 
2100
                    scol = altcol;
 
2101
                    sfld = altfld;
 
2102
                }
 
2103
            }
 
2104
 
 
2105
 
 
2106
 
 
2107
            current_index_state->status_col  = scol;
 
2108
            current_index_state->status_fld  = sfld;
 
2109
 
 
2110
            col = 0;
 
2111
            plusfld = iNothing;
 
2112
            pluscol = -1;
 
2113
            /* figure out which column to use for threading '+' */
 
2114
            if(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;
 
2120
                  cdesc++){
 
2121
                  width = cdesc->width;
 
2122
                  if(width == 0)
 
2123
                    continue;
 
2124
 
 
2125
                  /* space between columns */
 
2126
                  if(col > 0)
 
2127
                    col++;
 
2128
 
 
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;
 
2140
                      pluscol = col;
 
2141
                      break;
 
2142
                  }
 
2143
 
 
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;
 
2153
                      pluscol = col;
 
2154
                      break;
 
2155
                  }
 
2156
 
 
2157
                  col += width;
 
2158
                  fld++;
 
2159
              }
 
2160
 
 
2161
            current_index_state->plus_fld    = plusfld;
 
2162
            current_index_state->plus_col    = pluscol;
 
2163
 
 
2164
 
 
2165
 
 
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;
 
2170
                cdesc++){
 
2171
                width = cdesc->width;
 
2172
                if(width == 0)
 
2173
                  continue;
 
2174
 
 
2175
                if(cdesc->ctype == iArrow){
 
2176
                    arrowfld   = cdesc->ctype;
 
2177
                    break;
 
2178
                }
 
2179
 
 
2180
                fld++;
 
2181
            }
 
2182
 
 
2183
            current_index_state->arrow_fld   = arrowfld;
 
2184
        }
 
2185
    }
 
2186
}
 
2187
 
 
2188
 
 
2189
/*
 
2190
 * insert_condensed_thread_cue - used on pith hook to add decoration to
 
2191
 *                               subject or from text to show condensed thread info
 
2192
 */
 
2193
int
 
2194
condensed_thread_cue(PINETHRD_S *thd, ICE_S *ice, char **fieldstr, int width, int collapsed)
 
2195
{
 
2196
    if(current_index_state->plus_fld != iNothing && !THRD_INDX() && fieldstr && *fieldstr){
 
2197
        /*
 
2198
         * WARNING!
 
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.
 
2203
         */
 
2204
        if(ice)
 
2205
          ice->plus = collapsed ? ps_global->VAR_THREAD_MORE_CHAR[0]
 
2206
                                : (thd && thd->next)
 
2207
                                   ? ps_global->VAR_THREAD_EXP_CHAR[0] : ' ';
 
2208
 
 
2209
        if(width > 0){
 
2210
            *(*fieldstr)++ = ' ';
 
2211
            width--;
 
2212
        }
 
2213
 
 
2214
        if(width > 0){
 
2215
            *(*fieldstr)++ = ' ';
 
2216
            width--;
 
2217
        }
 
2218
    }
 
2219
 
 
2220
    return(width);
 
2221
}
 
2222
 
 
2223
 
 
2224
/*
 
2225
 * paint_index_hline - paint index line given what we got
 
2226
 */
 
2227
void
 
2228
paint_index_hline(MAILSTREAM *stream, long int msgno, ICE_S *ice)
 
2229
{
 
2230
    PINETHRD_S *thrd;
 
2231
 
 
2232
    /*
 
2233
     * Trust only what we get back that isn't bogus since
 
2234
     * we were prevented from doing any fetches and such...
 
2235
     */
 
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){
 
2241
        int line;
 
2242
 
 
2243
        /*
 
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
 
2252
         */
 
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)){
 
2256
                long n;
 
2257
                long zoomhide, collapsehide;
 
2258
 
 
2259
                zoomhide = any_lflagged(ps_global->msgmap, MN_HIDE);
 
2260
                collapsehide = any_lflagged(ps_global->msgmap, MN_CHID);
 
2261
 
 
2262
                /*
 
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.
 
2266
                 */
 
2267
                for(line = 0, n = current_index_state->msg_at_top;
 
2268
                    n != msgno;
 
2269
                    n++)
 
2270
                  if((zoomhide
 
2271
                      && get_lflag(stream, current_index_state->msgmap,
 
2272
                                   n, MN_SLCT)
 
2273
                      && (!collapsehide
 
2274
                          || !get_lflag(stream, current_index_state->msgmap, n,
 
2275
                                        MN_CHID)))
 
2276
                     ||
 
2277
                     (!zoomhide
 
2278
                      && !get_lflag(stream, current_index_state->msgmap,
 
2279
                                    n, MN_CHID)))
 
2280
                    line++;
 
2281
            }
 
2282
 
 
2283
            thrd = NULL;
 
2284
            if(THRD_INDX()){
 
2285
                unsigned long rawno;
 
2286
 
 
2287
                rawno = mn_m2raw(current_index_state->msgmap, msgno);
 
2288
                if(rawno)
 
2289
                  thrd = fetch_thread(stream, rawno);
 
2290
            }
 
2291
 
 
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
                             &current_index_state->entry_state[line],
 
2298
                             mn_is_cur(current_index_state->msgmap, msgno),
 
2299
                             THRD_INDX()
 
2300
                               ? (count_lflags_in_thread(stream, thrd,
 
2301
                                                   current_index_state->msgmap,
 
2302
                                                         MN_SLCT) > 0)
 
2303
                               : get_lflag(stream, current_index_state->msgmap,
 
2304
                                           msgno, MN_SLCT));
 
2305
            fflush(stdout);
 
2306
        }
 
2307
    }
 
2308
}
 
2309
 
 
2310
 
 
2311
 
 
2312
 
 
2313
/*
 
2314
 * pine_imap_env -- C-client's telling us an envelope just arrived
 
2315
 *                  from the server.  Use it if we can...
 
2316
 */
 
2317
void
 
2318
pine_imap_envelope(MAILSTREAM *stream, long unsigned int rawno, ENVELOPE *env)
 
2319
{
 
2320
    MESSAGECACHE *mc;
 
2321
 
 
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))
 
2327
       && mc->valid
 
2328
       && mc->rfc822_size
 
2329
       && !get_lflag(stream, NULL, rawno, MN_HIDE | MN_CHID | MN_EXLD)){
 
2330
        INDEXDATA_S  idata;
 
2331
        ICE_S       *ice;
 
2332
 
 
2333
        memset(&idata, 0, sizeof(INDEXDATA_S));
 
2334
        idata.no_fetch = 1;
 
2335
        idata.size     = mc->rfc822_size;
 
2336
        idata.rawno    = rawno;
 
2337
        idata.msgno    = mn_raw2m(sp_msgmap(stream), rawno);
 
2338
        idata.stream   = stream;
 
2339
 
 
2340
        index_data_env(&idata, env);
 
2341
 
 
2342
        /*
 
2343
         * Look for resent-to already in MAILCACHE data 
 
2344
         */
 
2345
        if(mc->private.msg.header.text.data){
 
2346
            STRINGLIST *lines;
 
2347
            SIZEDTEXT   szt;
 
2348
            static char *linelist[] = {"resent-to" , NULL};
 
2349
 
 
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);
 
2358
            }
 
2359
 
 
2360
            free_strlst(&lines);
 
2361
        }
 
2362
 
 
2363
        ice = (*format_index_line)(&idata);
 
2364
        if(idata.bogus)
 
2365
          clear_ice(&ice);
 
2366
        else
 
2367
          paint_index_hline(stream, idata.msgno, ice);
 
2368
    }
 
2369
}
 
2370
 
 
2371
 
 
2372
/*----------------------------------------------------------------------
 
2373
     Scroll to specified postion.
 
2374
 
 
2375
 
 
2376
  Args: pos - position to scroll to.
 
2377
 
 
2378
  Returns: TRUE - did the scroll operation.
 
2379
           FALSE - was not able to do the scroll operation.
 
2380
 ----*/
 
2381
int
 
2382
index_scroll_to_pos (long int pos)
 
2383
{
 
2384
    static short bad_timing = 0;
 
2385
    long        i, j, k;
 
2386
    
 
2387
    if(bad_timing)
 
2388
      return (FALSE);
 
2389
 
 
2390
    /*
 
2391
     * Put the requested line at the top of the screen...
 
2392
     */
 
2393
 
 
2394
    /*
 
2395
     * Starting at msg 'pos' find next visible message.
 
2396
     */
 
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;
 
2401
          break;
 
2402
      }
 
2403
    }
 
2404
 
 
2405
    /*
 
2406
     * If single selection, move selected message to be on the screen.
 
2407
     */
 
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);
 
2413
      }
 
2414
      else {
 
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) && 
 
2421
                j > 0L;
 
2422
              i++) {
 
2423
            if(!msgline_hidden(current_index_state->stream,
 
2424
                               current_index_state->msgmap, i, 0)){
 
2425
                j--;
 
2426
                k = i;
 
2427
            }
 
2428
        }
 
2429
        if(j <= 0L)
 
2430
            /* Move to end of screen. */
 
2431
            mn_set_cur(current_index_state->msgmap, k);
 
2432
      }
 
2433
    }
 
2434
 
 
2435
    bad_timing = 0;
 
2436
    return (TRUE);
 
2437
}
 
2438
 
 
2439
 
 
2440
 
 
2441
/*----------------------------------------------------------------------
 
2442
     Adjust the index display state down a line
 
2443
 
 
2444
  Args: scroll_count -- number of lines to scroll
 
2445
 
 
2446
  Returns: TRUE - did the scroll operation.
 
2447
           FALSE - was not able to do the scroll operation.
 
2448
 ----*/
 
2449
int
 
2450
index_scroll_down(long int scroll_count)
 
2451
{
 
2452
    static short bad_timing = 0;
 
2453
    long i, j, k;
 
2454
    long cur, total;
 
2455
 
 
2456
    if(bad_timing)
 
2457
      return (FALSE);
 
2458
 
 
2459
    bad_timing = 1;
 
2460
    
 
2461
    
 
2462
    j = -1L;
 
2463
    total = mn_get_total (current_index_state->msgmap);
 
2464
    for(k = i = current_index_state->msg_at_top; ; i++){
 
2465
 
 
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 */
 
2470
            k = i;
 
2471
            /* Increment count of lines.  */
 
2472
            if (++j >= scroll_count) {
 
2473
                /* Counted enough lines, stop. */
 
2474
                current_index_state->msg_at_top = k;
 
2475
                break;
 
2476
            }
 
2477
        }
 
2478
            
 
2479
        /* If at last message, stop. */
 
2480
        if (i >= total){
 
2481
            current_index_state->msg_at_top = k;
 
2482
            break;
 
2483
        }
 
2484
    }
 
2485
 
 
2486
    /*
 
2487
     * If not multiple selection, see if selected message visable.  if not
 
2488
     * set it to last visable message. 
 
2489
     */
 
2490
    if(mn_total_cur(current_index_state->msgmap) == 1L) {
 
2491
        j = 0L;
 
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) {
 
2497
                    break;
 
2498
                }
 
2499
                if (i == cur) 
 
2500
                    break;
 
2501
            }
 
2502
        }
 
2503
        if (i != cur) 
 
2504
            mn_set_cur(current_index_state->msgmap,
 
2505
                       current_index_state->msg_at_top);
 
2506
    }
 
2507
 
 
2508
    bad_timing = 0;
 
2509
    return (TRUE);
 
2510
}
 
2511
 
 
2512
 
 
2513
 
 
2514
/*----------------------------------------------------------------------
 
2515
     Adjust the index display state up a line
 
2516
 
 
2517
  Args: scroll_count -- number of lines to scroll
 
2518
 
 
2519
  Returns: TRUE - did the scroll operation.
 
2520
           FALSE - was not able to do the scroll operation.
 
2521
 
 
2522
 ----*/
 
2523
int
 
2524
index_scroll_up(long int scroll_count)
 
2525
{
 
2526
    static short bad_timing = 0;
 
2527
    long i, j, k;
 
2528
    long cur;
 
2529
 
 
2530
    if(bad_timing)
 
2531
      return(FALSE);
 
2532
 
 
2533
    bad_timing = 1;
 
2534
    
 
2535
    j = -1L;
 
2536
    for(k = i = current_index_state->msg_at_top; ; i--){
 
2537
 
 
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 */
 
2542
            k = i;
 
2543
            /* Increment count of lines.  */
 
2544
            if (++j >= scroll_count) {
 
2545
                /* Counted enough lines, stop. */
 
2546
                current_index_state->msg_at_top = k;
 
2547
                break;
 
2548
            }
 
2549
        }
 
2550
            
 
2551
        /* If at first message, stop */
 
2552
        if (i <= 1L){
 
2553
            current_index_state->msg_at_top = k;
 
2554
            break;
 
2555
        }
 
2556
    }
 
2557
 
 
2558
    
 
2559
    /*
 
2560
     * If not multiple selection, see if selected message visable.  if not
 
2561
     * set it to last visable message. 
 
2562
     */
 
2563
    if(mn_total_cur(current_index_state->msgmap) == 1L) {
 
2564
        j = 0L;
 
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);
 
2568
                ++i) {
 
2569
            if(!msgline_hidden(current_index_state->stream,
 
2570
                               current_index_state->msgmap, i, 0)){
 
2571
                if (++j >= current_index_state->lines_per_page) {
 
2572
                    k = i;
 
2573
                    break;
 
2574
                }
 
2575
                if (i == cur) 
 
2576
                    break;
 
2577
            }
 
2578
        }
 
2579
        if (i != cur) 
 
2580
            mn_set_cur(current_index_state->msgmap, k);
 
2581
    }
 
2582
 
 
2583
 
 
2584
    bad_timing = 0;
 
2585
    return (TRUE);
 
2586
}
 
2587
 
 
2588
 
 
2589
 
 
2590
/*----------------------------------------------------------------------
 
2591
     Calculate the message number that should be at the top of the display
 
2592
 
 
2593
  Args: current - the current message number
 
2594
        lines_per_page - the number of lines for the body of the index only
 
2595
 
 
2596
  Returns: -1 if the current message is -1 
 
2597
           the message entry for the first message at the top of the screen.
 
2598
 
 
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
 
2602
on the page. 
 
2603
 ----*/
 
2604
long
 
2605
top_ent_calc(MAILSTREAM *stream, MSGNO_S *msgs, long int at_top, long int lines_per_page)
 
2606
{
 
2607
    long current, hidden, visible, lastn;
 
2608
    long n, m = 0L, t = 1L;
 
2609
 
 
2610
    current = (mn_total_cur(msgs) <= 1L) ? mn_get_cur(msgs) : at_top;
 
2611
 
 
2612
    if(current < 0L)
 
2613
      return(-1);
 
2614
 
 
2615
    if(lines_per_page == 0L)
 
2616
      return(current);
 
2617
 
 
2618
    if(THRD_INDX_ENABLED()){
 
2619
        long rawno;
 
2620
        PINETHRD_S *thrd = NULL;
 
2621
 
 
2622
        rawno = mn_m2raw(msgs, mn_get_cur(msgs));
 
2623
        if(rawno)
 
2624
          thrd = fetch_thread(stream, rawno);
 
2625
 
 
2626
        if(THRD_INDX()){
 
2627
 
 
2628
            if(any_lflagged(msgs, MN_HIDE)){
 
2629
                long vis = 0L;
 
2630
                PINETHRD_S *is_current_thrd;
 
2631
 
 
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);
 
2639
                    }
 
2640
                    else{
 
2641
                        /* start with head of thread list */
 
2642
                        thrd = fetch_head_thread(stream);
 
2643
                    }
 
2644
 
 
2645
                    t = 1L;
 
2646
                    m = 0L;
 
2647
                    if(thrd)
 
2648
                      n = mn_raw2m(msgs, thrd->rawno);
 
2649
 
 
2650
                    while(thrd){
 
2651
                        if(!msgline_hidden(stream, msgs, n, 0)
 
2652
                           && (++m % lines_per_page) == 1L)
 
2653
                          t = n;
 
2654
                        
 
2655
                        if(thrd == is_current_thrd)
 
2656
                          break;
 
2657
 
 
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);
 
2662
                        else
 
2663
                          thrd = NULL;
 
2664
 
 
2665
                        if(thrd)
 
2666
                          n = mn_raw2m(msgs, thrd->rawno);
 
2667
                    }
 
2668
                }
 
2669
            }
 
2670
            else{
 
2671
                if(thrd){
 
2672
                    n = thrd->thrdno;
 
2673
                    m = lines_per_page * ((n - 1L)/ lines_per_page) + 1L;
 
2674
                    n = thrd->rawno;
 
2675
                    /*
 
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.
 
2681
                     */
 
2682
                    while(thrd && m < thrd->thrdno){
 
2683
                        n = thrd->rawno;
 
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);
 
2688
                        else
 
2689
                          thrd = NULL;
 
2690
                    }
 
2691
 
 
2692
                    if(thrd)
 
2693
                      n = thrd->rawno;
 
2694
 
 
2695
                    t = mn_raw2m(msgs, n);
 
2696
                }
 
2697
            }
 
2698
        }
 
2699
        else{           /* viewing a thread */
 
2700
 
 
2701
            lastn = mn_get_total(msgs);
 
2702
            t = 1L;
 
2703
 
 
2704
            /* get top of thread */
 
2705
            if(thrd && thrd->top && thrd->top != thrd->rawno)
 
2706
              thrd = fetch_thread(stream, thrd->top);
 
2707
 
 
2708
            if(thrd){
 
2709
                if(mn_get_revsort(msgs))
 
2710
                  lastn = mn_raw2m(msgs, thrd->rawno);
 
2711
                else
 
2712
                  t = mn_raw2m(msgs, thrd->rawno);
 
2713
            }
 
2714
 
 
2715
            n = 0L;
 
2716
 
 
2717
            /* n is the end of this thread */
 
2718
            while(thrd){
 
2719
                n = mn_raw2m(msgs, thrd->rawno);
 
2720
                if(thrd->branch)
 
2721
                  thrd = fetch_thread(stream, thrd->branch);
 
2722
                else if(thrd->next)
 
2723
                  thrd = fetch_thread(stream, thrd->next);
 
2724
                else
 
2725
                  thrd = NULL;
 
2726
            }
 
2727
 
 
2728
            if(n){
 
2729
                if(mn_get_revsort(msgs))
 
2730
                  t = n;
 
2731
                else
 
2732
                  lastn = n;
 
2733
            }
 
2734
 
 
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)
 
2738
                t = n;
 
2739
        }
 
2740
 
 
2741
        return(t);
 
2742
    }
 
2743
    else if(hidden = any_lflagged(msgs, MN_HIDE | MN_CHID)){
 
2744
 
 
2745
        if(current < mn_get_total(msgs) / 2){
 
2746
            t = 1L;
 
2747
            m = 0L;
 
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)
 
2751
                t = n;
 
2752
        }
 
2753
        else{
 
2754
            t = current+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)
 
2759
                t = n;
 
2760
            
 
2761
            if(t > current)
 
2762
              t = 1L;
 
2763
        }
 
2764
 
 
2765
        return(t);
 
2766
    }
 
2767
    else
 
2768
      return(lines_per_page * ((current - 1L)/ lines_per_page) + 1L);
 
2769
}
 
2770
 
 
2771
 
 
2772
/*----------------------------------------------------------------------
 
2773
      Clear various bits that make up a healthy display
 
2774
 
 
2775
 ----*/
 
2776
void
 
2777
reset_index_border(void)
 
2778
{
 
2779
    mark_status_dirty();
 
2780
    mark_keymenu_dirty();
 
2781
    mark_titlebar_dirty();
 
2782
    ps_global->mangled_screen = 1;      /* signal FULL repaint */
 
2783
}
 
2784
 
 
2785
 
 
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
 
2790
anywhere.
 
2791
 ----*/
 
2792
void
 
2793
redraw_index_body(void)
 
2794
{
 
2795
    int agg;
 
2796
 
 
2797
    if(agg = (mn_total_cur(current_index_state->msgmap) > 1L))
 
2798
      restore_selected(current_index_state->msgmap);
 
2799
 
 
2800
    ps_global->mangled_body = 1;
 
2801
 
 
2802
    (void) update_index(ps_global, current_index_state);
 
2803
    if(agg)
 
2804
      pseudo_selected(current_index_state->msgmap);
 
2805
}
 
2806
 
 
2807
 
 
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.
 
2811
   
 
2812
   Args: none
 
2813
 
 
2814
 Result: message may be printed to status line
 
2815
  ----*/
 
2816
void
 
2817
warn_other_cmds(void)
 
2818
{
 
2819
    static int other_cmds = 0;
 
2820
 
 
2821
    other_cmds++;
 
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");
 
2826
}
 
2827
 
 
2828
 
 
2829
void
 
2830
thread_command(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap, int preloadkeystroke, int q_line)
 
2831
{
 
2832
    PINETHRD_S   *thrd = NULL;
 
2833
    unsigned long rawno, save_branch;
 
2834
    int           we_cancel = 0;
 
2835
    int           flags = AC_FROM_THREAD;
 
2836
 
 
2837
    if(!(stream && msgmap))
 
2838
      return;
 
2839
 
 
2840
    rawno = mn_m2raw(msgmap, mn_get_cur(msgmap));
 
2841
    if(rawno)
 
2842
      thrd = fetch_thread(stream, rawno);
 
2843
 
 
2844
    if(!thrd)
 
2845
      return;
 
2846
 
 
2847
    save_branch = thrd->branch;
 
2848
    thrd->branch = 0L;          /* branch is a sibling, not part of thread */
 
2849
 
 
2850
    if(!preloadkeystroke){
 
2851
        if(!THRD_INDX()){
 
2852
            if(get_lflag(stream, NULL, rawno, MN_COLL) && thrd->next)
 
2853
              flags |= AC_EXPN;
 
2854
            else
 
2855
              flags |= AC_COLL;
 
2856
        }
 
2857
 
 
2858
        if(count_lflags_in_thread(stream, thrd, msgmap, MN_SLCT)
 
2859
               == count_lflags_in_thread(stream, thrd, msgmap, MN_NONE))
 
2860
          flags |= AC_UNSEL;
 
2861
    }
 
2862
 
 
2863
    we_cancel = busy_cue(NULL, NULL, 1);
 
2864
 
 
2865
    /* save the SLCT flags in STMP for restoring at the bottom */
 
2866
    copy_lflags(stream, msgmap, MN_SLCT, MN_STMP);
 
2867
 
 
2868
    /* clear the values from the SLCT flags */
 
2869
    set_lflags(stream, msgmap, MN_SLCT, 0);
 
2870
 
 
2871
    /* set SLCT for thrd on down */
 
2872
    set_flags_for_thread(stream, msgmap, MN_SLCT, thrd, 1);
 
2873
    thrd->branch = save_branch;
 
2874
 
 
2875
    if(we_cancel)
 
2876
      cancel_busy_cue(0);
 
2877
 
 
2878
    (void ) apply_command(state, stream, msgmap, preloadkeystroke, flags,
 
2879
                          q_line);
 
2880
 
 
2881
    /* restore the original flags */
 
2882
    copy_lflags(stream, msgmap, MN_STMP, MN_SLCT);
 
2883
 
 
2884
    if(any_lflagged(msgmap, MN_HIDE) > 0L){
 
2885
        long cur;
 
2886
 
 
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"));
 
2892
        }
 
2893
 
 
2894
        /* if current is hidden, adjust */
 
2895
        adjust_cur_to_visible(stream, msgmap);
 
2896
    }
 
2897
}
 
2898
 
 
2899
 
 
2900
/*----------------------------------------------------------------------
 
2901
      Search the message headers as displayed in index
 
2902
 
 
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
 
2906
 
 
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 
 
2909
away.
 
2910
  ----*/
 
2911
void
 
2912
index_search(struct pine *state, MAILSTREAM *stream, int command_line, MSGNO_S *msgmap)
 
2913
{
 
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];
 
2918
    HelpType    help;
 
2919
    static char search_string[MAX_SEARCH+1] = { '\0' };
 
2920
    ICE_S      *ice, *ic;
 
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} };
 
2925
 
 
2926
    dprint((4, "\n - search headers - \n"));
 
2927
 
 
2928
    if(!any_messages(msgmap, NULL, "to search")){
 
2929
        return;
 
2930
    }
 
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)));
 
2934
        return;
 
2935
    }
 
2936
    else
 
2937
      sorted_msg = mn_get_cur(msgmap);
 
2938
 
 
2939
    help = NO_HELP;
 
2940
    new_string[0] = '\0';
 
2941
 
 
2942
    while(1) {
 
2943
        snprintf(prompt, sizeof(prompt), _("Word to search for [%s] : "), search_string);
 
2944
 
 
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");
 
2950
        }
 
2951
        else{
 
2952
            header_search_key[0].ch   = header_search_key[0].rval  = 0;
 
2953
            header_search_key[0].name = header_search_key[0].label = NULL;
 
2954
        }
 
2955
        
 
2956
        flags = OE_APPEND_CURRENT | OE_KEEP_TRAILING_SPACE;
 
2957
        
 
2958
        rc = optionally_enter(new_string, command_line, 0, sizeof(new_string),
 
2959
                              prompt, header_search_key, help, &flags);
 
2960
 
 
2961
        if(rc == 3) {
 
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;
 
2965
            continue;
 
2966
        }
 
2967
        else if(rc == 10){
 
2968
            q_status_message(SM_ORDER, 0, 3, _("Searched to First Message."));
 
2969
            if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
 
2970
                do{
 
2971
                    selected = sorted_msg;
 
2972
                    mn_dec_cur(stream, msgmap, MH_NONE);
 
2973
                    sorted_msg = mn_get_cur(msgmap);
 
2974
                }
 
2975
                while(selected != sorted_msg);
 
2976
            }
 
2977
            else
 
2978
              sorted_msg = (mn_get_total(msgmap) > 0L) ? 1L : 0L;
 
2979
 
 
2980
            mn_set_cur(msgmap, sorted_msg);
 
2981
            return;
 
2982
        }
 
2983
        else if(rc == 11){
 
2984
            q_status_message(SM_ORDER, 0, 3, _("Searched to Last Message."));
 
2985
            if(any_lflagged(msgmap, MN_HIDE | MN_CHID)){
 
2986
                do{
 
2987
                    selected = sorted_msg;
 
2988
                    mn_inc_cur(stream, msgmap, MH_NONE);
 
2989
                    sorted_msg = mn_get_cur(msgmap);
 
2990
                }
 
2991
                while(selected != sorted_msg);
 
2992
            }
 
2993
            else
 
2994
              sorted_msg = mn_get_total(msgmap);
 
2995
 
 
2996
            mn_set_cur(msgmap, sorted_msg);
 
2997
            return;
 
2998
        }
 
2999
        else if(rc == 12){
 
3000
            select_all = 1;
 
3001
            break;
 
3002
        }
 
3003
 
 
3004
        if(rc != 4)                     /* redraw */
 
3005
          break; /* redraw */
 
3006
    }
 
3007
 
 
3008
    if(rc == 1 || (new_string[0] == '\0' && search_string[0] == '\0')) {
 
3009
        cmd_cancelled("Search");
 
3010
        return;
 
3011
    }
 
3012
 
 
3013
    if(new_string[0] == '\0'){
 
3014
        strncpy(new_string, search_string, sizeof(new_string));
 
3015
        new_string[sizeof(new_string)-1] = '\0';
 
3016
    }
 
3017
 
 
3018
    strncpy(search_string, new_string, sizeof(search_string));
 
3019
    search_string[sizeof(search_string)-1] = '\0';
 
3020
 
 
3021
#ifndef DOS
 
3022
    intr_handling_on();
 
3023
#endif
 
3024
 
 
3025
    for(i = sorted_msg + ((select_all)?0:1);
 
3026
        i <= mn_get_total(msgmap) && !ps_global->intr_pending;
 
3027
        i++){
 
3028
      if(msgline_hidden(stream, msgmap, i, 0))
 
3029
        continue;
 
3030
 
 
3031
      ic = build_header_line(state, stream, msgmap, i, NULL);
 
3032
 
 
3033
      ice = (ic && THRD_INDX() && ic->tice) ? ic->tice : ic;
 
3034
 
 
3035
      if(srchstr(simple_index_line(buf, sizeof(buf), ps_global->ttyo->screen_cols, ice, i),
 
3036
                                   search_string)){
 
3037
        selected++;
 
3038
        if(select_all)
 
3039
          set_lflag(stream, msgmap, i, MN_SLCT, 1);
 
3040
        else
 
3041
          break;
 
3042
      }
 
3043
    }
 
3044
 
 
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))
 
3048
          continue;
 
3049
 
 
3050
        ic = build_header_line(state, stream, msgmap, i, NULL);
 
3051
 
 
3052
        ice = (ic && THRD_INDX() && ic->tice) ? ic->tice : ic;
 
3053
 
 
3054
        if(srchstr(simple_index_line(buf, sizeof(buf), ps_global->ttyo->screen_cols, ice, i),
 
3055
                                     search_string)){
 
3056
          selected++;
 
3057
          if(select_all)
 
3058
            set_lflag(stream, msgmap, i, MN_SLCT, 1);
 
3059
          else
 
3060
            break;
 
3061
        }
 
3062
      }
 
3063
    }
 
3064
 
 
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.":"");
 
3068
    }
 
3069
    else if(select_all){
 
3070
        if(selected
 
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);
 
3075
            
 
3076
        q_status_message1(SM_ORDER, 0, 3, _("%s messages found matching word"),
 
3077
                          long2string(selected));
 
3078
    }
 
3079
    else if(selected){
 
3080
        q_status_message1(SM_ORDER, 0, 3, "Word found%s",
 
3081
                          (i <= sorted_msg)
 
3082
                            ? ". Search wrapped to beginning" : "");
 
3083
        mn_set_cur(msgmap, i);
 
3084
    }
 
3085
    else
 
3086
      q_status_message(SM_ORDER, 0, 3, _("Word not found"));
 
3087
 
 
3088
#ifndef DOS
 
3089
    intr_handling_off();
 
3090
#endif
 
3091
}
 
3092
 
 
3093
 
 
3094
/*
 
3095
 * Original idea from Stephen Casner <casner@acm.org>.
 
3096
 *
 
3097
 * Apply the appropriate reverse color transformation to the given
 
3098
 * color pair and return a new color pair. The caller should free the
 
3099
 * color pair.
 
3100
 *
 
3101
 */
 
3102
COLOR_PAIR *
 
3103
apply_rev_color(COLOR_PAIR *cp, int style)
 
3104
{
 
3105
    COLOR_PAIR *rc = pico_get_rev_color();
 
3106
 
 
3107
    if(rc){
 
3108
        if(style == IND_COL_REV){
 
3109
            /* just use Reverse color regardless */
 
3110
            return(new_color_pair(rc->fg, rc->bg));
 
3111
        }
 
3112
        else if(style == IND_COL_FG){
 
3113
            /*
 
3114
             * If changing to Rev fg is readable and different
 
3115
             * from what it already is, do it.
 
3116
             */
 
3117
            if(strcmp(rc->fg, cp->bg) && strcmp(rc->fg, cp->fg))
 
3118
              return(new_color_pair(rc->fg, cp->bg));
 
3119
        }
 
3120
        else if(style == IND_COL_BG){
 
3121
            /*
 
3122
             * If changing to Rev bg is readable and different
 
3123
             * from what it already is, do it.
 
3124
             */
 
3125
            if(strcmp(rc->bg, cp->fg) && strcmp(rc->bg, cp->bg))
 
3126
              return(new_color_pair(cp->fg, rc->bg));
 
3127
        }
 
3128
        else if(style == IND_COL_FG_NOAMBIG){
 
3129
            /*
 
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.
 
3133
             */
 
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));
 
3137
        }
 
3138
        else if(style == IND_COL_BG_NOAMBIG){
 
3139
            /*
 
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.
 
3143
             */
 
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));
 
3147
        }
 
3148
    }
 
3149
 
 
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 */
 
3152
}
 
3153
 
 
3154
 
 
3155
 
 
3156
#ifdef _WINDOWS
 
3157
 
 
3158
/*----------------------------------------------------------------------
 
3159
  Callback to get the text of the current message.  Used to display
 
3160
  a message in an alternate window.       
 
3161
 
 
3162
  Args: cmd - what type of scroll operation.
 
3163
        text - filled with pointer to text.
 
3164
        l - length of text.
 
3165
        style - Returns style of text.  Can be:
 
3166
                GETTEXT_TEXT - Is a pointer to text with CRLF deliminated
 
3167
                                lines
 
3168
                GETTEXT_LINES - Is a pointer to NULL terminated array of
 
3169
                                char *.  Each entry points to a line of
 
3170
                                text.
 
3171
                                        
 
3172
                this implementation always returns GETTEXT_TEXT.
 
3173
 
 
3174
  Returns: TRUE - did the scroll operation.
 
3175
           FALSE - was not able to do the scroll operation.
 
3176
 ----*/
 
3177
int
 
3178
index_scroll_callback (cmd, scroll_pos)
 
3179
int     cmd;
 
3180
long    scroll_pos;
 
3181
{
 
3182
    int paint = TRUE;
 
3183
 
 
3184
    switch (cmd) {
 
3185
      case MSWIN_KEY_SCROLLUPLINE:
 
3186
        paint = index_scroll_up (scroll_pos);
 
3187
        break;
 
3188
 
 
3189
      case MSWIN_KEY_SCROLLDOWNLINE:
 
3190
        paint = index_scroll_down (scroll_pos);
 
3191
        break;
 
3192
 
 
3193
      case MSWIN_KEY_SCROLLUPPAGE:
 
3194
        paint = index_scroll_up (current_index_state->lines_per_page);
 
3195
        break;
 
3196
 
 
3197
      case MSWIN_KEY_SCROLLDOWNPAGE:
 
3198
        paint = index_scroll_down (current_index_state->lines_per_page);
 
3199
        break;
 
3200
 
 
3201
      case MSWIN_KEY_SCROLLTO:
 
3202
        /* Normalize msgno in zoomed case */
 
3203
        if(any_lflagged(ps_global->msgmap, MN_HIDE | MN_CHID)){
 
3204
            long n, x;
 
3205
 
 
3206
            for(n = 1L, x = 0;
 
3207
                x < scroll_pos && n < mn_get_total(ps_global->msgmap);
 
3208
                n++)
 
3209
              if(!msgline_hidden(ps_global->mail_stream, ps_global->msgmap,
 
3210
                                 n, 0))
 
3211
                x++;
 
3212
 
 
3213
            scroll_pos = n - 1; /* list-position --> message number  */
 
3214
        }
 
3215
 
 
3216
        paint = index_scroll_to_pos (scroll_pos + 1);
 
3217
        break;
 
3218
    }
 
3219
 
 
3220
    if(paint){
 
3221
        mswin_beginupdate();
 
3222
        update_titlebar_message();
 
3223
        update_titlebar_status();
 
3224
        redraw_index_body();
 
3225
        mswin_endupdate();
 
3226
    }
 
3227
 
 
3228
    return(paint);
 
3229
}
 
3230
 
 
3231
 
 
3232
/*----------------------------------------------------------------------
 
3233
     MSWin scroll callback to get the text of the current message
 
3234
 
 
3235
  Args: title - title for new window
 
3236
        text - 
 
3237
        l - 
 
3238
        style - 
 
3239
 
 
3240
  Returns: TRUE - got the requested text
 
3241
           FALSE - was not able to get the requested text
 
3242
 ----*/
 
3243
int
 
3244
index_gettext_callback(title, titlelen, text, l, style)
 
3245
    char  *title;
 
3246
    size_t titlelen;
 
3247
    void **text;
 
3248
    long  *l;
 
3249
    int   *style;
 
3250
{
 
3251
    int       rv = 0;
 
3252
    ENVELOPE *env;
 
3253
    BODY     *body;
 
3254
    STORE_S  *so;
 
3255
    gf_io_t   pc;
 
3256
 
 
3257
    if(mn_get_total(ps_global->msgmap) > 0L
 
3258
       && (so = so_get(CharStar, NULL, WRITE_ACCESS))){
 
3259
        gf_set_so_writec(&pc, so);
 
3260
 
 
3261
        if((env = pine_mail_fetchstructure(ps_global->mail_stream,
 
3262
                                           mn_m2raw(ps_global->msgmap,
 
3263
                                               mn_get_cur(ps_global->msgmap)),
 
3264
                                           &body))
 
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;
 
3276
 
 
3277
            /* free alloc'd so, but preserve the text passed back to caller */
 
3278
            so->txt = (void *) NULL;
 
3279
            rv = 1;
 
3280
        }
 
3281
 
 
3282
        gf_clear_so_writec(so);
 
3283
        so_give(&so);
 
3284
    }
 
3285
 
 
3286
    return(rv);
 
3287
}
 
3288
 
 
3289
 
 
3290
/*
 
3291
 *
 
3292
 */
 
3293
int
 
3294
index_sort_callback(set, order)
 
3295
    int  set;
 
3296
    long order;
 
3297
{
 
3298
    int i = 0;
 
3299
 
 
3300
    if(set){
 
3301
        sort_folder(ps_global->mail_stream, ps_global->msgmap,
 
3302
                    order & 0x000000ff,
 
3303
                    (order & 0x00000100) != 0, SRT_VRB);
 
3304
        mswin_beginupdate();
 
3305
        update_titlebar_message();
 
3306
        update_titlebar_status();
 
3307
        redraw_index_body();
 
3308
        mswin_endupdate();
 
3309
        flush_status_messages(1);
 
3310
    }
 
3311
    else{
 
3312
        i = (int) mn_get_sort(ps_global->msgmap);
 
3313
        if(mn_get_revsort(ps_global->msgmap))
 
3314
          i |= 0x0100;
 
3315
    }
 
3316
 
 
3317
    return(i);
 
3318
}
 
3319
 
 
3320
 
 
3321
/*
 
3322
 *
 
3323
 */
 
3324
void
 
3325
index_popup(stream,  msgmap, full)
 
3326
    MAILSTREAM *stream;
 
3327
    MSGNO_S    *msgmap;
 
3328
    int         full;
 
3329
{
 
3330
    int           n;
 
3331
    long          rawno;
 
3332
    MESSAGECACHE *mc;
 
3333
    MPopup        view_index_popup[32];
 
3334
 
 
3335
    if(full){
 
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';
 
3340
 
 
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";
 
3344
 
 
3345
        view_index_popup[2].type = tSeparator;
 
3346
 
 
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';
 
3356
        }
 
3357
        else{
 
3358
            view_index_popup[3].label.string = "&Delete";
 
3359
            view_index_popup[3].data.val     = 'D';
 
3360
        }
 
3361
 
 
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);
 
3366
            n = 5;
 
3367
        }
 
3368
        else
 
3369
          n = 4;
 
3370
 
 
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';
 
3375
 
 
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   = '%';
 
3380
 
 
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';
 
3385
 
 
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';
 
3390
 
 
3391
        view_index_popup[n++].type = tSeparator;
 
3392
    }
 
3393
    else
 
3394
      n = 0;
 
3395
 
 
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   = '<';
 
3400
 
 
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';
 
3405
 
 
3406
    view_index_popup[n].type = tTail;
 
3407
 
 
3408
    if((n = mswin_popup(view_index_popup)) == 1 && full){
 
3409
        char title[GETTEXT_TITLELEN+1];
 
3410
        void    *text;
 
3411
        long    len;
 
3412
        int     format;
 
3413
 
 
3414
        /* Launch text in alt window. */
 
3415
        if (index_gettext_callback (title, sizeof(title), &text,
 
3416
                                    &len, &format)) {
 
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);
 
3421
        }
 
3422
    }
 
3423
}
 
3424
 
 
3425
 
 
3426
char *
 
3427
pcpine_help_index(title)
 
3428
    char *title;
 
3429
{
 
3430
    /* 
 
3431
     * Title is size 256 in pico. Put in args.
 
3432
     */
 
3433
    if(title)
 
3434
      strncpy(title, "Alpine MESSAGE INDEX Help", 256);
 
3435
 
 
3436
    return(pcpine_help(h_mail_index));
 
3437
}
 
3438
 
 
3439
char *
 
3440
pcpine_help_index_simple(title)
 
3441
    char *title;
 
3442
{
 
3443
    /* 
 
3444
     * Title is size 256 in pico. Put in args.
 
3445
     */
 
3446
    if(title)
 
3447
      strncpy(title, "Alpine SELECT MESSAGE Help", 256);
 
3448
 
 
3449
    return(pcpine_help(h_simple_index));
 
3450
}
 
3451
 
 
3452
 
 
3453
int
 
3454
pcpine_resize_index()
 
3455
{
 
3456
    int orig_col = ps_global->ttyo->screen_cols;
 
3457
 
 
3458
    reset_index_border();
 
3459
    (void) get_windsize (ps_global->ttyo);
 
3460
 
 
3461
    if(orig_col != ps_global->ttyo->screen_cols)
 
3462
      clear_index_cache(ps_global->mail_stream, 0);
 
3463
 
 
3464
    mswin_beginupdate();
 
3465
    update_titlebar_message();
 
3466
    update_titlebar_status();
 
3467
    redraw_index_body();
 
3468
    mswin_endupdate();
 
3469
    return(0);
 
3470
}
 
3471
 
 
3472
#endif  /* _WINDOWS */